Initial commit
This commit is contained in:
commit
c3d80f0c61
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
36
Dockerfile
Normal file
36
Dockerfile
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# Use a base image with node and build essentials
|
||||||
|
FROM node:20-buster
|
||||||
|
|
||||||
|
# Install dependencies and Bun
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl git unzip && \
|
||||||
|
curl -fsSL https://bun.sh/install | bash
|
||||||
|
|
||||||
|
# Add Bun to PATH
|
||||||
|
ENV PATH="/root/.bun/bin:${PATH}"
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files first
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies using bun
|
||||||
|
RUN bun install
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Create logs directory
|
||||||
|
RUN mkdir -p /app/logs && chmod 777 /app/logs
|
||||||
|
|
||||||
|
# Expose port 5002 explicitly
|
||||||
|
EXPOSE 5002
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV LOG_PATH=/app/logs
|
||||||
|
|
||||||
|
# Use npm/bun scripts to run the server
|
||||||
|
CMD ["bun", "run", "dev-server-bun"]
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Node/Bun server example
|
||||||
|
|
||||||
|
This is a simple example of how to integrate tldraw's sync engine with a Node server or a Bun server.
|
||||||
|
|
||||||
|
Run `yarn dev-node` or `yarn dev-bun` in this folder to start the server + client.
|
||||||
0
bunfig.toml
Normal file
0
bunfig.toml
Normal file
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"dev-server-bun": "bun --watch ./src/server/server.bun.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dagrejs/dagre": "^1.1.4",
|
||||||
|
"@fastify/cors": "^9.0.1",
|
||||||
|
"@fastify/websocket": "^10.0.1",
|
||||||
|
"@tldraw/sync": "3.6.1",
|
||||||
|
"@tldraw/sync-core": "3.6.1",
|
||||||
|
"@tldraw/tlschema": "3.6.1",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"cheerio": "^1.0.0-rc.12",
|
||||||
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"fastify": "^4.28.1",
|
||||||
|
"itty-router": "^5.0.17",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.24.1",
|
||||||
|
"socket.io-client": "^4.8.0",
|
||||||
|
"unfurl.js": "^6.4.0",
|
||||||
|
"vite": "^5.3.3",
|
||||||
|
"ws": "^8.16.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.1.6",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/node": "^20.11.0",
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"concurrently": "^8.2.2",
|
||||||
|
"lazyrepo": "0.0.0-alpha.27",
|
||||||
|
"@types/react": "^18.2.0",
|
||||||
|
"@types/react-dom": "^18.2.0",
|
||||||
|
"@babel/core": "^7.23.3",
|
||||||
|
"@babel/preset-react": "^7.23.3",
|
||||||
|
"typescript": "^5.3.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
2
src/axiosConfig.ts
Normal file
2
src/axiosConfig.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
export default axios;
|
||||||
46
src/logger.ts
Normal file
46
src/logger.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { existsSync, mkdirSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const LOG_DIR = process.env.LOG_PATH || './logs';
|
||||||
|
const LOG_FILE = join(LOG_DIR, 'server.log');
|
||||||
|
|
||||||
|
// Ensure log directory exists
|
||||||
|
if (!existsSync(LOG_DIR)) {
|
||||||
|
mkdirSync(LOG_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogLevel = 'INFO' | 'ERROR' | 'DEBUG' | 'WARN';
|
||||||
|
|
||||||
|
function formatLog(level: LogLevel, message: string, data?: any): string {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const dataStr = data ? `\n${JSON.stringify(data, null, 2)}` : '';
|
||||||
|
return `[${timestamp}] [${level}] ${message}${dataStr}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logger = {
|
||||||
|
info: (message: string, data?: any) => {
|
||||||
|
const log = formatLog('INFO', message, data);
|
||||||
|
console.log(log);
|
||||||
|
Bun.write(LOG_FILE, log, { append: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
error: (message: string, data?: any) => {
|
||||||
|
const log = formatLog('ERROR', message, data);
|
||||||
|
console.error(log);
|
||||||
|
Bun.write(LOG_FILE, log, { append: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
debug: (message: string, data?: any) => {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
const log = formatLog('DEBUG', message, data);
|
||||||
|
console.debug(log);
|
||||||
|
Bun.write(LOG_FILE, log, { append: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
warn: (message: string, data?: any) => {
|
||||||
|
const log = formatLog('WARN', message, data);
|
||||||
|
console.warn(log);
|
||||||
|
Bun.write(LOG_FILE, log, { append: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
53
src/server/assets.ts
Normal file
53
src/server/assets.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { mkdir, readFile, writeFile } from 'fs/promises'
|
||||||
|
import { join, resolve } from 'path'
|
||||||
|
import { Readable } from 'stream'
|
||||||
|
import crypto from 'crypto'
|
||||||
|
|
||||||
|
// We are just using the filesystem to store assets
|
||||||
|
const DIR = resolve('./.assets')
|
||||||
|
|
||||||
|
function hashFileName(fileName: string): string {
|
||||||
|
return crypto.createHash('md5').update(fileName).digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function storeAsset(id: string, stream: Readable) {
|
||||||
|
console.log(`Storing asset with ID: ${id}`)
|
||||||
|
console.log(`Asset directory: ${DIR}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mkdir(DIR, { recursive: true })
|
||||||
|
console.log(`Directory created or already exists: ${DIR}`)
|
||||||
|
|
||||||
|
const hashedFileName = hashFileName(id)
|
||||||
|
const filePath = join(DIR, hashedFileName)
|
||||||
|
console.log(`Writing file to path: ${filePath}`)
|
||||||
|
|
||||||
|
const chunks = []
|
||||||
|
for await (const chunk of stream) {
|
||||||
|
chunks.push(chunk)
|
||||||
|
}
|
||||||
|
const buffer = Buffer.concat(chunks)
|
||||||
|
|
||||||
|
await writeFile(filePath, buffer)
|
||||||
|
console.log(`Asset stored successfully with ID: ${id}`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error storing asset with ID: ${id}`, error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadAsset(id: string) {
|
||||||
|
console.log(`Loading asset with ID: ${id}`)
|
||||||
|
const hashedFileName = hashFileName(id)
|
||||||
|
const filePath = join(DIR, hashedFileName)
|
||||||
|
console.log(`Reading file from path: ${filePath}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await readFile(filePath)
|
||||||
|
console.log(`Asset loaded successfully with ID: ${id}`)
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error loading asset with ID: ${id}`, error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/server/rooms.ts
Normal file
121
src/server/rooms.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { RoomSnapshot, TLSocketRoom } from '@tldraw/sync-core'
|
||||||
|
import { TLStoreSchema } from '@tldraw/tlschema'
|
||||||
|
import { mkdir, readFile, writeFile } from 'fs/promises'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { TLSchema, TLStore, TLStoreOptions } from 'tldraw'
|
||||||
|
import { logger } from './../logger'
|
||||||
|
|
||||||
|
// For this example we're just saving data to the local filesystem
|
||||||
|
const DIR = './.rooms'
|
||||||
|
async function readSnapshotIfExists(roomId: string) {
|
||||||
|
try {
|
||||||
|
const data = await readFile(join(DIR, roomId))
|
||||||
|
const snapshot = JSON.parse(data.toString()) ?? undefined;
|
||||||
|
logger.info(`📥 Loaded snapshot for room: ${roomId}`);
|
||||||
|
return snapshot;
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(`⚠️ No existing snapshot found for room: ${roomId}`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveSnapshot(roomId: string, snapshot: RoomSnapshot) {
|
||||||
|
try {
|
||||||
|
await mkdir(DIR, { recursive: true });
|
||||||
|
await writeFile(join(DIR, roomId), JSON.stringify(snapshot));
|
||||||
|
logger.info(`💾 Saved snapshot for room: ${roomId}`);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`❌ Failed to save snapshot for room: ${roomId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll keep an in-memory map of rooms and their data
|
||||||
|
interface RoomState {
|
||||||
|
room: TLSocketRoom<any, void>
|
||||||
|
id: string
|
||||||
|
needsPersist: boolean
|
||||||
|
lastActivity: number
|
||||||
|
connectedSessions: Set<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
const rooms = new Map<string, RoomState>()
|
||||||
|
|
||||||
|
// Very simple mutex using promise chaining, to avoid race conditions
|
||||||
|
// when loading rooms. In production you probably want one mutex per room
|
||||||
|
// to avoid unnecessary blocking!
|
||||||
|
let mutex = Promise.resolve<null | Error>(null)
|
||||||
|
|
||||||
|
export async function makeOrLoadRoom(
|
||||||
|
roomId: string,
|
||||||
|
schema: TLSchema,
|
||||||
|
options?: Partial<TLStoreOptions>
|
||||||
|
): Promise<TLSocketRoom<any, void>> {
|
||||||
|
mutex = mutex
|
||||||
|
.then(async () => {
|
||||||
|
if (rooms.has(roomId)) {
|
||||||
|
const roomState = await rooms.get(roomId)!
|
||||||
|
if (!roomState.room.isClosed()) {
|
||||||
|
logger.info(`🔄 Using existing room: ${roomId}`);
|
||||||
|
return null // all good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info(`🔄 Loading room: ${roomId}`);
|
||||||
|
const initialSnapshot = await readSnapshotIfExists(roomId)
|
||||||
|
|
||||||
|
const roomState: RoomState = {
|
||||||
|
needsPersist: false,
|
||||||
|
id: roomId,
|
||||||
|
lastActivity: Date.now(),
|
||||||
|
connectedSessions: new Set(),
|
||||||
|
room: new TLSocketRoom({
|
||||||
|
initialSnapshot,
|
||||||
|
schema: schema,
|
||||||
|
onSessionRemoved(room, args) {
|
||||||
|
logger.info(`👋 Client disconnected from room: ${roomId}`);
|
||||||
|
roomState.connectedSessions.delete(args.sessionId);
|
||||||
|
roomState.lastActivity = Date.now();
|
||||||
|
if (args.numSessionsRemaining === 0) {
|
||||||
|
logger.info(`🔒 Closing empty room: ${roomId}`);
|
||||||
|
room.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDataChange() {
|
||||||
|
roomState.needsPersist = true;
|
||||||
|
roomState.lastActivity = Date.now();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
rooms.set(roomId, roomState)
|
||||||
|
return null // all good
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.error(`❌ Error making/loading room: ${roomId}`);
|
||||||
|
// return errors as normal values to avoid stopping the mutex chain
|
||||||
|
return error
|
||||||
|
})
|
||||||
|
|
||||||
|
const err = await mutex
|
||||||
|
if (err) throw err
|
||||||
|
return rooms.get(roomId)!.room
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do persistence on a regular interval.
|
||||||
|
// In production you probably want a smarter system with throttling.
|
||||||
|
setInterval(() => {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const roomState of rooms.values()) {
|
||||||
|
if (roomState.needsPersist) {
|
||||||
|
// persist room
|
||||||
|
roomState.needsPersist = false;
|
||||||
|
logger.info(`💾 Saving snapshot for room: ${roomState.id}`);
|
||||||
|
saveSnapshot(roomState.id, roomState.room.getCurrentSnapshot());
|
||||||
|
}
|
||||||
|
if (roomState.room.isClosed()) {
|
||||||
|
logger.info(`🗑️ Deleting closed room: ${roomState.id}`);
|
||||||
|
rooms.delete(roomState.id);
|
||||||
|
} else if (now - roomState.lastActivity > 30 * 60 * 1000) { // 30 minutes inactivity
|
||||||
|
logger.info(`⏰ Closing inactive room: ${roomState.id}`);
|
||||||
|
roomState.room.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
199
src/server/schema.ts
Normal file
199
src/server/schema.ts
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import { createTLSchema, defaultShapeSchemas, defaultBindingSchemas } from '@tldraw/tlschema'
|
||||||
|
import { ccBindingProps, ccShapeProps } from '../utils/tldraw/cc-base/cc-props'
|
||||||
|
import { ccBindingMigrations, ccShapeMigrations } from '../utils/tldraw/cc-base/cc-migrations'
|
||||||
|
import { ccGraphShapeProps } from '../utils/tldraw/cc-base/cc-graph-props'
|
||||||
|
import { ccGraphMigrations } from '../utils/tldraw/cc-base/cc-graph-migrations'
|
||||||
|
|
||||||
|
export const server_schema_default = createTLSchema({
|
||||||
|
shapes: {
|
||||||
|
...defaultShapeSchemas,
|
||||||
|
'cc-base': {
|
||||||
|
props: ccShapeProps.base,
|
||||||
|
migrations: ccShapeMigrations.base,
|
||||||
|
},
|
||||||
|
'cc-live-transcription': {
|
||||||
|
props: ccShapeProps.liveTranscription,
|
||||||
|
migrations: ccShapeMigrations.liveTranscription,
|
||||||
|
},
|
||||||
|
'cc-calendar': {
|
||||||
|
props: ccShapeProps.calendar,
|
||||||
|
migrations: ccShapeMigrations.calendar,
|
||||||
|
},
|
||||||
|
'cc-settings': {
|
||||||
|
props: ccShapeProps.settings,
|
||||||
|
migrations: ccShapeMigrations.settings,
|
||||||
|
},
|
||||||
|
'cc-slideshow': {
|
||||||
|
props: ccShapeProps.slideshow,
|
||||||
|
migrations: ccShapeMigrations.slideshow,
|
||||||
|
},
|
||||||
|
'cc-slide': {
|
||||||
|
props: ccShapeProps.slide,
|
||||||
|
migrations: ccShapeMigrations.slide,
|
||||||
|
},
|
||||||
|
'cc-web-browser': {
|
||||||
|
props: ccShapeProps.webBrowser,
|
||||||
|
migrations: ccShapeMigrations.webBrowser,
|
||||||
|
},
|
||||||
|
'cc-search': {
|
||||||
|
props: ccShapeProps.search,
|
||||||
|
migrations: ccShapeMigrations.search,
|
||||||
|
},
|
||||||
|
'cc-youtube-embed': {
|
||||||
|
props: ccShapeProps['cc-youtube-embed'],
|
||||||
|
migrations: ccShapeMigrations['cc-youtube-embed'],
|
||||||
|
},
|
||||||
|
// Graph shapes
|
||||||
|
'cc-user-node': {
|
||||||
|
props: ccGraphShapeProps['cc-user-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-user-node'],
|
||||||
|
},
|
||||||
|
'cc-teacher-node': {
|
||||||
|
props: ccGraphShapeProps['cc-teacher-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-teacher-node'],
|
||||||
|
},
|
||||||
|
'cc-student-node': {
|
||||||
|
props: ccGraphShapeProps['cc-student-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-student-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-year-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-year-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-year-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-month-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-month-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-month-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-week-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-week-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-week-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-day-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-day-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-day-node'],
|
||||||
|
},
|
||||||
|
'cc-calendar-time-chunk-node': {
|
||||||
|
props: ccGraphShapeProps['cc-calendar-time-chunk-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-calendar-time-chunk-node'],
|
||||||
|
},
|
||||||
|
'cc-school-node': {
|
||||||
|
props: ccGraphShapeProps['cc-school-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-school-node'],
|
||||||
|
},
|
||||||
|
'cc-department-node': {
|
||||||
|
props: ccGraphShapeProps['cc-department-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-department-node'],
|
||||||
|
},
|
||||||
|
'cc-room-node': {
|
||||||
|
props: ccGraphShapeProps['cc-room-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-room-node'],
|
||||||
|
},
|
||||||
|
'cc-subject-class-node': {
|
||||||
|
props: ccGraphShapeProps['cc-subject-class-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-subject-class-node'],
|
||||||
|
},
|
||||||
|
'cc-pastoral-structure-node': {
|
||||||
|
props: ccGraphShapeProps['cc-pastoral-structure-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-pastoral-structure-node'],
|
||||||
|
},
|
||||||
|
'cc-year-group-node': {
|
||||||
|
props: ccGraphShapeProps['cc-year-group-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-year-group-node'],
|
||||||
|
},
|
||||||
|
'cc-curriculum-structure-node': {
|
||||||
|
props: ccGraphShapeProps['cc-curriculum-structure-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-curriculum-structure-node'],
|
||||||
|
},
|
||||||
|
'cc-key-stage-node': {
|
||||||
|
props: ccGraphShapeProps['cc-key-stage-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-key-stage-node'],
|
||||||
|
},
|
||||||
|
'cc-key-stage-syllabus-node': {
|
||||||
|
props: ccGraphShapeProps['cc-key-stage-syllabus-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-key-stage-syllabus-node'],
|
||||||
|
},
|
||||||
|
'cc-year-group-syllabus-node': {
|
||||||
|
props: ccGraphShapeProps['cc-year-group-syllabus-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-year-group-syllabus-node'],
|
||||||
|
},
|
||||||
|
'cc-subject-node': {
|
||||||
|
props: ccGraphShapeProps['cc-subject-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-subject-node'],
|
||||||
|
},
|
||||||
|
'cc-topic-node': {
|
||||||
|
props: ccGraphShapeProps['cc-topic-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-topic-node'],
|
||||||
|
},
|
||||||
|
'cc-topic-lesson-node': {
|
||||||
|
props: ccGraphShapeProps['cc-topic-lesson-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-topic-lesson-node'],
|
||||||
|
},
|
||||||
|
'cc-learning-statement-node': {
|
||||||
|
props: ccGraphShapeProps['cc-learning-statement-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-learning-statement-node'],
|
||||||
|
},
|
||||||
|
'cc-science-lab-node': {
|
||||||
|
props: ccGraphShapeProps['cc-science-lab-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-science-lab-node'],
|
||||||
|
},
|
||||||
|
'cc-teacher-timetable-node': {
|
||||||
|
props: ccGraphShapeProps['cc-teacher-timetable-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-teacher-timetable-node'],
|
||||||
|
},
|
||||||
|
'cc-timetable-lesson-node': {
|
||||||
|
props: ccGraphShapeProps['cc-timetable-lesson-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-timetable-lesson-node'],
|
||||||
|
},
|
||||||
|
'cc-planned-lesson-node': {
|
||||||
|
props: ccGraphShapeProps['cc-planned-lesson-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-planned-lesson-node'],
|
||||||
|
},
|
||||||
|
'cc-school-timetable-node': {
|
||||||
|
props: ccGraphShapeProps['cc-school-timetable-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-school-timetable-node'],
|
||||||
|
},
|
||||||
|
'cc-academic-year-node': {
|
||||||
|
props: ccGraphShapeProps['cc-academic-year-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-academic-year-node'],
|
||||||
|
},
|
||||||
|
'cc-academic-term-node': {
|
||||||
|
props: ccGraphShapeProps['cc-academic-term-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-academic-term-node'],
|
||||||
|
},
|
||||||
|
'cc-academic-week-node': {
|
||||||
|
props: ccGraphShapeProps['cc-academic-week-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-academic-week-node'],
|
||||||
|
},
|
||||||
|
'cc-academic-day-node': {
|
||||||
|
props: ccGraphShapeProps['cc-academic-day-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-academic-day-node'],
|
||||||
|
},
|
||||||
|
'cc-academic-period-node': {
|
||||||
|
props: ccGraphShapeProps['cc-academic-period-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-academic-period-node'],
|
||||||
|
},
|
||||||
|
'cc-registration-period-node': {
|
||||||
|
props: ccGraphShapeProps['cc-registration-period-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-registration-period-node'],
|
||||||
|
},
|
||||||
|
'cc-user-teacher-timetable-node': {
|
||||||
|
props: ccGraphShapeProps['cc-user-teacher-timetable-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-user-teacher-timetable-node'],
|
||||||
|
},
|
||||||
|
'cc-user-timetable-lesson-node': {
|
||||||
|
props: ccGraphShapeProps['cc-user-timetable-lesson-node'],
|
||||||
|
migrations: ccGraphMigrations['cc-user-timetable-lesson-node'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bindings: {
|
||||||
|
...defaultBindingSchemas,
|
||||||
|
'cc-slide-layout': {
|
||||||
|
props: ccBindingProps['cc-slide-layout'],
|
||||||
|
migrations: ccBindingMigrations['cc-slide-layout'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
199
src/server/server.bun.ts
Normal file
199
src/server/server.bun.ts
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// External imports
|
||||||
|
import { TLSocketRoom } from '@tldraw/sync-core'
|
||||||
|
import { IRequest, Router, RouterType, cors, json } from 'itty-router'
|
||||||
|
import { Readable } from 'stream'
|
||||||
|
import {
|
||||||
|
createTLStore,
|
||||||
|
} from 'tldraw'
|
||||||
|
// Internal imports
|
||||||
|
import { loadAsset, storeAsset } from './assets'
|
||||||
|
import { makeOrLoadRoom } from './rooms'
|
||||||
|
import { unfurl } from './unfurl'
|
||||||
|
import { server_schema_default } from './schema'
|
||||||
|
import { logger } from './../logger'
|
||||||
|
|
||||||
|
// Add debug logging for environment variables
|
||||||
|
logger.info('Environment variables:', {
|
||||||
|
PORT: process.env.PORT,
|
||||||
|
PORT_TLDRAW_SYNC: process.env.PORT_TLDRAW_SYNC,
|
||||||
|
NODE_ENV: process.env.NODE_ENV
|
||||||
|
});
|
||||||
|
|
||||||
|
// Be explicit about port precedence
|
||||||
|
const PORT = process.env.PORT_TLDRAW_SYNC || 5002
|
||||||
|
|
||||||
|
// Log the port being used
|
||||||
|
logger.info(`Using port: ${PORT}`)
|
||||||
|
|
||||||
|
const { corsify, preflight } = cors({ origin: '*' })
|
||||||
|
|
||||||
|
const router: RouterType<IRequest, any, any> = Router()
|
||||||
|
.all('*', preflight)
|
||||||
|
|
||||||
|
.get(`/connect/:roomId`, async (req) => {
|
||||||
|
const {roomId} = req.params
|
||||||
|
const {sessionId} = req.query
|
||||||
|
logger.info(`Connecting to room: ${roomId}, session: ${sessionId}`)
|
||||||
|
server.upgrade(req, { data: { roomId, sessionId } })
|
||||||
|
return new Response(null, { status: 101 })
|
||||||
|
})
|
||||||
|
|
||||||
|
.put(`/uploads/:id`, async (req) => {
|
||||||
|
const {id} = req.params;
|
||||||
|
logger.info(`Received upload request for ID: ${id}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buffer = await req.arrayBuffer(); // Directly convert the incoming request body to an ArrayBuffer
|
||||||
|
const stream = Readable.from(Buffer.from(buffer)); // Convert ArrayBuffer to Node.js Readable Stream
|
||||||
|
|
||||||
|
await storeAsset(id, stream);
|
||||||
|
const response = new Response(JSON.stringify({ ok: true }), {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
},
|
||||||
|
status: 200
|
||||||
|
}); // TODO: Unsafe, change
|
||||||
|
logger.info(`Upload successful for ID: ${id}`);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Error storing asset with ID: ${id}`, error);
|
||||||
|
return new Response('Internal Server Error', { status: 500 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.get(`/uploads/:id`, async (req) => {
|
||||||
|
const id = (req.params as any).id as string
|
||||||
|
logger.info(`Received request to load asset with ID: ${id}`)
|
||||||
|
try {
|
||||||
|
const asset = await loadAsset(id)
|
||||||
|
const response = new Response(asset)
|
||||||
|
response.headers.set('Access-Control-Allow-Origin', '*') // TODO: Unsafe, change
|
||||||
|
logger.info(`Asset loaded successfully for ID: ${id}`)
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Error loading asset with ID: ${id}`, error)
|
||||||
|
return new Response('Internal Server Error', { status: 500 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.get(`/unfurl`, async (req) => {
|
||||||
|
const url = (req.query as any).url as string
|
||||||
|
logger.info(`Received unfurl request for URL: ${url}`)
|
||||||
|
try {
|
||||||
|
const data = await unfurl(url)
|
||||||
|
const response = json(data)
|
||||||
|
response.headers.set('Access-Control-Allow-Origin', '*') // TODO: Unsafe, change
|
||||||
|
logger.info(`Unfurling successful for URL: ${url}`)
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Error unfurling URL: ${url}`, error)
|
||||||
|
return new Response('Internal Server Error', { status: 500 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.all('*', (req) => {
|
||||||
|
logger.info(`Received request for unknown route: ${req.url}`);
|
||||||
|
const response = new Response('Not found', { status: 404 });
|
||||||
|
response.headers.set('Access-Control-Allow-Origin', '*'); // TODO: Unsafe, change
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
|
||||||
|
const server = Bun.serve<{ room?: TLSocketRoom<any, void>; sessionId: string; roomId: string }>({
|
||||||
|
port: parseInt(PORT as string), // Ensure it's parsed as a number
|
||||||
|
fetch(req) {
|
||||||
|
try {
|
||||||
|
logger.info(`Server started on port: ${PORT}`) // Add explicit port logging
|
||||||
|
logger.info('Received request: ', req.url)
|
||||||
|
return router.fetch(req).then(corsify)
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Error handling request: ', e)
|
||||||
|
return new Response('Something went wrong', {
|
||||||
|
status: 500,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
websocket: {
|
||||||
|
async open(socket) {
|
||||||
|
logger.debug(`WebSocket connection attempt for room: ${socket.data.roomId}`, {
|
||||||
|
sessionId: socket.data.sessionId
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const { sessionId, roomId } = socket.data;
|
||||||
|
if (!sessionId || !roomId) {
|
||||||
|
logger.error('Missing sessionId or roomId in WebSocket connection data', {
|
||||||
|
sessionId,
|
||||||
|
roomId
|
||||||
|
});
|
||||||
|
socket.close(4000, 'Missing data');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info(`WebSocket opened for room: ${roomId}, session: ${sessionId}`);
|
||||||
|
const room = await makeOrLoadRoom(roomId, server_schema_default);
|
||||||
|
if (!room) {
|
||||||
|
logger.error('Failed to create or load room', {
|
||||||
|
roomId,
|
||||||
|
sessionId
|
||||||
|
});
|
||||||
|
socket.close(4001, 'Failed to load room');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
room.handleSocketConnect({ sessionId, socket });
|
||||||
|
socket.data.room = room;
|
||||||
|
logger.info(`Successfully connected to room: ${roomId}`, {
|
||||||
|
sessionId,
|
||||||
|
roomId
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error during WebSocket open:', error);
|
||||||
|
socket.close(1011, 'Internal error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async message(ws, message) {
|
||||||
|
try {
|
||||||
|
logger.debug(`WebSocket message for session: ${ws.data.sessionId}`, {
|
||||||
|
message,
|
||||||
|
roomId: ws.data.roomId
|
||||||
|
});
|
||||||
|
if (!ws.data.room) {
|
||||||
|
logger.error('No room found for WebSocket message', {
|
||||||
|
sessionId: ws.data.sessionId,
|
||||||
|
roomId: ws.data.roomId
|
||||||
|
});
|
||||||
|
ws.close(4002, 'No room found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ws.data.room.handleSocketMessage(ws.data.sessionId, message);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error handling WebSocket message:', error);
|
||||||
|
ws.close(1011, 'Message handling error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
drain(ws) {
|
||||||
|
logger.info(`WebSocket drain for session: ${ws.data.sessionId}`, {
|
||||||
|
roomId: ws.data.roomId
|
||||||
|
});
|
||||||
|
ws.close();
|
||||||
|
},
|
||||||
|
close(ws) {
|
||||||
|
logger.info(`WebSocket closed for session: ${ws.data.sessionId}`, {
|
||||||
|
roomId: ws.data.roomId
|
||||||
|
});
|
||||||
|
if (ws.data.room) {
|
||||||
|
ws.data.room.handleSocketClose(ws.data.sessionId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add explicit logging of the server configuration
|
||||||
|
logger.info('Server configuration:', {
|
||||||
|
port: server.port,
|
||||||
|
hostname: server.hostname
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info(`Listening for connections on URL: ${server.url}`)
|
||||||
|
|
||||||
|
logger.info(`Listening on localhost:${PORT}`)
|
||||||
|
|
||||||
|
logger.info(`Server: ${server}`)
|
||||||
14
src/server/unfurl.ts
Normal file
14
src/server/unfurl.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import _unfurl from 'unfurl.js'
|
||||||
|
|
||||||
|
export async function unfurl(url: string) {
|
||||||
|
const { title, description, open_graph, twitter_card, favicon } = await _unfurl.unfurl(url)
|
||||||
|
|
||||||
|
const image = open_graph?.images?.[0]?.url || twitter_card?.images?.[0]?.url
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
image,
|
||||||
|
favicon,
|
||||||
|
}
|
||||||
|
}
|
||||||
310
src/types/graph_node_types.ts
Normal file
310
src/types/graph_node_types.ts
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
export interface BaseNodeInterface {
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
color: string;
|
||||||
|
__primarylabel__: string;
|
||||||
|
unique_id: string;
|
||||||
|
path: string;
|
||||||
|
created: string;
|
||||||
|
merged: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Users
|
||||||
|
export interface UserNodeInterface extends BaseNodeInterface
|
||||||
|
{
|
||||||
|
user_id: string;
|
||||||
|
user_type: string;
|
||||||
|
user_name: string;
|
||||||
|
user_email: string;
|
||||||
|
worker_node_data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeveloperNodeInterface extends BaseNodeInterface{
|
||||||
|
user_id: string;
|
||||||
|
user_type: string;
|
||||||
|
user_name: string;
|
||||||
|
user_email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TeacherNodeInterface extends BaseNodeInterface{
|
||||||
|
teacher_code: string;
|
||||||
|
teacher_name_formal: string;
|
||||||
|
teacher_email: string;
|
||||||
|
worker_db_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StudentNodeInterface extends BaseNodeInterface{
|
||||||
|
student_code: string;
|
||||||
|
student_name_formal: string;
|
||||||
|
student_email: string;
|
||||||
|
worker_db_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StandardUserNodeInterface extends BaseNodeInterface{
|
||||||
|
user_id: string;
|
||||||
|
user_type: string;
|
||||||
|
user_name: string;
|
||||||
|
user_email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SchoolAdminNodeInterface extends BaseNodeInterface {
|
||||||
|
user_id: string;
|
||||||
|
user_type: string;
|
||||||
|
user_name: string;
|
||||||
|
user_email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
export interface CalendarNodeInterface extends BaseNodeInterface {
|
||||||
|
name: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalendarYearNodeInterface extends BaseNodeInterface {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalendarMonthNodeInterface extends BaseNodeInterface {
|
||||||
|
year: string;
|
||||||
|
month: string;
|
||||||
|
month_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalendarWeekNodeInterface extends BaseNodeInterface {
|
||||||
|
start_date: string;
|
||||||
|
week_number: string;
|
||||||
|
iso_week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalendarDayNodeInterface extends BaseNodeInterface {
|
||||||
|
date: string;
|
||||||
|
day_of_week: string;
|
||||||
|
iso_day: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalendarTimeChunkNodeInterface extends BaseNodeInterface {
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// School
|
||||||
|
export interface SchoolNodeInterface extends BaseNodeInterface
|
||||||
|
{
|
||||||
|
school_name: string;
|
||||||
|
school_website: string;
|
||||||
|
school_uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepartmentNodeInterface extends BaseNodeInterface
|
||||||
|
{
|
||||||
|
department_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoomNodeInterface extends BaseNodeInterface {
|
||||||
|
room_code: string;
|
||||||
|
room_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubjectClassNodeInterface extends BaseNodeInterface
|
||||||
|
{
|
||||||
|
subject_class_code: string;
|
||||||
|
year_group: string;
|
||||||
|
subject: string;
|
||||||
|
subject_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Curriculum
|
||||||
|
export interface PastoralStructureNodeInterface extends BaseNodeInterface {
|
||||||
|
// No additional properties
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface YearGroupNodeInterface extends BaseNodeInterface {
|
||||||
|
year_group: string;
|
||||||
|
year_group_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CurriculumStructureNodeInterface extends BaseNodeInterface {
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KeyStageNodeInterface extends BaseNodeInterface {
|
||||||
|
key_stage_name: string;
|
||||||
|
key_stage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KeyStageSyllabusNodeInterface extends BaseNodeInterface {
|
||||||
|
ks_syllabus_id: string;
|
||||||
|
ks_syllabus_name: string;
|
||||||
|
ks_syllabus_key_stage: string;
|
||||||
|
ks_syllabus_subject: string;
|
||||||
|
ks_syllabus_subject_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface YearGroupSyllabusNodeInterface extends BaseNodeInterface {
|
||||||
|
yr_syllabus_id: string;
|
||||||
|
yr_syllabus_name: string;
|
||||||
|
yr_syllabus_year_group: string;
|
||||||
|
yr_syllabus_subject: string;
|
||||||
|
yr_syllabus_subject_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface SubjectNodeInterface extends BaseNodeInterface {
|
||||||
|
subject_code: string;
|
||||||
|
subject_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface TopicNodeInterface extends BaseNodeInterface {
|
||||||
|
topic_id: string;
|
||||||
|
topic_title: string;
|
||||||
|
total_number_of_lessons_for_topic: string;
|
||||||
|
topic_type: string;
|
||||||
|
topic_assessment_type: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TopicLessonNodeInterface extends BaseNodeInterface {
|
||||||
|
topic_lesson_id: string;
|
||||||
|
topic_lesson_title: string;
|
||||||
|
topic_lesson_type: string;
|
||||||
|
topic_lesson_length: string;
|
||||||
|
topic_lesson_suggested_activities: string;
|
||||||
|
topic_lesson_skills_learned: string;
|
||||||
|
topic_lesson_weblinks: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface LearningStatementNodeInterface extends BaseNodeInterface {
|
||||||
|
lesson_learning_statement_id: string;
|
||||||
|
lesson_learning_statement: string;
|
||||||
|
lesson_learning_statement_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScienceLabNodeInterface extends BaseNodeInterface {
|
||||||
|
science_lab_id: string;
|
||||||
|
science_lab_title: string;
|
||||||
|
science_lab_summary: string;
|
||||||
|
science_lab_requirements: string;
|
||||||
|
science_lab_procedure: string;
|
||||||
|
science_lab_safety: string;
|
||||||
|
science_lab_weblinks: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// School Timetable
|
||||||
|
export interface SchoolTimetableNodeInterface extends BaseNodeInterface {
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicYearNodeInterface extends BaseNodeInterface {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicTermNodeInterface extends BaseNodeInterface {
|
||||||
|
term_name: string;
|
||||||
|
term_number: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicTermBreakNodeInterface extends BaseNodeInterface {
|
||||||
|
term_break_name: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicWeekNodeInterface extends BaseNodeInterface {
|
||||||
|
academic_week_number: string;
|
||||||
|
start_date: string;
|
||||||
|
week_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HolidayWeekNodeInterface extends BaseNodeInterface {
|
||||||
|
start_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicDayNodeInterface extends BaseNodeInterface {
|
||||||
|
academic_day: string;
|
||||||
|
date: string;
|
||||||
|
day_of_week: string;
|
||||||
|
day_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OffTimetableDayNodeInterface extends BaseNodeInterface {
|
||||||
|
date: string;
|
||||||
|
day_of_week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StaffDayNodeInterface extends BaseNodeInterface {
|
||||||
|
date: string;
|
||||||
|
day_of_week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HolidayDayNodeInterface extends BaseNodeInterface {
|
||||||
|
date: string;
|
||||||
|
day_of_week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AcademicPeriodNodeInterface extends BaseNodeInterface {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegistrationPeriodNodeInterface extends BaseNodeInterface {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BreakPeriodNodeInterface extends BaseNodeInterface {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OffTimetablePeriodNodeInterface extends BaseNodeInterface {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teacher timetable
|
||||||
|
export interface TeacherTimetableNodeInterface extends BaseNodeInterface {
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableLessonNodeInterface extends BaseNodeInterface {
|
||||||
|
subject_class: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlannedLessonNodeInterface extends BaseNodeInterface {
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
subject_class: string;
|
||||||
|
year_group: string;
|
||||||
|
subject: string;
|
||||||
|
teacher_code: string;
|
||||||
|
planning_status: string;
|
||||||
|
topic_code?: string | null | undefined;
|
||||||
|
topic_name?: string | null | undefined;
|
||||||
|
lesson_code?: string | null | undefined;
|
||||||
|
lesson_name?: string | null | undefined;
|
||||||
|
learning_statement_codes?: string | null | undefined;
|
||||||
|
learning_statements?: string | null | undefined;
|
||||||
|
learning_resource_codes?: string | null | undefined;
|
||||||
|
learning_resources?: string | null | undefined;
|
||||||
|
}
|
||||||
12
src/types/graph_relationship_types.ts
Normal file
12
src/types/graph_relationship_types.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export interface BaseRelationshipInterface {
|
||||||
|
__relationshiptype__: string;
|
||||||
|
source: string;
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// General
|
||||||
|
export interface GeneralRelationshipInterface extends BaseRelationshipInterface {
|
||||||
|
__relationshiptype__: string;
|
||||||
|
source: string;
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
32
src/utils/tldraw/cc-base/cc-graph-migrations.ts
Normal file
32
src/utils/tldraw/cc-base/cc-graph-migrations.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { ccGraphShapeProps } from './cc-graph-props'
|
||||||
|
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from 'tldraw'
|
||||||
|
import { CCGraphShape, GraphShapeType } from './cc-graph-types'
|
||||||
|
|
||||||
|
// Helper function to create version IDs for a shape type
|
||||||
|
const createVersions = (shapeType: GraphShapeType) => {
|
||||||
|
return createShapePropsMigrationIds(shapeType, {
|
||||||
|
Initial: 1 // All shapes start at version 1 as required by TLDraw
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create a migration sequence for a shape
|
||||||
|
const createMigrationSequence = (shapeType: GraphShapeType) => {
|
||||||
|
const versions = createVersions(shapeType)
|
||||||
|
return createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: versions.Initial,
|
||||||
|
up: (props: CCGraphShape['props']) => {
|
||||||
|
// Initial version - no changes needed
|
||||||
|
return props
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create migrations for all graph shapes
|
||||||
|
export const ccGraphMigrations = Object.keys(ccGraphShapeProps).reduce((acc, shapeType) => ({
|
||||||
|
...acc,
|
||||||
|
[shapeType]: createMigrationSequence(shapeType as GraphShapeType)
|
||||||
|
}), {} as Record<GraphShapeType, ReturnType<typeof createShapePropsMigrationSequence>>)
|
||||||
656
src/utils/tldraw/cc-base/cc-graph-props.ts
Normal file
656
src/utils/tldraw/cc-base/cc-graph-props.ts
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
import { T, TLBinding, TLShapeId } from 'tldraw'
|
||||||
|
import { baseShapeProps } from './cc-props'
|
||||||
|
import { ShapeState } from './cc-graph-types'
|
||||||
|
|
||||||
|
// State props validation
|
||||||
|
const stateProps = T.object({
|
||||||
|
parentId: T.optional(T.string.nullable()),
|
||||||
|
isPageChild: T.optional(T.boolean.nullable()),
|
||||||
|
hasChildren: T.optional(T.boolean.nullable()),
|
||||||
|
bindings: T.optional(T.arrayOf(T.object({})).nullable())
|
||||||
|
})
|
||||||
|
|
||||||
|
// Base props for all nodes
|
||||||
|
const graphBaseProps = {
|
||||||
|
...baseShapeProps,
|
||||||
|
__primarylabel__: T.string,
|
||||||
|
unique_id: T.string,
|
||||||
|
path: T.string,
|
||||||
|
created: T.string,
|
||||||
|
merged: T.string,
|
||||||
|
state: T.optional(stateProps.nullable()),
|
||||||
|
defaultComponent: T.optional(T.boolean.nullable())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Props for specific node types
|
||||||
|
export const ccGraphShapeProps = {
|
||||||
|
'cc-user-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
user_name: T.string,
|
||||||
|
user_email: T.string,
|
||||||
|
user_type: T.string,
|
||||||
|
user_id: T.string,
|
||||||
|
worker_node_data: T.string,
|
||||||
|
},
|
||||||
|
'cc-teacher-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
teacher_code: T.string,
|
||||||
|
teacher_name_formal: T.string,
|
||||||
|
teacher_email: T.string,
|
||||||
|
user_db_name: T.string,
|
||||||
|
worker_db_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-student-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
student_code: T.string,
|
||||||
|
student_name_formal: T.string,
|
||||||
|
student_email: T.string,
|
||||||
|
worker_db_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
name: T.string,
|
||||||
|
calendar_type: T.string,
|
||||||
|
calendar_name: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-year-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
year: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-month-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
year: T.string,
|
||||||
|
month: T.string,
|
||||||
|
month_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-week-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
start_date: T.string,
|
||||||
|
week_number: T.string,
|
||||||
|
iso_week: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-day-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
date: T.string,
|
||||||
|
day_of_week: T.string,
|
||||||
|
iso_day: T.string,
|
||||||
|
},
|
||||||
|
'cc-calendar-time-chunk-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
},
|
||||||
|
'cc-school-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
school_uuid: T.string,
|
||||||
|
school_name: T.string,
|
||||||
|
school_website: T.string,
|
||||||
|
},
|
||||||
|
'cc-department-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
department_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-room-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
room_code: T.string,
|
||||||
|
room_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-subject-class-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
subject_class_code: T.string,
|
||||||
|
year_group: T.string,
|
||||||
|
subject: T.string,
|
||||||
|
subject_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-pastoral-structure-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
},
|
||||||
|
'cc-year-group-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
year_group: T.string,
|
||||||
|
year_group_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-curriculum-structure-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
},
|
||||||
|
'cc-key-stage-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
key_stage_name: T.string,
|
||||||
|
key_stage: T.string,
|
||||||
|
},
|
||||||
|
'cc-key-stage-syllabus-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
ks_syllabus_id: T.string,
|
||||||
|
ks_syllabus_name: T.string,
|
||||||
|
ks_syllabus_key_stage: T.string,
|
||||||
|
ks_syllabus_subject: T.string,
|
||||||
|
ks_syllabus_subject_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-year-group-syllabus-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
yr_syllabus_id: T.string,
|
||||||
|
yr_syllabus_name: T.string,
|
||||||
|
yr_syllabus_year_group: T.string,
|
||||||
|
yr_syllabus_subject: T.string,
|
||||||
|
yr_syllabus_subject_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-subject-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
subject_code: T.string,
|
||||||
|
subject_name: T.string,
|
||||||
|
},
|
||||||
|
'cc-topic-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
topic_id: T.string,
|
||||||
|
topic_title: T.string,
|
||||||
|
total_number_of_lessons_for_topic: T.string,
|
||||||
|
topic_type: T.string,
|
||||||
|
topic_assessment_type: T.string,
|
||||||
|
},
|
||||||
|
'cc-topic-lesson-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
topic_lesson_id: T.string,
|
||||||
|
topic_lesson_title: T.string,
|
||||||
|
topic_lesson_type: T.string,
|
||||||
|
topic_lesson_length: T.string,
|
||||||
|
topic_lesson_skills_learned: T.string,
|
||||||
|
topic_lesson_suggested_activities: T.string,
|
||||||
|
topic_lesson_weblinks: T.string,
|
||||||
|
},
|
||||||
|
'cc-learning-statement-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
lesson_learning_statement_id: T.string,
|
||||||
|
lesson_learning_statement: T.string,
|
||||||
|
lesson_learning_statement_type: T.string,
|
||||||
|
},
|
||||||
|
'cc-science-lab-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
science_lab_id: T.string,
|
||||||
|
science_lab_title: T.string,
|
||||||
|
science_lab_summary: T.string,
|
||||||
|
science_lab_requirements: T.string,
|
||||||
|
science_lab_procedure: T.string,
|
||||||
|
science_lab_safety: T.string,
|
||||||
|
science_lab_weblinks: T.string,
|
||||||
|
},
|
||||||
|
'cc-teacher-timetable-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
teacher_id: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
},
|
||||||
|
'cc-timetable-lesson-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
subject_class: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-planned-lesson-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
subject_class: T.string,
|
||||||
|
year_group: T.string,
|
||||||
|
subject: T.string,
|
||||||
|
teacher_code: T.string,
|
||||||
|
planning_status: T.string,
|
||||||
|
topic_code: T.string,
|
||||||
|
topic_name: T.string,
|
||||||
|
lesson_code: T.string,
|
||||||
|
lesson_name: T.string,
|
||||||
|
learning_statement_codes: T.string,
|
||||||
|
learning_statements: T.string,
|
||||||
|
learning_resource_codes: T.string,
|
||||||
|
learning_resources: T.string,
|
||||||
|
},
|
||||||
|
'cc-school-timetable-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
},
|
||||||
|
'cc-academic-year-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
year: T.string,
|
||||||
|
},
|
||||||
|
'cc-academic-term-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
term_name: T.string,
|
||||||
|
term_number: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
},
|
||||||
|
'cc-academic-week-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
academic_week_number: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
week_type: T.string,
|
||||||
|
},
|
||||||
|
'cc-academic-day-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
academic_day: T.string,
|
||||||
|
date: T.string,
|
||||||
|
day_of_week: T.string,
|
||||||
|
day_type: T.string,
|
||||||
|
},
|
||||||
|
'cc-academic-period-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
name: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-registration-period-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
name: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
},
|
||||||
|
'cc-department-structure-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
department_structure_type: T.string,
|
||||||
|
},
|
||||||
|
'cc-user-teacher-timetable-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
school_db_name: T.string,
|
||||||
|
school_timetable_id: T.string,
|
||||||
|
},
|
||||||
|
'cc-user-timetable-lesson-node': {
|
||||||
|
...graphBaseProps,
|
||||||
|
subject_class: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
school_db_name: T.string,
|
||||||
|
school_period_id: T.string,
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Default props getters
|
||||||
|
export const getDefaultBaseProps = () => ({
|
||||||
|
w: 200 as number,
|
||||||
|
h: 200 as number,
|
||||||
|
headerColor: '#3e6589' as string,
|
||||||
|
backgroundColor: '#f0f0f0' as string,
|
||||||
|
title: 'Untitled' as string,
|
||||||
|
isLocked: false as boolean,
|
||||||
|
unique_id: '' as string,
|
||||||
|
path: '' as string,
|
||||||
|
created: '' as string,
|
||||||
|
merged: '' as string,
|
||||||
|
state: {
|
||||||
|
parentId: null as TLShapeId | null,
|
||||||
|
isPageChild: true as boolean | null,
|
||||||
|
hasChildren: null as boolean | null,
|
||||||
|
bindings: null as TLBinding[] | null
|
||||||
|
} as ShapeState | null,
|
||||||
|
defaultComponent: true as boolean | null
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCUserNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
__primarylabel__: 'User',
|
||||||
|
user_name: '',
|
||||||
|
user_email: '',
|
||||||
|
user_type: '',
|
||||||
|
user_id: '',
|
||||||
|
worker_node_data: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCTeacherNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
__primarylabel__: 'Teacher',
|
||||||
|
teacher_code: '',
|
||||||
|
teacher_name_formal: '',
|
||||||
|
teacher_email: '',
|
||||||
|
user_db_name: '',
|
||||||
|
worker_db_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCStudentNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
__primarylabel__: 'Student',
|
||||||
|
student_code: '',
|
||||||
|
student_name_formal: '',
|
||||||
|
student_email: '',
|
||||||
|
worker_db_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar',
|
||||||
|
__primarylabel__: 'Calendar',
|
||||||
|
name: '',
|
||||||
|
calendar_type: '',
|
||||||
|
calendar_name: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarYearNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar Year',
|
||||||
|
__primarylabel__: 'Calendar Year',
|
||||||
|
year: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarMonthNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar Month',
|
||||||
|
__primarylabel__: 'Calendar Month',
|
||||||
|
year: '',
|
||||||
|
month: '',
|
||||||
|
month_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarWeekNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar Week',
|
||||||
|
__primarylabel__: 'Calendar Week',
|
||||||
|
start_date: '',
|
||||||
|
week_number: '',
|
||||||
|
iso_week: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarDayNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar Day',
|
||||||
|
__primarylabel__: 'Calendar Day',
|
||||||
|
date: '',
|
||||||
|
day_of_week: '',
|
||||||
|
iso_day: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarTimeChunkNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Calendar Time Chunk',
|
||||||
|
__primarylabel__: 'Calendar Time Chunk',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCSchoolNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'School',
|
||||||
|
__primarylabel__: 'School',
|
||||||
|
school_uuid: '',
|
||||||
|
school_name: '',
|
||||||
|
school_website: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCDepartmentNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Department',
|
||||||
|
__primarylabel__: 'Department',
|
||||||
|
department_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCRoomNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Room',
|
||||||
|
__primarylabel__: 'Room',
|
||||||
|
room_code: '',
|
||||||
|
room_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCSubjectClassNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Subject Class',
|
||||||
|
__primarylabel__: 'Subject Class',
|
||||||
|
subject_class_code: '',
|
||||||
|
year_group: '',
|
||||||
|
subject: '',
|
||||||
|
subject_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCPastoralStructureNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Pastoral Structure',
|
||||||
|
__primarylabel__: 'Pastoral Structure',
|
||||||
|
pastoral_structure_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCYearGroupNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Year Group',
|
||||||
|
__primarylabel__: 'Year Group',
|
||||||
|
year_group: '',
|
||||||
|
year_group_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCurriculumStructureNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Curriculum Structure',
|
||||||
|
__primarylabel__: 'Curriculum Structure',
|
||||||
|
curriculum_structure_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCKeyStageNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Key Stage',
|
||||||
|
__primarylabel__: 'Key Stage',
|
||||||
|
key_stage_name: '',
|
||||||
|
key_stage: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCKeyStageSyllabusNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Key Stage Syllabus',
|
||||||
|
__primarylabel__: 'Key Stage Syllabus',
|
||||||
|
ks_syllabus_id: '',
|
||||||
|
ks_syllabus_name: '',
|
||||||
|
ks_syllabus_key_stage: '',
|
||||||
|
ks_syllabus_subject: '',
|
||||||
|
ks_syllabus_subject_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCYearGroupSyllabusNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Year Group Syllabus',
|
||||||
|
__primarylabel__: 'Year Group Syllabus',
|
||||||
|
yr_syllabus_id: '',
|
||||||
|
yr_syllabus_name: '',
|
||||||
|
yr_syllabus_year_group: '',
|
||||||
|
yr_syllabus_subject: '',
|
||||||
|
yr_syllabus_subject_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCSubjectNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Subject',
|
||||||
|
__primarylabel__: 'Subject',
|
||||||
|
subject_code: '',
|
||||||
|
subject_name: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCTopicNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Topic',
|
||||||
|
__primarylabel__: 'Topic',
|
||||||
|
topic_id: '',
|
||||||
|
topic_title: '',
|
||||||
|
total_number_of_lessons_for_topic: '',
|
||||||
|
topic_type: '',
|
||||||
|
topic_assessment_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCTopicLessonNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Topic Lesson',
|
||||||
|
__primarylabel__: 'Topic Lesson',
|
||||||
|
topic_lesson_id: '',
|
||||||
|
topic_lesson_title: '',
|
||||||
|
topic_lesson_type: '',
|
||||||
|
topic_lesson_length: '',
|
||||||
|
topic_lesson_skills_learned: '',
|
||||||
|
topic_lesson_suggested_activities: '',
|
||||||
|
topic_lesson_weblinks: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCLearningStatementNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Learning Statement',
|
||||||
|
__primarylabel__: 'Learning Statement',
|
||||||
|
lesson_learning_statement_id: '',
|
||||||
|
lesson_learning_statement: '',
|
||||||
|
lesson_learning_statement_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCScienceLabNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Science Lab',
|
||||||
|
__primarylabel__: 'Science Lab',
|
||||||
|
science_lab_id: '',
|
||||||
|
science_lab_title: '',
|
||||||
|
science_lab_summary: '',
|
||||||
|
science_lab_requirements: '',
|
||||||
|
science_lab_procedure: '',
|
||||||
|
science_lab_safety: '',
|
||||||
|
science_lab_weblinks: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCTeacherTimetableNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Teacher Timetable',
|
||||||
|
__primarylabel__: 'Teacher Timetable',
|
||||||
|
teacher_id: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCTimetableLessonNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Timetable Lesson',
|
||||||
|
__primarylabel__: 'Timetable Lesson',
|
||||||
|
subject_class: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCPlannedLessonNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Planned Lesson',
|
||||||
|
__primarylabel__: 'Planned Lesson',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
subject_class: '',
|
||||||
|
year_group: '',
|
||||||
|
subject: '',
|
||||||
|
teacher_code: '',
|
||||||
|
planning_status: '',
|
||||||
|
topic_code: '',
|
||||||
|
topic_name: '',
|
||||||
|
lesson_code: '',
|
||||||
|
lesson_name: '',
|
||||||
|
learning_statement_codes: '',
|
||||||
|
learning_statements: '',
|
||||||
|
learning_resource_codes: '',
|
||||||
|
learning_resources: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCSchoolTimetableNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'School Timetable',
|
||||||
|
__primarylabel__: 'School Timetable',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCAcademicYearNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Academic Year',
|
||||||
|
__primarylabel__: 'Academic Year',
|
||||||
|
year: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCAcademicTermNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Academic Term',
|
||||||
|
__primarylabel__: 'Academic Term',
|
||||||
|
term_name: '',
|
||||||
|
term_number: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCAcademicWeekNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Academic Week',
|
||||||
|
__primarylabel__: 'Academic Week',
|
||||||
|
academic_week_number: '',
|
||||||
|
start_date: '',
|
||||||
|
week_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCAcademicDayNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Academic Day',
|
||||||
|
__primarylabel__: 'Academic Day',
|
||||||
|
academic_day: '',
|
||||||
|
date: '',
|
||||||
|
day_of_week: '',
|
||||||
|
day_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCAcademicPeriodNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Academic Period',
|
||||||
|
__primarylabel__: 'Academic Period',
|
||||||
|
name: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCRegistrationPeriodNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Registration Period',
|
||||||
|
__primarylabel__: 'Registration Period',
|
||||||
|
name: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCDepartmentStructureNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'Department Structure',
|
||||||
|
__primarylabel__: 'DepartmentStructure',
|
||||||
|
department_structure_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCUserTeacherTimetableNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'User Teacher Timetable',
|
||||||
|
__primarylabel__: 'UserTeacherTimetable',
|
||||||
|
school_db_name: '',
|
||||||
|
school_timetable_id: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCUserTimetableLessonNodeProps = () => ({
|
||||||
|
...getDefaultBaseProps(),
|
||||||
|
title: 'User Timetable Lesson',
|
||||||
|
__primarylabel__: 'UserTimetableLesson',
|
||||||
|
subject_class: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
school_db_name: '',
|
||||||
|
school_period_id: '',
|
||||||
|
})
|
||||||
169
src/utils/tldraw/cc-base/cc-graph-styles.ts
Normal file
169
src/utils/tldraw/cc-base/cc-graph-styles.ts
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Shared styles for all nodes
|
||||||
|
export const SHARED_NODE_STYLES = {
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column' as const,
|
||||||
|
padding: '8px',
|
||||||
|
gap: '4px',
|
||||||
|
backgroundColor: 'var(--color-muted)',
|
||||||
|
color: 'var(--color-text)',
|
||||||
|
borderRadius: '4px',
|
||||||
|
minWidth: '150px',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 'bold' as const,
|
||||||
|
marginBottom: '4px',
|
||||||
|
color: 'var(--color-text)',
|
||||||
|
},
|
||||||
|
property: {
|
||||||
|
label: {
|
||||||
|
fontSize: '12px',
|
||||||
|
color: 'var(--color-text-2)',
|
||||||
|
marginRight: '4px',
|
||||||
|
fontWeight: '500' as const,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: '12px',
|
||||||
|
color: 'var(--color-text)',
|
||||||
|
fontWeight: '200' as const,
|
||||||
|
},
|
||||||
|
wrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '4px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
container: {
|
||||||
|
padding: '8px',
|
||||||
|
backgroundColor: 'var(--color-error)',
|
||||||
|
color: 'white',
|
||||||
|
borderRadius: '4px',
|
||||||
|
fontSize: '12px',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
fontWeight: 'bold' as const,
|
||||||
|
},
|
||||||
|
details: {
|
||||||
|
marginTop: '4px',
|
||||||
|
opacity: 0.8,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultComponent: {
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
gap: '8px',
|
||||||
|
marginBottom: '8px',
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
padding: '4px 8px',
|
||||||
|
fontSize: '12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
backgroundColor: 'var(--color-muted-2)',
|
||||||
|
color: 'var(--color-text)',
|
||||||
|
border: 'none',
|
||||||
|
cursor: 'pointer',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'var(--color-muted-3)',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Color themes for different node types
|
||||||
|
export const NODE_THEMES = {
|
||||||
|
calendar: {
|
||||||
|
headerColor: '#0066cc',
|
||||||
|
backgroundColor: '#e6f0ff',
|
||||||
|
},
|
||||||
|
academic: {
|
||||||
|
headerColor: '#008000',
|
||||||
|
backgroundColor: '#e6ffe6',
|
||||||
|
},
|
||||||
|
curriculum: {
|
||||||
|
headerColor: '#ff8c00',
|
||||||
|
backgroundColor: '#fff3e6',
|
||||||
|
},
|
||||||
|
pastoral: {
|
||||||
|
headerColor: '#8a2be2',
|
||||||
|
backgroundColor: '#f5e6ff',
|
||||||
|
},
|
||||||
|
people: {
|
||||||
|
headerColor: '#cc0000',
|
||||||
|
backgroundColor: '#ffe6e6',
|
||||||
|
},
|
||||||
|
resource: {
|
||||||
|
headerColor: '#cccc00',
|
||||||
|
backgroundColor: '#fffff0',
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Node type to theme mapping
|
||||||
|
export const NODE_TYPE_THEMES: Record<string, keyof typeof NODE_THEMES> = {
|
||||||
|
// Calendar nodes
|
||||||
|
'cc-calendar-node': 'calendar',
|
||||||
|
'cc-calendar-year-node': 'calendar',
|
||||||
|
'cc-calendar-month-node': 'calendar',
|
||||||
|
'cc-calendar-week-node': 'calendar',
|
||||||
|
'cc-calendar-day-node': 'calendar',
|
||||||
|
'cc-calendar-time-chunk-node': 'calendar',
|
||||||
|
|
||||||
|
// Academic nodes
|
||||||
|
'cc-academic-year-node': 'academic',
|
||||||
|
'cc-academic-term-node': 'academic',
|
||||||
|
'cc-academic-week-node': 'academic',
|
||||||
|
'cc-academic-day-node': 'academic',
|
||||||
|
'cc-academic-period-node': 'academic',
|
||||||
|
'cc-registration-period-node': 'academic',
|
||||||
|
'cc-timetable-lesson-node': 'academic',
|
||||||
|
'cc-planned-lesson-node': 'academic',
|
||||||
|
'cc-school-timetable-node': 'academic',
|
||||||
|
'cc-user-teacher-timetable-node': 'academic',
|
||||||
|
'cc-user-timetable-lesson-node': 'academic',
|
||||||
|
|
||||||
|
// Curriculum nodes
|
||||||
|
'cc-curriculum-structure-node': 'curriculum',
|
||||||
|
'cc-key-stage-node': 'curriculum',
|
||||||
|
'cc-key-stage-syllabus-node': 'curriculum',
|
||||||
|
|
||||||
|
'cc-year-group-syllabus-node': 'curriculum',
|
||||||
|
'cc-subject-node': 'curriculum',
|
||||||
|
'cc-topic-node': 'curriculum',
|
||||||
|
'cc-topic-lesson-node': 'curriculum',
|
||||||
|
'cc-learning-statement-node': 'curriculum',
|
||||||
|
'cc-science-lab-node': 'curriculum',
|
||||||
|
|
||||||
|
// Pastoral nodes
|
||||||
|
'cc-pastoral-structure-node': 'pastoral',
|
||||||
|
'cc-year-group-node': 'pastoral',
|
||||||
|
|
||||||
|
// People nodes
|
||||||
|
'cc-user-node': 'people',
|
||||||
|
'cc-teacher-node': 'people',
|
||||||
|
'cc-student-node': 'people',
|
||||||
|
|
||||||
|
// Resource nodes
|
||||||
|
'cc-school-node': 'resource',
|
||||||
|
'cc-department-node': 'resource',
|
||||||
|
'cc-room-node': 'resource',
|
||||||
|
'cc-subject-class-node': 'resource',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Helper function to get theme for a node type
|
||||||
|
export const getNodeTheme = (nodeType: string) => {
|
||||||
|
const themeKey = NODE_TYPE_THEMES[nodeType]
|
||||||
|
return themeKey ? NODE_THEMES[themeKey] : NODE_THEMES.resource // Default to resource theme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get styles for a specific node type
|
||||||
|
export const getNodeStyles = (nodeType: string) => {
|
||||||
|
const theme = getNodeTheme(nodeType)
|
||||||
|
return {
|
||||||
|
...SHARED_NODE_STYLES,
|
||||||
|
container: {
|
||||||
|
...SHARED_NODE_STYLES.container,
|
||||||
|
backgroundColor: theme.backgroundColor,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
387
src/utils/tldraw/cc-base/cc-graph-types.ts
Normal file
387
src/utils/tldraw/cc-base/cc-graph-types.ts
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
import { TLBinding, TLBaseShape, TLShapeId } from 'tldraw'
|
||||||
|
import { CCBaseShape } from './cc-types'
|
||||||
|
import { CCBaseProps } from './cc-props'
|
||||||
|
import { ccGraphShapeProps } from './cc-graph-props'
|
||||||
|
|
||||||
|
// Export type for graph shape types
|
||||||
|
export type GraphShapeType = keyof typeof ccGraphShapeProps
|
||||||
|
|
||||||
|
export interface ShapeState {
|
||||||
|
parentId: TLShapeId | null
|
||||||
|
isPageChild: boolean | null
|
||||||
|
hasChildren: boolean | null
|
||||||
|
bindings: TLBinding[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCGraphShapeProps = CCBaseProps & {
|
||||||
|
__primarylabel__: string
|
||||||
|
unique_id: string
|
||||||
|
path: string
|
||||||
|
created: string
|
||||||
|
merged: string
|
||||||
|
state: ShapeState | null | undefined
|
||||||
|
defaultComponent: boolean | null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the base shape type for graph shapes
|
||||||
|
export type CCGraphShape = CCBaseShape & TLBaseShape<GraphShapeType, {
|
||||||
|
__primarylabel__: CCGraphShapeProps['__primarylabel__']
|
||||||
|
unique_id: CCGraphShapeProps['unique_id']
|
||||||
|
path: CCGraphShapeProps['path']
|
||||||
|
created: CCGraphShapeProps['created']
|
||||||
|
merged: CCGraphShapeProps['merged']
|
||||||
|
state: CCGraphShapeProps['state']
|
||||||
|
defaultComponent: CCGraphShapeProps['defaultComponent']
|
||||||
|
}>
|
||||||
|
|
||||||
|
export type CCUserNodeProps = CCGraphShapeProps & {
|
||||||
|
user_name: string
|
||||||
|
user_email: string
|
||||||
|
user_type: string
|
||||||
|
user_id: string
|
||||||
|
worker_node_data: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCTeacherNodeProps = CCGraphShapeProps & {
|
||||||
|
teacher_code: string
|
||||||
|
teacher_name_formal: string
|
||||||
|
teacher_email: string
|
||||||
|
user_db_name: string
|
||||||
|
worker_db_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCStudentNodeProps = CCGraphShapeProps & {
|
||||||
|
student_name_formal: string
|
||||||
|
student_code: string
|
||||||
|
student_email: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarNodeProps = CCGraphShapeProps & {
|
||||||
|
title: string
|
||||||
|
name: string
|
||||||
|
calendar_type: string
|
||||||
|
calendar_name: string
|
||||||
|
start_date: string
|
||||||
|
end_date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarYearNodeProps = CCGraphShapeProps & {
|
||||||
|
year: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarMonthNodeProps = CCGraphShapeProps & {
|
||||||
|
year: string
|
||||||
|
month: string
|
||||||
|
month_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarWeekNodeProps = CCGraphShapeProps & {
|
||||||
|
start_date: string
|
||||||
|
week_number: string
|
||||||
|
iso_week: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarDayNodeProps = CCGraphShapeProps & {
|
||||||
|
date: string
|
||||||
|
day_of_week: string
|
||||||
|
iso_day: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCalendarTimeChunkNodeProps = CCGraphShapeProps & {
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCSchoolNodeProps = CCGraphShapeProps & {
|
||||||
|
school_uuid: string
|
||||||
|
school_name: string
|
||||||
|
school_website: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCDepartmentNodeProps = CCGraphShapeProps & {
|
||||||
|
department_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCRoomNodeProps = CCGraphShapeProps & {
|
||||||
|
room_code: string
|
||||||
|
room_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCSubjectClassNodeProps = CCGraphShapeProps & {
|
||||||
|
subject_class_code: string
|
||||||
|
year_group: string
|
||||||
|
subject: string
|
||||||
|
subject_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCPastoralStructureNodeProps = CCGraphShapeProps & {
|
||||||
|
pastoral_structure_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCYearGroupNodeProps = CCGraphShapeProps & {
|
||||||
|
year_group: string
|
||||||
|
year_group_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCCurriculumStructureNodeProps = CCGraphShapeProps & {
|
||||||
|
curriculum_structure_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCKeyStageNodeProps = CCGraphShapeProps & {
|
||||||
|
key_stage_name: string
|
||||||
|
key_stage: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCKeyStageSyllabusNodeProps = CCGraphShapeProps & {
|
||||||
|
ks_syllabus_id: string
|
||||||
|
ks_syllabus_name: string
|
||||||
|
ks_syllabus_key_stage: string
|
||||||
|
ks_syllabus_subject: string
|
||||||
|
ks_syllabus_subject_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCYearGroupSyllabusNodeProps = CCGraphShapeProps & {
|
||||||
|
yr_syllabus_id: string
|
||||||
|
yr_syllabus_name: string
|
||||||
|
yr_syllabus_year_group: string
|
||||||
|
yr_syllabus_subject: string
|
||||||
|
yr_syllabus_subject_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCSubjectNodeProps = CCGraphShapeProps & {
|
||||||
|
subject_code: string
|
||||||
|
subject_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCTopicNodeProps = CCGraphShapeProps & {
|
||||||
|
topic_id: string
|
||||||
|
topic_title: string
|
||||||
|
total_number_of_lessons_for_topic: string
|
||||||
|
topic_type: string
|
||||||
|
topic_assessment_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCTopicLessonNodeProps = CCGraphShapeProps & {
|
||||||
|
topic_lesson_id: string
|
||||||
|
topic_lesson_title: string
|
||||||
|
topic_lesson_type: string
|
||||||
|
topic_lesson_length: string
|
||||||
|
topic_lesson_skills_learned: string
|
||||||
|
topic_lesson_suggested_activities: string
|
||||||
|
topic_lesson_weblinks: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCLearningStatementNodeProps = CCGraphShapeProps & {
|
||||||
|
lesson_learning_statement_id: string
|
||||||
|
lesson_learning_statement: string
|
||||||
|
lesson_learning_statement_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCScienceLabNodeProps = CCGraphShapeProps & {
|
||||||
|
science_lab_id: string
|
||||||
|
science_lab_title: string
|
||||||
|
science_lab_summary: string
|
||||||
|
science_lab_requirements: string
|
||||||
|
science_lab_procedure: string
|
||||||
|
science_lab_safety: string
|
||||||
|
science_lab_weblinks: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCTeacherTimetableNodeProps = CCGraphShapeProps & {
|
||||||
|
teacher_id: string
|
||||||
|
start_date: string
|
||||||
|
end_date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCTimetableLessonNodeProps = CCGraphShapeProps & {
|
||||||
|
subject_class: string
|
||||||
|
date: string
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
period_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCPlannedLessonNodeProps = CCGraphShapeProps & {
|
||||||
|
date: string
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
period_code: string
|
||||||
|
subject_class: string
|
||||||
|
year_group: string
|
||||||
|
subject: string
|
||||||
|
teacher_code: string
|
||||||
|
planning_status: string
|
||||||
|
topic_code: string
|
||||||
|
topic_name: string
|
||||||
|
lesson_code: string
|
||||||
|
lesson_name: string
|
||||||
|
learning_statement_codes: string
|
||||||
|
learning_statements: string
|
||||||
|
learning_resource_codes: string
|
||||||
|
learning_resources: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCSchoolTimetableNodeProps = CCGraphShapeProps & {
|
||||||
|
start_date: string
|
||||||
|
end_date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCAcademicYearNodeProps = CCGraphShapeProps & {
|
||||||
|
year: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCAcademicTermNodeProps = CCGraphShapeProps & {
|
||||||
|
term_name: string
|
||||||
|
term_number: string
|
||||||
|
start_date: string
|
||||||
|
end_date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCAcademicWeekNodeProps = CCGraphShapeProps & {
|
||||||
|
academic_week_number: string
|
||||||
|
start_date: string
|
||||||
|
week_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCAcademicDayNodeProps = CCGraphShapeProps & {
|
||||||
|
academic_day: string
|
||||||
|
date: string
|
||||||
|
day_of_week: string
|
||||||
|
day_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCAcademicPeriodNodeProps = CCGraphShapeProps & {
|
||||||
|
name: string
|
||||||
|
date: string
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
period_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCRegistrationPeriodNodeProps = CCGraphShapeProps & {
|
||||||
|
name: string
|
||||||
|
date: string
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
period_code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCDepartmentStructureNodeProps = CCGraphShapeProps & {
|
||||||
|
department_structure_type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCUserTeacherTimetableNodeProps = CCGraphShapeProps & {
|
||||||
|
school_db_name: string
|
||||||
|
school_timetable_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CCUserTimetableLessonNodeProps = CCGraphShapeProps & {
|
||||||
|
subject_class: string
|
||||||
|
date: string
|
||||||
|
start_time: string
|
||||||
|
end_time: string
|
||||||
|
period_code: string
|
||||||
|
school_db_name: string
|
||||||
|
school_period_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a type-safe mapping of node types to their configurations
|
||||||
|
export type CCNodeTypes = {
|
||||||
|
User: { props: CCUserNodeProps }
|
||||||
|
Developer: { props: CCUserNodeProps }
|
||||||
|
Teacher: { props: CCTeacherNodeProps }
|
||||||
|
Student: { props: CCStudentNodeProps }
|
||||||
|
Calendar: { props: CCCalendarNodeProps }
|
||||||
|
TeacherTimetable: { props: CCTeacherTimetableNodeProps }
|
||||||
|
TimetableLesson: { props: CCTimetableLessonNodeProps }
|
||||||
|
PlannedLesson: { props: CCPlannedLessonNodeProps }
|
||||||
|
School: { props: CCSchoolNodeProps }
|
||||||
|
CalendarYear: { props: CCCalendarYearNodeProps }
|
||||||
|
CalendarMonth: { props: CCCalendarMonthNodeProps }
|
||||||
|
CalendarWeek: { props: CCCalendarWeekNodeProps }
|
||||||
|
CalendarDay: { props: CCCalendarDayNodeProps }
|
||||||
|
CalendarTimeChunk: { props: CCCalendarTimeChunkNodeProps }
|
||||||
|
ScienceLab: { props: CCScienceLabNodeProps }
|
||||||
|
KeyStageSyllabus: { props: CCKeyStageSyllabusNodeProps }
|
||||||
|
YearGroupSyllabus: { props: CCYearGroupSyllabusNodeProps }
|
||||||
|
CurriculumStructure: { props: CCCurriculumStructureNodeProps }
|
||||||
|
Topic: { props: CCTopicNodeProps }
|
||||||
|
TopicLesson: { props: CCTopicLessonNodeProps }
|
||||||
|
LearningStatement: { props: CCLearningStatementNodeProps }
|
||||||
|
SchoolTimetable: { props: CCSchoolTimetableNodeProps }
|
||||||
|
AcademicYear: { props: CCAcademicYearNodeProps }
|
||||||
|
AcademicTerm: { props: CCAcademicTermNodeProps }
|
||||||
|
AcademicWeek: { props: CCAcademicWeekNodeProps }
|
||||||
|
AcademicDay: { props: CCAcademicDayNodeProps }
|
||||||
|
AcademicPeriod: { props: CCAcademicPeriodNodeProps }
|
||||||
|
RegistrationPeriod: { props: CCRegistrationPeriodNodeProps }
|
||||||
|
PastoralStructure: { props: CCPastoralStructureNodeProps }
|
||||||
|
KeyStage: { props: CCKeyStageNodeProps }
|
||||||
|
Department: { props: CCDepartmentNodeProps }
|
||||||
|
Room: { props: CCRoomNodeProps }
|
||||||
|
SubjectClass: { props: CCSubjectClassNodeProps }
|
||||||
|
DepartmentStructure: { props: CCDepartmentStructureNodeProps }
|
||||||
|
UserTeacherTimetable: { props: CCUserTeacherTimetableNodeProps }
|
||||||
|
UserTimetableLesson: { props: CCUserTimetableLessonNodeProps }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get shape type from node type
|
||||||
|
export const getShapeType = (nodeType: keyof CCNodeTypes): string => {
|
||||||
|
return `cc-${nodeType.replace(/([A-Z])/g, '-$1').toLowerCase().substring(1)}-node`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get allowed props from node type
|
||||||
|
export const getAllowedProps = (): string[] => {
|
||||||
|
return ['__primarylabel__', 'unique_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get node configuration
|
||||||
|
export const getNodeConfig = <T extends keyof CCNodeTypes>(nodeType: T) => {
|
||||||
|
const shapeType = getShapeType(nodeType);
|
||||||
|
return {
|
||||||
|
shapeType,
|
||||||
|
allowedProps: getAllowedProps()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a string is a valid node type
|
||||||
|
export const isValidNodeType = (type: string): type is keyof CCNodeTypes => {
|
||||||
|
return type in {
|
||||||
|
User: true,
|
||||||
|
Developer: true,
|
||||||
|
Teacher: true,
|
||||||
|
Student: true,
|
||||||
|
Calendar: true,
|
||||||
|
TeacherTimetable: true,
|
||||||
|
TimetableLesson: true,
|
||||||
|
PlannedLesson: true,
|
||||||
|
School: true,
|
||||||
|
CalendarYear: true,
|
||||||
|
CalendarMonth: true,
|
||||||
|
CalendarWeek: true,
|
||||||
|
CalendarDay: true,
|
||||||
|
CalendarTimeChunk: true,
|
||||||
|
ScienceLab: true,
|
||||||
|
KeyStageSyllabus: true,
|
||||||
|
YearGroupSyllabus: true,
|
||||||
|
CurriculumStructure: true,
|
||||||
|
Topic: true,
|
||||||
|
TopicLesson: true,
|
||||||
|
LearningStatement: true,
|
||||||
|
SchoolTimetable: true,
|
||||||
|
AcademicYear: true,
|
||||||
|
AcademicTerm: true,
|
||||||
|
AcademicWeek: true,
|
||||||
|
AcademicDay: true,
|
||||||
|
AcademicPeriod: true,
|
||||||
|
RegistrationPeriod: true,
|
||||||
|
PastoralStructure: true,
|
||||||
|
KeyStage: true,
|
||||||
|
Department: true,
|
||||||
|
Room: true,
|
||||||
|
SubjectClass: true,
|
||||||
|
DepartmentStructure: true,
|
||||||
|
UserTeacherTimetable: true,
|
||||||
|
UserTimetableLesson: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
246
src/utils/tldraw/cc-base/cc-migrations.ts
Normal file
246
src/utils/tldraw/cc-base/cc-migrations.ts
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import { TLRecord, TLShape } from 'tldraw'
|
||||||
|
import { getDefaultCCBaseProps, getDefaultCCCalendarProps, getDefaultCCLiveTranscriptionProps, getDefaultCCSettingsProps, getDefaultCCSlideProps, getDefaultCCSlideShowProps, getDefaultCCSlideLayoutBindingProps, getDefaultCCYoutubeEmbedProps, getDefaultCCSearchProps, getDefaultCCWebBrowserProps } from './cc-props'
|
||||||
|
|
||||||
|
// Export both shape and binding migrations
|
||||||
|
export const ccBindingMigrations = {
|
||||||
|
'cc-slide-layout': {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'binding') return record
|
||||||
|
if (record.type !== 'cc-slide-layout') return record
|
||||||
|
return {
|
||||||
|
...record,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCSlideLayoutBindingProps(),
|
||||||
|
...record.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ccShapeMigrations = {
|
||||||
|
base: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-base') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
calendar: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-calendar') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCCalendarProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
liveTranscription: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-live-transcription') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCLiveTranscriptionProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-settings') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCSettingsProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
slideshow: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-slideshow') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCSlideShowProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
slide: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-slide') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCSlideProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
'cc-youtube-embed': {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-youtube-embed') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCYoutubeEmbedProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
search: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-search') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCSearchProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
webBrowser: {
|
||||||
|
firstVersion: 1,
|
||||||
|
currentVersion: 1,
|
||||||
|
migrators: {
|
||||||
|
1: {
|
||||||
|
up: (record: TLRecord) => {
|
||||||
|
if (record.typeName !== 'shape') return record
|
||||||
|
const shape = record as TLShape
|
||||||
|
if (shape.type !== 'cc-web-browser') return record
|
||||||
|
return {
|
||||||
|
...shape,
|
||||||
|
props: {
|
||||||
|
...getDefaultCCWebBrowserProps(),
|
||||||
|
...shape.props,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down: (record: TLRecord) => {
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
262
src/utils/tldraw/cc-base/cc-props.ts
Normal file
262
src/utils/tldraw/cc-base/cc-props.ts
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
import { T } from 'tldraw'
|
||||||
|
import { CC_BASE_STYLE_CONSTANTS, CC_SLIDESHOW_STYLE_CONSTANTS } from './cc-styles'
|
||||||
|
|
||||||
|
export interface CCBaseProps {
|
||||||
|
title: string
|
||||||
|
w: number
|
||||||
|
h: number
|
||||||
|
headerColor: string
|
||||||
|
backgroundColor: string
|
||||||
|
isLocked: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a constant for the base props validation
|
||||||
|
export const baseShapeProps = {
|
||||||
|
title: T.string,
|
||||||
|
w: T.number,
|
||||||
|
h: T.number,
|
||||||
|
headerColor: T.string,
|
||||||
|
backgroundColor: T.string,
|
||||||
|
isLocked: T.boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ccShapeProps = {
|
||||||
|
base: baseShapeProps,
|
||||||
|
|
||||||
|
calendar: {
|
||||||
|
...baseShapeProps,
|
||||||
|
date: T.string,
|
||||||
|
selectedDate: T.string,
|
||||||
|
view: T.string,
|
||||||
|
events: T.arrayOf(T.object({
|
||||||
|
id: T.string,
|
||||||
|
title: T.string,
|
||||||
|
start: T.string,
|
||||||
|
end: T.string,
|
||||||
|
groupId: T.string.optional(),
|
||||||
|
extendedProps: T.object({
|
||||||
|
subjectClass: T.string,
|
||||||
|
color: T.string,
|
||||||
|
periodCode: T.string,
|
||||||
|
path: T.string.optional()
|
||||||
|
})
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
|
||||||
|
liveTranscription: {
|
||||||
|
...baseShapeProps,
|
||||||
|
isRecording: T.boolean,
|
||||||
|
segments: T.arrayOf(T.object({
|
||||||
|
id: T.string,
|
||||||
|
text: T.string,
|
||||||
|
completed: T.boolean,
|
||||||
|
start: T.string,
|
||||||
|
end: T.string,
|
||||||
|
})),
|
||||||
|
currentSegment: T.object({
|
||||||
|
id: T.string,
|
||||||
|
text: T.string,
|
||||||
|
completed: T.boolean,
|
||||||
|
start: T.string,
|
||||||
|
end: T.string,
|
||||||
|
}).optional(),
|
||||||
|
lastProcessedSegment: T.string.optional(),
|
||||||
|
},
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
...baseShapeProps,
|
||||||
|
userEmail: T.string,
|
||||||
|
userRole: T.string,
|
||||||
|
isTeacher: T.boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
slideshow: {
|
||||||
|
...baseShapeProps,
|
||||||
|
currentSlideIndex: T.number,
|
||||||
|
slidePattern: T.string,
|
||||||
|
numSlides: T.number,
|
||||||
|
slides: T.arrayOf(T.object({
|
||||||
|
imageData: T.string,
|
||||||
|
meta: T.object({
|
||||||
|
text: T.string,
|
||||||
|
format: T.string,
|
||||||
|
}),
|
||||||
|
})).optional(),
|
||||||
|
},
|
||||||
|
|
||||||
|
slide: {
|
||||||
|
...baseShapeProps,
|
||||||
|
imageData: T.string,
|
||||||
|
meta: T.object({
|
||||||
|
text: T.string,
|
||||||
|
format: T.string,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
|
||||||
|
'cc-youtube-embed': {
|
||||||
|
...baseShapeProps,
|
||||||
|
video_url: T.string,
|
||||||
|
transcript: T.arrayOf(T.object({
|
||||||
|
start: T.number,
|
||||||
|
duration: T.number,
|
||||||
|
text: T.string,
|
||||||
|
})),
|
||||||
|
transcriptVisible: T.boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
search: {
|
||||||
|
...baseShapeProps,
|
||||||
|
query: T.string,
|
||||||
|
results: T.arrayOf(T.object({
|
||||||
|
title: T.string,
|
||||||
|
url: T.string,
|
||||||
|
content: T.string,
|
||||||
|
})),
|
||||||
|
isSearching: T.boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
webBrowser: {
|
||||||
|
...baseShapeProps,
|
||||||
|
url: T.string,
|
||||||
|
history: T.arrayOf(T.string),
|
||||||
|
currentHistoryIndex: T.number,
|
||||||
|
isLoading: T.boolean,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ccBindingProps = {
|
||||||
|
'cc-slide-layout': {
|
||||||
|
isMovingWithParent: T.boolean.optional(),
|
||||||
|
placeholder: T.boolean.optional(),
|
||||||
|
index: T.string
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDefaultCCBaseProps = () => ({
|
||||||
|
title: 'Base Shape',
|
||||||
|
w: 100,
|
||||||
|
h: 100,
|
||||||
|
headerColor: '#3e6589',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
isLocked: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCCalendarProps = () => ({
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
date: new Date().toISOString(),
|
||||||
|
selectedDate: new Date().toISOString(),
|
||||||
|
view: 'timeGridWeek',
|
||||||
|
events: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCLiveTranscriptionProps = () => ({
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
isRecording: false,
|
||||||
|
segments: [],
|
||||||
|
currentSegment: undefined,
|
||||||
|
lastProcessedSegment: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCSettingsProps = () => ({
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
userEmail: '',
|
||||||
|
userRole: '',
|
||||||
|
isTeacher: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
export function getDefaultCCSlideShowProps() {
|
||||||
|
// Base 16:9 ratio dimensions
|
||||||
|
const baseWidth = 1280
|
||||||
|
const baseHeight = 720
|
||||||
|
// Add header height and spacing
|
||||||
|
const totalHeight = baseHeight +
|
||||||
|
CC_SLIDESHOW_STYLE_CONSTANTS.SLIDE_HEADER_HEIGHT + // Slideshow's own header
|
||||||
|
CC_SLIDESHOW_STYLE_CONSTANTS.SLIDE_SPACING * 2 + // Top and bottom spacing
|
||||||
|
CC_SLIDESHOW_STYLE_CONSTANTS.SLIDE_CONTENT_PADDING // Extra padding for content
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: 'Slideshow',
|
||||||
|
w: baseWidth,
|
||||||
|
h: totalHeight,
|
||||||
|
headerColor: '#3e6589',
|
||||||
|
backgroundColor: '#0f0f0f',
|
||||||
|
isLocked: false,
|
||||||
|
currentSlideIndex: 0,
|
||||||
|
slidePattern: 'horizontal',
|
||||||
|
numSlides: 3,
|
||||||
|
slides: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDefaultCCSlideProps() {
|
||||||
|
// Base 16:9 ratio dimensions
|
||||||
|
const baseWidth = 1280
|
||||||
|
const baseHeight = 720
|
||||||
|
// Add header height
|
||||||
|
const totalHeight = baseHeight + CC_BASE_STYLE_CONSTANTS.HEADER.height
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: 'Slide',
|
||||||
|
w: baseWidth,
|
||||||
|
h: totalHeight,
|
||||||
|
headerColor: '#3e6589',
|
||||||
|
backgroundColor: '#0f0f0f',
|
||||||
|
isLocked: false,
|
||||||
|
imageData: '',
|
||||||
|
meta: {
|
||||||
|
text: '',
|
||||||
|
format: 'markdown'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDefaultCCSlideLayoutBindingProps() {
|
||||||
|
return {
|
||||||
|
isMovingWithParent: false,
|
||||||
|
placeholder: false,
|
||||||
|
index: '0',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDefaultCCYoutubeEmbedProps() {
|
||||||
|
const videoHeight = 450
|
||||||
|
const totalHeight = videoHeight + CC_BASE_STYLE_CONSTANTS.HEADER.height + (CC_BASE_STYLE_CONSTANTS.CONTENT.padding * 2)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
title: 'YouTube Video',
|
||||||
|
w: 800,
|
||||||
|
h: totalHeight,
|
||||||
|
headerColor: '#ff0000',
|
||||||
|
backgroundColor: '#0f0f0f',
|
||||||
|
isLocked: false,
|
||||||
|
video_url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||||
|
transcript: [],
|
||||||
|
transcriptVisible: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDefaultCCSearchProps = () => ({
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
w: 400,
|
||||||
|
h: 500,
|
||||||
|
title: 'Search',
|
||||||
|
headerColor: '#1a73e8',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
query: '',
|
||||||
|
results: [],
|
||||||
|
isSearching: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDefaultCCWebBrowserProps = () => ({
|
||||||
|
...getDefaultCCBaseProps(),
|
||||||
|
title: 'Web Browser',
|
||||||
|
w: 800,
|
||||||
|
h: 600,
|
||||||
|
headerColor: '#1a73e8',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
url: '',
|
||||||
|
history: [],
|
||||||
|
currentHistoryIndex: -1,
|
||||||
|
isLoading: false,
|
||||||
|
})
|
||||||
118
src/utils/tldraw/cc-base/cc-styles.ts
Normal file
118
src/utils/tldraw/cc-base/cc-styles.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Style constants used by all CC shapes
|
||||||
|
export const CC_BASE_STYLE_CONSTANTS = {
|
||||||
|
FONT_FAMILY: 'Inter, sans-serif',
|
||||||
|
FONT_SIZES: {
|
||||||
|
small: 12,
|
||||||
|
medium: 14,
|
||||||
|
large: 16,
|
||||||
|
},
|
||||||
|
// Container styles
|
||||||
|
CONTAINER: {
|
||||||
|
borderRadius: '4px',
|
||||||
|
borderWidth: '2px',
|
||||||
|
borderColor: '#e2e8f0',
|
||||||
|
boxShadow: '0 2px 4px var(--color-muted-1)',
|
||||||
|
},
|
||||||
|
HEADER: {
|
||||||
|
height: 32,
|
||||||
|
padding: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
CONTENT: {
|
||||||
|
padding: 16,
|
||||||
|
borderRadius: 8,
|
||||||
|
borderWidth: 2,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
},
|
||||||
|
HANDLE: {
|
||||||
|
width: 8,
|
||||||
|
},
|
||||||
|
COLORS: {
|
||||||
|
primary: '#3e6589',
|
||||||
|
primary_dark: '#2e4a69',
|
||||||
|
secondary: '#718096',
|
||||||
|
secondary_dark: '#5a687a',
|
||||||
|
background: '#ffffff',
|
||||||
|
border: '#e2e8f0',
|
||||||
|
text: '#1a202c',
|
||||||
|
textLight: '#718096',
|
||||||
|
},
|
||||||
|
// Minimum dimensions
|
||||||
|
MIN_DIMENSIONS: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Calendar specific styles
|
||||||
|
export const CC_CALENDAR_STYLE_CONSTANTS = {
|
||||||
|
// Common button styles
|
||||||
|
COMMON_BUTTON: {
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '5px',
|
||||||
|
padding: '0.4em 1em',
|
||||||
|
fontSize: '0.95em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: '0.05em',
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'background-color 0.3s ease',
|
||||||
|
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Application button styles
|
||||||
|
APPLICATION_BUTTON: {
|
||||||
|
backgroundColor: '#4f80ff',
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Option button styles
|
||||||
|
OPTION_BUTTON: {
|
||||||
|
backgroundColor: '#f0f4f9',
|
||||||
|
color: '#2c3e50',
|
||||||
|
border: '1px solid #ddd',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Calendar event styles
|
||||||
|
EVENT: {
|
||||||
|
mainFrame: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
padding: '0px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
minHeight: '100%',
|
||||||
|
borderRadius: '4px',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: '1.1em',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
textAlign: 'center',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
opacity: 1,
|
||||||
|
padding: '0px 0px',
|
||||||
|
width: '100%',
|
||||||
|
letterSpacing: '0.02em',
|
||||||
|
margin: '0px 0px',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// Slideshow specific styles
|
||||||
|
export const CC_SLIDESHOW_STYLE_CONSTANTS = {
|
||||||
|
DEFAULT_SLIDE_WIDTH: 800,
|
||||||
|
DEFAULT_SLIDE_HEIGHT: 600,
|
||||||
|
SLIDE_HEADER_HEIGHT: 40,
|
||||||
|
SLIDE_HEADER_PADDING: 8,
|
||||||
|
SLIDE_CONTENT_PADDING: 16,
|
||||||
|
SLIDE_BORDER_RADIUS: 4,
|
||||||
|
SLIDE_BORDER_WIDTH: 1,
|
||||||
|
SLIDE_SPACING: 16,
|
||||||
|
SLIDE_COLORS: {
|
||||||
|
background: '#ffffff',
|
||||||
|
border: '#e2e8f0',
|
||||||
|
text: '#ffffff',
|
||||||
|
secondary: '#718096',
|
||||||
|
},
|
||||||
|
} as const
|
||||||
4
src/utils/tldraw/cc-base/cc-types.ts
Normal file
4
src/utils/tldraw/cc-base/cc-types.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { TLBaseShape } from 'tldraw'
|
||||||
|
import { CCBaseProps } from './cc-props'
|
||||||
|
|
||||||
|
export interface CCBaseShape extends TLBaseShape<string, CCBaseProps> {}
|
||||||
411
src/utils/tldraw/graph/baseNodeShapeUtil.tsx
Normal file
411
src/utils/tldraw/graph/baseNodeShapeUtil.tsx
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
import {
|
||||||
|
Editor,
|
||||||
|
HTMLContainer,
|
||||||
|
Rectangle2d,
|
||||||
|
ShapeUtil,
|
||||||
|
TLDefaultColorTheme,
|
||||||
|
getDefaultColorTheme,
|
||||||
|
createShapeId
|
||||||
|
} from 'tldraw'
|
||||||
|
import {
|
||||||
|
AllNodeShapes
|
||||||
|
} from './graph-shape-types'
|
||||||
|
import {
|
||||||
|
AllRelationshipShapes
|
||||||
|
} from './graph-relationship-types'
|
||||||
|
import { getNodeComponent } from './nodeComponents';
|
||||||
|
import axios from '../../../axiosConfig';
|
||||||
|
import graphState from './graphStateUtil';
|
||||||
|
|
||||||
|
export const nodeTypeConfig = {
|
||||||
|
Developer: { shapeType: 'developer_node', color: 'light-blue' },
|
||||||
|
Teacher: { shapeType: 'teacher_node', color: 'light-green' },
|
||||||
|
|
||||||
|
User: { shapeType: 'user_node', color: 'light-green' },
|
||||||
|
TeacherTimetable: { shapeType: 'teacher_timetable_node', color: 'blue' },
|
||||||
|
TimetableLesson: { shapeType: 'timetable_lesson_node', color: 'light-blue' },
|
||||||
|
PlannedLesson: { shapeType: 'planned_lesson_node', color: 'light-green' },
|
||||||
|
School: { shapeType: 'school_node', color: 'grey' },
|
||||||
|
Calendar: { shapeType: 'calendar_node', color: 'violet' },
|
||||||
|
CalendarYear: { shapeType: 'calendar_year_node', color: 'red' },
|
||||||
|
CalendarMonth: { shapeType: 'calendar_month_node', color: 'light-violet' },
|
||||||
|
CalendarWeek: { shapeType: 'calendar_week_node', color: 'light-red' },
|
||||||
|
CalendarDay: { shapeType: 'calendar_day_node', color: 'light-blue' },
|
||||||
|
CalendarTimeChunk: { shapeType: 'calendar_time_chunk_node', color: 'blue' },
|
||||||
|
ScienceLab: { shapeType: 'science_lab_node', color: 'yellow' },
|
||||||
|
KeyStageSyllabus: { shapeType: 'key_stage_syllabus_node', color: 'grey' },
|
||||||
|
YearGroupSyllabus: { shapeType: 'year_group_syllabus_node', color: 'light-blue' },
|
||||||
|
CurriculumStructure: { shapeType: 'curriculum_structure_node', color: 'grey' },
|
||||||
|
Topic: { shapeType: 'topic_node', color: 'green' },
|
||||||
|
TopicLesson: { shapeType: 'topic_lesson_node', color: 'light-green' },
|
||||||
|
LearningStatement: { shapeType: 'learning_statement_node', color: 'light-blue' },
|
||||||
|
SchoolTimetable: { shapeType: 'school_timetable_node', color: 'grey' },
|
||||||
|
AcademicYear: { shapeType: 'academic_year_node', color: 'light-violet' },
|
||||||
|
AcademicTerm: { shapeType: 'academic_term_node', color: 'yellow' },
|
||||||
|
AcademicWeek: { shapeType: 'academic_week_node', color: 'orange' },
|
||||||
|
AcademicDay: { shapeType: 'academic_day_node', color: 'light-red' },
|
||||||
|
AcademicPeriod: { shapeType: 'academic_period_node', color: 'light-green' },
|
||||||
|
RegistrationPeriod: { shapeType: 'registration_period_node', color: 'light-green' },
|
||||||
|
PastoralStructure: { shapeType: 'pastoral_structure_node', color: 'grey' },
|
||||||
|
KeyStage: { shapeType: 'key_stage_node', color: 'blue' },
|
||||||
|
Department: { shapeType: 'department_node', color: 'light-blue' },
|
||||||
|
Room: { shapeType: 'room_node', color: 'violet' },
|
||||||
|
SubjectClass: { shapeType: 'subject_class_node', color: 'light-blue' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const createNodeComponent = (shape: AllNodeShapes, theme: TLDefaultColorTheme, editor: Editor) => {
|
||||||
|
let isDragging = false;
|
||||||
|
let startX = 0;
|
||||||
|
let startY = 0;
|
||||||
|
|
||||||
|
const borderColor = theme.id === 'dark' ? 'white' : 'black'
|
||||||
|
|
||||||
|
const handlePointerDown = (e: React.PointerEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
const rect = e.currentTarget.getBoundingClientRect()
|
||||||
|
const x = e.clientX - rect.left
|
||||||
|
const y = e.clientY - rect.top
|
||||||
|
|
||||||
|
// Define button areas
|
||||||
|
const openFileButtonArea = { x: 10, y: shape.props.h - 60, width: shape.props.w - 20, height: 25 }
|
||||||
|
const getConnectedNodesButtonArea = { x: 10, y: shape.props.h - 30, width: shape.props.w - 20, height: 25 }
|
||||||
|
|
||||||
|
if (isPointInRect(x, y, openFileButtonArea)) {
|
||||||
|
console.log('Clicked on Open File button')
|
||||||
|
loadTldrawFile(shape.props.path, editor)
|
||||||
|
} else if (isPointInRect(x, y, getConnectedNodesButtonArea)) {
|
||||||
|
console.log('Clicked on Get Connected Nodes button')
|
||||||
|
handleGetConnectedNodes()
|
||||||
|
} else if (isPointInShape(x, y, shape) && !isPointInRect(x, y, openFileButtonArea) && !isPointInRect(x, y, getConnectedNodesButtonArea)) {
|
||||||
|
console.log('Clicked on shape')
|
||||||
|
isDragging = true;
|
||||||
|
startX = e.clientX - shape.x;
|
||||||
|
startY = e.clientY - shape.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePointerMove = (e: React.PointerEvent) => {
|
||||||
|
if (isDragging) {
|
||||||
|
const newX = e.clientX - startX;
|
||||||
|
const newY = e.clientY - startY;
|
||||||
|
editor.updateShape({
|
||||||
|
id: shape.id,
|
||||||
|
type: shape.type,
|
||||||
|
x: newX,
|
||||||
|
y: newY,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePointerUp = (e: React.PointerEvent) => {
|
||||||
|
isDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPointInShape = (x: number, y: number, shape: AllNodeShapes) => {
|
||||||
|
const bounds = editor.getShapeGeometry(shape).bounds
|
||||||
|
return x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPointInRect = (x: number, y: number, rect: { x: number, y: number, width: number, height: number }) => {
|
||||||
|
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height
|
||||||
|
}
|
||||||
|
|
||||||
|
let isFetchingConnectedNodes = false;
|
||||||
|
|
||||||
|
const handleGetConnectedNodes = async () => {
|
||||||
|
if (isFetchingConnectedNodes) {
|
||||||
|
console.log("WARNING! Already fetching connected nodes. Skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isFetchingConnectedNodes = true;
|
||||||
|
|
||||||
|
console.log("Getting connected nodes for:", shape.props.unique_id);
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`/api/database/tools/get-connected-nodes-and-edges?unique_id=${shape.props.unique_id}`);
|
||||||
|
console.log("Connected nodes response:", response.data);
|
||||||
|
if (response.data.status === "success") {
|
||||||
|
const mainNode = response.data.main_node;
|
||||||
|
const connectedNodes = response.data.connected_nodes;
|
||||||
|
const relationships = response.data.relationships;
|
||||||
|
|
||||||
|
// Add nodes to the graph
|
||||||
|
[mainNode, ...connectedNodes].forEach((node: any) => {
|
||||||
|
console.log("Node:", node);
|
||||||
|
const newShapeId = createShapeId(node.node_data.unique_id);
|
||||||
|
const doesShapeExist = editor.getShape(newShapeId);
|
||||||
|
if (!doesShapeExist) {
|
||||||
|
console.log("Creating new shape with ID:", newShapeId);
|
||||||
|
const nodeConfig = nodeTypeConfig[node.node_type as keyof typeof nodeTypeConfig];
|
||||||
|
if (nodeConfig) {
|
||||||
|
const newShape = {
|
||||||
|
id: newShapeId,
|
||||||
|
type: nodeConfig.shapeType,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
props: {
|
||||||
|
color: nodeConfig.color,
|
||||||
|
...node.node_data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log("New shape:", newShape);
|
||||||
|
console.log("Creating shape:", newShape);
|
||||||
|
editor.createShape(newShape);
|
||||||
|
console.log("New shape created:", newShape);
|
||||||
|
const bounds = editor.getShapeGeometry(newShapeId).bounds;
|
||||||
|
console.log("Shape bounds:", bounds);
|
||||||
|
console.log("Updating shape with width:", bounds.w, "and height:", bounds.h);
|
||||||
|
newShape.props.w = bounds.w;
|
||||||
|
newShape.props.h = bounds.h;
|
||||||
|
console.log("Adding node to graphState:", newShape);
|
||||||
|
const shapeWithWidthAndHeight = {
|
||||||
|
...newShape,
|
||||||
|
w: bounds.w,
|
||||||
|
h: bounds.h
|
||||||
|
}
|
||||||
|
graphState.addNode(shapeWithWidthAndHeight);
|
||||||
|
console.log("Node added to graphState:", newShape);
|
||||||
|
} else {
|
||||||
|
console.log("WARNING! Node type not found:", node.node_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log("Updating shapes with dagre...");
|
||||||
|
graphState.setEditor(editor);
|
||||||
|
graphState.updateShapesWithDagre();
|
||||||
|
|
||||||
|
// Add edges to the graph
|
||||||
|
relationships.forEach((relationship: any) => {
|
||||||
|
graphState.addEdge(relationship.start_node.unique_id, relationship.end_node.unique_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create edge shapes
|
||||||
|
graphState.getEdges().forEach((edge: any) => {
|
||||||
|
console.log("WARNING! Cancelling createEdgeComponent()...");
|
||||||
|
// console.log("handleGetConnectedNodes(): Creating edge component for:", edge.v, edge.w);
|
||||||
|
// createEdgeComponent(edge.v, edge.w, editor);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Done!");
|
||||||
|
} else {
|
||||||
|
console.error('Error in response:', response.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching connected nodes:', error);
|
||||||
|
} finally {
|
||||||
|
isFetchingConnectedNodes = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadTldrawFile = async (path: string, editor: any) => {
|
||||||
|
console.log("Loading tldraw_file...")
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`/api/database/tldraw_fs/get_tldraw_user_file${path}/tldraw_file.json`);
|
||||||
|
const fileContent = response.data;
|
||||||
|
|
||||||
|
console.log("File content:", fileContent);
|
||||||
|
|
||||||
|
if (fileContent && fileContent.document && fileContent.document.store) {
|
||||||
|
|
||||||
|
// Ensure the schema version is set
|
||||||
|
if (!fileContent.document.schema) {
|
||||||
|
console.log("!fileContent.document.schema")
|
||||||
|
fileContent.document.schema = { schemaVersion: 1 };
|
||||||
|
} else if (!fileContent.document.schema.schemaVersion) {
|
||||||
|
console.log("!fileContent.document.schema.schemaVersion")
|
||||||
|
fileContent.document.schema.schemaVersion = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the new content
|
||||||
|
console.log("Loading snapshot: ", fileContent)
|
||||||
|
editor.loadSnapshot(fileContent);
|
||||||
|
} else {
|
||||||
|
console.error('Invalid file content structure:', fileContent);
|
||||||
|
throw new Error('Invalid file content structure');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading tldraw file:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HTMLContainer
|
||||||
|
id={shape.id}
|
||||||
|
style={{
|
||||||
|
border: `1px solid ${borderColor}`,
|
||||||
|
borderRadius: '5px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
pointerEvents: 'all',
|
||||||
|
backgroundColor: theme[shape.props.color].semi,
|
||||||
|
color: theme[shape.props.color].solid,
|
||||||
|
boxShadow: '1px 1px 2px rgba(0, 0, 0, 0.1)',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
overflow: 'hidden',
|
||||||
|
padding: '10px',
|
||||||
|
height: shape.props.h,
|
||||||
|
}}
|
||||||
|
onPointerDown={handlePointerDown}
|
||||||
|
onPointerMove={handlePointerMove}
|
||||||
|
onPointerUp={handlePointerUp}
|
||||||
|
>
|
||||||
|
{getNodeComponent(shape, theme)}
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', marginTop: '10px' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme[shape.props.color].solid,
|
||||||
|
color: theme[shape.props.color].semi,
|
||||||
|
padding: '5px',
|
||||||
|
borderRadius: '3px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
marginBottom: '5px',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
onClick={() => loadTldrawFile(shape.props.path, editor)}
|
||||||
|
>
|
||||||
|
Open File
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme[shape.props.color].solid,
|
||||||
|
color: theme[shape.props.color].semi,
|
||||||
|
padding: '5px',
|
||||||
|
borderRadius: '3px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
onClick={handleGetConnectedNodes}
|
||||||
|
>
|
||||||
|
Get Connected Nodes
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</HTMLContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createNodeIndicator = (shape: AllNodeShapes, editor: any) => {
|
||||||
|
const bounds = editor.getShapeGeometry(shape).bounds
|
||||||
|
const theme = getDefaultColorTheme({ isDarkMode: editor.user.getIsDarkMode() })
|
||||||
|
return (
|
||||||
|
<rect
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
width={bounds.width}
|
||||||
|
height={bounds.height}
|
||||||
|
fill="none"
|
||||||
|
stroke={theme[shape.props.color].solid}
|
||||||
|
strokeWidth={2}
|
||||||
|
rx={5}
|
||||||
|
ry={5}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createEdgeComponent = (sourceId: string, targetId: string, editor: any) => {
|
||||||
|
console.log("Creating edge component for:", sourceId, targetId)
|
||||||
|
const edge = {
|
||||||
|
type: 'general_relationship',
|
||||||
|
props: {
|
||||||
|
w: 200,
|
||||||
|
h: 300,
|
||||||
|
color: 'black',
|
||||||
|
__relationshiptype__: '',
|
||||||
|
source: sourceId,
|
||||||
|
target: targetId,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
editor.createShape(edge);
|
||||||
|
graphState.addNode(edge);
|
||||||
|
};
|
||||||
|
|
||||||
|
export abstract class BaseNodeShapeUtil<T extends AllNodeShapes> extends ShapeUtil<T> {
|
||||||
|
static override type: string
|
||||||
|
|
||||||
|
static override props: any
|
||||||
|
static override migrations: any
|
||||||
|
|
||||||
|
override isAspectRatioLocked = (_shape: T) => true
|
||||||
|
override canResize = (_shape: T) => true
|
||||||
|
|
||||||
|
abstract override getDefaultProps(): T['props']
|
||||||
|
|
||||||
|
getGeometry(shape: T) {
|
||||||
|
return new Rectangle2d({
|
||||||
|
width: shape.props.w,
|
||||||
|
height: shape.props.h,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
isFilled: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
component(shape: T) {
|
||||||
|
const theme = getDefaultColorTheme({ isDarkMode: this.editor.user.getIsDarkMode() })
|
||||||
|
return createNodeComponent(shape, theme, this.editor)
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator(shape: T) {
|
||||||
|
return createNodeIndicator(shape, this.editor)
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrag = (shape: T, dx: number, dy: number) => {
|
||||||
|
return {
|
||||||
|
x: shape.x + dx,
|
||||||
|
y: shape.y + dy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BaseRelationshipShapeUtil<T extends AllRelationshipShapes> extends ShapeUtil<T> {
|
||||||
|
static override type: string
|
||||||
|
|
||||||
|
static override props: any
|
||||||
|
static override migrations: any
|
||||||
|
|
||||||
|
override isAspectRatioLocked = (_shape: T) => true
|
||||||
|
override canResize = (_shape: T) => true
|
||||||
|
|
||||||
|
abstract override getDefaultProps(): T['props']
|
||||||
|
|
||||||
|
getGeometry(shape: T) {
|
||||||
|
return new Rectangle2d({
|
||||||
|
width: shape.props.w,
|
||||||
|
height: shape.props.h,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
isFilled: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
component(shape: T) {
|
||||||
|
// Define how the edge is rendered
|
||||||
|
return (
|
||||||
|
<line
|
||||||
|
x1={shape.x}
|
||||||
|
y1={shape.y}
|
||||||
|
x2={shape.x}
|
||||||
|
y2={shape.y}
|
||||||
|
stroke={shape.props.color}
|
||||||
|
strokeWidth={2}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator(shape: T) {
|
||||||
|
// Define the indicator for the edge
|
||||||
|
return (
|
||||||
|
<line
|
||||||
|
x1={shape.x}
|
||||||
|
y1={shape.y}
|
||||||
|
x2={shape.x}
|
||||||
|
y2={shape.y}
|
||||||
|
stroke={shape.props.color}
|
||||||
|
strokeWidth={2}
|
||||||
|
strokeDasharray="4 2"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/utils/tldraw/graph/graph-relationship-migrations.ts
Normal file
23
src/utils/tldraw/graph/graph-relationship-migrations.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from 'tldraw'
|
||||||
|
|
||||||
|
// Ensure each node type and its migrations are added separately
|
||||||
|
const generalRelationshipVersions = createShapePropsMigrationIds(
|
||||||
|
'general_relationship',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const generalRelationshipShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: generalRelationshipVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
20
src/utils/tldraw/graph/graph-relationship-props.ts
Normal file
20
src/utils/tldraw/graph/graph-relationship-props.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { DefaultColorStyle, T, RecordProps } from 'tldraw'
|
||||||
|
import {
|
||||||
|
GeneralRelationshipShape
|
||||||
|
} from './graph-relationship-types'
|
||||||
|
|
||||||
|
// Base node shape props
|
||||||
|
export const baseRelationshipShapeProps = {
|
||||||
|
w: T.number,
|
||||||
|
h: T.number,
|
||||||
|
color: DefaultColorStyle,
|
||||||
|
__relationshiptype__: T.string,
|
||||||
|
source: T.string,
|
||||||
|
target: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
// General relationship shape props
|
||||||
|
export const generalRelationshipShapeProps: RecordProps<GeneralRelationshipShape> = {
|
||||||
|
...baseRelationshipShapeProps,
|
||||||
|
}
|
||||||
|
|
||||||
14
src/utils/tldraw/graph/graph-relationship-types.ts
Normal file
14
src/utils/tldraw/graph/graph-relationship-types.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { TLBaseShape, TLDefaultColorStyle } from 'tldraw'
|
||||||
|
import {
|
||||||
|
GeneralRelationshipInterface
|
||||||
|
} from '../../../types/graph_relationship_types'
|
||||||
|
|
||||||
|
export type BaseRelationshipShape<T extends string, U> = TLBaseShape<T, {
|
||||||
|
w: number
|
||||||
|
h: number
|
||||||
|
color: TLDefaultColorStyle
|
||||||
|
} & U>;
|
||||||
|
|
||||||
|
export type AllRelationshipShapes = GeneralRelationshipShape;
|
||||||
|
|
||||||
|
export type GeneralRelationshipShape = BaseRelationshipShape<"general_relationship", GeneralRelationshipInterface>;
|
||||||
749
src/utils/tldraw/graph/graph-shape-migrations.ts
Normal file
749
src/utils/tldraw/graph/graph-shape-migrations.ts
Normal file
@ -0,0 +1,749 @@
|
|||||||
|
import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from 'tldraw'
|
||||||
|
|
||||||
|
// Ensure each node type and its migrations are added separately
|
||||||
|
const userNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'user_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const developerNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'developer_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const teacherNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'teacher_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const studentNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'student_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const userNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: userNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const developerNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: developerNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const teacherNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: teacherNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const studentNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: studentNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// Calendar node shape migrations
|
||||||
|
const calendarNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const yearNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_year_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const monthNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_month_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const weekNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_week_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const dayNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_day_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const timeChunkNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'calendar_time_chunk_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const calendarNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: calendarNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const yearNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: yearNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const monthNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: monthNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const weekNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: weekNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const dayNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: dayNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const timeChunkNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: timeChunkNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const schoolNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'school_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const departmentNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'department_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const roomNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'room_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const subjectClassNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'subject_class_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const schoolNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: schoolNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const departmentNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: departmentNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const roomNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: roomNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const subjectClassNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: subjectClassNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const pastoralStructureNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'pastoral_structure_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const yearGroupNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'year_group_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const curriculumStructureNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'curriculum_structure_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyStageNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'key_stage_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyStageSyllabusNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'key_stage_syllabus_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const yearGroupSyllabusNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'year_group_syllabus_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const subjectNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'subject_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const topicNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'topic_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const topicLessonNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'topic_lesson_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const learningStatementNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'learning_statement_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const scienceLabNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'science_lab_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const pastoralStructureNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: pastoralStructureNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const yearGroupNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: yearGroupNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const curriculumStructureNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: curriculumStructureNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const keyStageNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: keyStageNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const keyStageSyllabusNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: keyStageSyllabusNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const yearGroupSyllabusNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: yearGroupSyllabusNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const subjectNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: subjectNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const topicNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: topicNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const topicLessonNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: topicLessonNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export const learningStatementNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: learningStatementNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const scienceLabNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: scienceLabNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const schoolTimetableNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'school_timetable_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const academicYearNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'academic_year_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const academicTermNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'academic_term_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const academicWeekNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'academic_week_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const academicDayNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'academic_day_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const academicPeriodNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'academic_period_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const registrationPeriodNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'registration_period_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const schoolTimetableNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: schoolTimetableNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const academicYearNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: academicYearNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const academicTermNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: academicTermNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const academicWeekNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: academicWeekNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const academicDayNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: academicDayNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const academicPeriodNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: academicPeriodNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const registrationPeriodNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: registrationPeriodNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const teacherTimetableNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'teacher_timetable_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const timetableLessonNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'timetable_lesson_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const plannedLessonNodeVersions = createShapePropsMigrationIds(
|
||||||
|
'planned_lesson_node',
|
||||||
|
{
|
||||||
|
AddSomeProperty: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const teacherTimetableNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: teacherTimetableNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const timetableLessonNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: timetableLessonNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const plannedLessonNodeShapeMigrations = createShapePropsMigrationSequence({
|
||||||
|
sequence: [
|
||||||
|
{
|
||||||
|
id: plannedLessonNodeVersions.AddSomeProperty,
|
||||||
|
up(props) {
|
||||||
|
props.someProperty = 'some value'
|
||||||
|
},
|
||||||
|
down(props) {
|
||||||
|
delete props.someProperty
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
332
src/utils/tldraw/graph/graph-shape-props.ts
Normal file
332
src/utils/tldraw/graph/graph-shape-props.ts
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
import { DefaultColorStyle, RecordProps, T } from 'tldraw'
|
||||||
|
import {
|
||||||
|
UserNodeShape,
|
||||||
|
DeveloperNodeShape,
|
||||||
|
TeacherNodeShape,
|
||||||
|
StudentNodeShape,
|
||||||
|
CalendarNodeShape,
|
||||||
|
CalendarYearNodeShape,
|
||||||
|
CalendarMonthNodeShape,
|
||||||
|
CalendarWeekNodeShape,
|
||||||
|
CalendarDayNodeShape,
|
||||||
|
CalendarTimeChunkNodeShape,
|
||||||
|
SchoolNodeShape,
|
||||||
|
DepartmentNodeShape,
|
||||||
|
RoomNodeShape,
|
||||||
|
SubjectClassNodeShape,
|
||||||
|
PastoralStructureNodeShape,
|
||||||
|
YearGroupNodeShape,
|
||||||
|
CurriculumStructureNodeShape,
|
||||||
|
KeyStageNodeShape,
|
||||||
|
KeyStageSyllabusNodeShape,
|
||||||
|
YearGroupSyllabusNodeShape,
|
||||||
|
SubjectNodeShape,
|
||||||
|
TopicNodeShape,
|
||||||
|
TopicLessonNodeShape,
|
||||||
|
LearningStatementNodeShape,
|
||||||
|
ScienceLabNodeShape,
|
||||||
|
SchoolTimetableNodeShape,
|
||||||
|
AcademicYearNodeShape,
|
||||||
|
AcademicTermNodeShape,
|
||||||
|
AcademicWeekNodeShape,
|
||||||
|
AcademicDayNodeShape,
|
||||||
|
AcademicPeriodNodeShape,
|
||||||
|
RegistrationPeriodNodeShape,
|
||||||
|
TeacherTimetableNodeShape,
|
||||||
|
TimetableLessonNodeShape,
|
||||||
|
PlannedLessonNodeShape,
|
||||||
|
} from './graph-shape-types'
|
||||||
|
|
||||||
|
// Base node shape props
|
||||||
|
const baseNodeShapeProps = {
|
||||||
|
w: T.number,
|
||||||
|
h: T.number,
|
||||||
|
color: DefaultColorStyle,
|
||||||
|
__primarylabel__: T.string,
|
||||||
|
unique_id: T.string,
|
||||||
|
path: T.string,
|
||||||
|
created: T.string,
|
||||||
|
merged: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const userNodeShapeProps: RecordProps<UserNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
user_id: T.string,
|
||||||
|
user_name: T.string,
|
||||||
|
user_email: T.string,
|
||||||
|
worker_node_data: T.string,
|
||||||
|
user_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const developerNodeShapeProps: RecordProps<DeveloperNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
user_id: T.string,
|
||||||
|
user_name: T.string,
|
||||||
|
user_email: T.string,
|
||||||
|
user_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const teacherNodeShapeProps: RecordProps<TeacherNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
teacher_code: T.string,
|
||||||
|
teacher_name_formal: T.string,
|
||||||
|
teacher_email: T.string,
|
||||||
|
worker_db_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const studentNodeShapeProps: RecordProps<StudentNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
student_code: T.string,
|
||||||
|
student_name_formal: T.string,
|
||||||
|
student_email: T.string,
|
||||||
|
worker_db_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calendar node shape props
|
||||||
|
export const calendarNodeShapeProps: RecordProps<CalendarNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
name: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calendarYearNodeShapeProps: RecordProps<CalendarYearNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
year: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calendarMonthNodeShapeProps: RecordProps<CalendarMonthNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
year: T.string,
|
||||||
|
month: T.string,
|
||||||
|
month_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calendarWeekNodeShapeProps: RecordProps<CalendarWeekNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
start_date: T.string,
|
||||||
|
week_number: T.string,
|
||||||
|
iso_week: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calendarDayNodeShapeProps: RecordProps<CalendarDayNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
date: T.string,
|
||||||
|
day_of_week: T.string,
|
||||||
|
iso_day: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calendarTimeChunkNodeShapeProps: RecordProps<CalendarTimeChunkNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// School
|
||||||
|
export const schoolNodeShapeProps: RecordProps<SchoolNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
school_name: T.string,
|
||||||
|
school_website: T.string,
|
||||||
|
school_uuid: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const departmentNodeShapeProps: RecordProps<DepartmentNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
department_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const roomNodeShapeProps: RecordProps<RoomNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
room_code: T.string,
|
||||||
|
room_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const subjectClassNodeShapeProps: RecordProps<SubjectClassNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
subject_class_code: T.string,
|
||||||
|
year_group: T.string,
|
||||||
|
subject: T.string,
|
||||||
|
subject_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Curriculum
|
||||||
|
export const pastoralStructureNodeShapeProps: RecordProps<PastoralStructureNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const yearGroupNodeShapeProps: RecordProps<YearGroupNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
year_group: T.string,
|
||||||
|
year_group_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const curriculumStructureNodeShapeProps: RecordProps<CurriculumStructureNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const keyStageNodeShapeProps: RecordProps<KeyStageNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
key_stage_name: T.string,
|
||||||
|
key_stage: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const keyStageSyllabusNodeShapeProps: RecordProps<KeyStageSyllabusNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
ks_syllabus_id: T.string,
|
||||||
|
ks_syllabus_name: T.string,
|
||||||
|
ks_syllabus_key_stage: T.string,
|
||||||
|
ks_syllabus_subject: T.string,
|
||||||
|
ks_syllabus_subject_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const yearGroupSyllabusNodeShapeProps: RecordProps<YearGroupSyllabusNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
yr_syllabus_id: T.string,
|
||||||
|
yr_syllabus_name: T.string,
|
||||||
|
yr_syllabus_year_group: T.string,
|
||||||
|
yr_syllabus_subject: T.string,
|
||||||
|
yr_syllabus_subject_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const subjectNodeShapeProps: RecordProps<SubjectNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
subject_code: T.string,
|
||||||
|
subject_name: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const topicNodeShapeProps: RecordProps<TopicNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
topic_id: T.string,
|
||||||
|
topic_title: T.string,
|
||||||
|
total_number_of_lessons_for_topic: T.string,
|
||||||
|
topic_type: T.string,
|
||||||
|
topic_assessment_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const topicLessonNodeShapeProps: RecordProps<TopicLessonNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
topic_lesson_id: T.string,
|
||||||
|
topic_lesson_title: T.string,
|
||||||
|
topic_lesson_type: T.string,
|
||||||
|
topic_lesson_length: T.string,
|
||||||
|
topic_lesson_suggested_activities: T.string,
|
||||||
|
topic_lesson_skills_learned: T.string,
|
||||||
|
topic_lesson_weblinks: T.string,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const learningStatementNodeShapeProps: RecordProps<LearningStatementNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
lesson_learning_statement_id: T.string,
|
||||||
|
lesson_learning_statement: T.string,
|
||||||
|
lesson_learning_statement_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const scienceLabNodeShapeProps: RecordProps<ScienceLabNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
science_lab_id: T.string,
|
||||||
|
science_lab_title: T.string,
|
||||||
|
science_lab_summary: T.string,
|
||||||
|
science_lab_requirements: T.string,
|
||||||
|
science_lab_procedure: T.string,
|
||||||
|
science_lab_safety: T.string,
|
||||||
|
science_lab_weblinks: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
// School Timetable
|
||||||
|
export const schoolTimetableNodeShapeProps: RecordProps<SchoolTimetableNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const academicYearNodeShapeProps: RecordProps<AcademicYearNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
year: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const academicTermNodeShapeProps: RecordProps<AcademicTermNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
term_name: T.string,
|
||||||
|
term_number: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
end_date: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const academicWeekNodeShapeProps: RecordProps<AcademicWeekNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
academic_week_number: T.string,
|
||||||
|
start_date: T.string,
|
||||||
|
week_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const academicDayNodeShapeProps: RecordProps<AcademicDayNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
academic_day: T.string,
|
||||||
|
date: T.string,
|
||||||
|
day_of_week: T.string,
|
||||||
|
day_type: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const academicPeriodNodeShapeProps: RecordProps<AcademicPeriodNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
name: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const registrationPeriodNodeShapeProps: RecordProps<RegistrationPeriodNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
name: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Teacher Timetable
|
||||||
|
export const teacherTimetableNodeShapeProps: RecordProps<TeacherTimetableNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const timetableLessonNodeShapeProps: RecordProps<TimetableLessonNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
subject_class: T.string,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const plannedLessonNodeShapeProps: RecordProps<PlannedLessonNodeShape> = {
|
||||||
|
...baseNodeShapeProps,
|
||||||
|
date: T.string,
|
||||||
|
start_time: T.string,
|
||||||
|
end_time: T.string,
|
||||||
|
period_code: T.string,
|
||||||
|
subject_class: T.string,
|
||||||
|
year_group: T.string,
|
||||||
|
subject: T.string,
|
||||||
|
teacher_code: T.string,
|
||||||
|
planning_status: T.string,
|
||||||
|
topic_code: T.string.optional().nullable(),
|
||||||
|
topic_name: T.string.optional().nullable(),
|
||||||
|
lesson_code: T.string.optional().nullable(),
|
||||||
|
lesson_name: T.string.optional().nullable(),
|
||||||
|
learning_statement_codes: T.string.optional().nullable(),
|
||||||
|
learning_statements: T.string.optional().nullable(),
|
||||||
|
learning_resource_codes: T.string.optional().nullable(),
|
||||||
|
learning_resources: T.string.optional().nullable(),
|
||||||
|
}
|
||||||
94
src/utils/tldraw/graph/graph-shape-types.ts
Normal file
94
src/utils/tldraw/graph/graph-shape-types.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { TLBaseShape, TLDefaultColorStyle } from 'tldraw'
|
||||||
|
import {
|
||||||
|
UserNodeInterface,
|
||||||
|
DeveloperNodeInterface,
|
||||||
|
TeacherNodeInterface,
|
||||||
|
StudentNodeInterface,
|
||||||
|
CalendarNodeInterface,
|
||||||
|
CalendarYearNodeInterface,
|
||||||
|
CalendarMonthNodeInterface,
|
||||||
|
CalendarWeekNodeInterface,
|
||||||
|
CalendarDayNodeInterface,
|
||||||
|
CalendarTimeChunkNodeInterface,
|
||||||
|
SchoolNodeInterface,
|
||||||
|
DepartmentNodeInterface,
|
||||||
|
RoomNodeInterface,
|
||||||
|
SubjectClassNodeInterface,
|
||||||
|
PastoralStructureNodeInterface,
|
||||||
|
YearGroupNodeInterface,
|
||||||
|
CurriculumStructureNodeInterface,
|
||||||
|
KeyStageNodeInterface,
|
||||||
|
KeyStageSyllabusNodeInterface,
|
||||||
|
YearGroupSyllabusNodeInterface,
|
||||||
|
SubjectNodeInterface,
|
||||||
|
TopicNodeInterface,
|
||||||
|
TopicLessonNodeInterface,
|
||||||
|
LearningStatementNodeInterface,
|
||||||
|
ScienceLabNodeInterface,
|
||||||
|
SchoolTimetableNodeInterface,
|
||||||
|
AcademicYearNodeInterface,
|
||||||
|
AcademicTermNodeInterface,
|
||||||
|
AcademicWeekNodeInterface,
|
||||||
|
AcademicDayNodeInterface,
|
||||||
|
AcademicPeriodNodeInterface,
|
||||||
|
RegistrationPeriodNodeInterface,
|
||||||
|
TeacherTimetableNodeInterface,
|
||||||
|
TimetableLessonNodeInterface,
|
||||||
|
PlannedLessonNodeInterface
|
||||||
|
} from '../../../types/graph_node_types';
|
||||||
|
|
||||||
|
export type BaseNodeShape<T extends string, U> = TLBaseShape<T, {
|
||||||
|
w: number
|
||||||
|
h: number
|
||||||
|
color: TLDefaultColorStyle
|
||||||
|
} & U>;
|
||||||
|
|
||||||
|
export type AllNodeShapes = UserNodeShape | DeveloperNodeShape | TeacherNodeShape | StudentNodeShape | CalendarNodeShape | CalendarYearNodeShape | CalendarMonthNodeShape | CalendarWeekNodeShape | CalendarDayNodeShape | CalendarTimeChunkNodeShape | ScienceLabNodeShape | KeyStageSyllabusNodeShape | YearGroupNodeShape | YearGroupSyllabusNodeShape | CurriculumStructureNodeShape | TopicNodeShape | TopicLessonNodeShape | LearningStatementNodeShape | SchoolNodeShape | TeacherTimetableNodeShape | TimetableLessonNodeShape | PlannedLessonNodeShape | SchoolTimetableNodeShape | SubjectClassNodeShape | SubjectNodeShape | AcademicDayNodeShape | AcademicWeekNodeShape | AcademicYearNodeShape | AcademicTermNodeShape | AcademicPeriodNodeShape | RegistrationPeriodNodeShape | PastoralStructureNodeShape | KeyStageNodeShape | RoomNodeShape | DepartmentNodeShape;
|
||||||
|
|
||||||
|
// User entity node shapes
|
||||||
|
export type UserNodeShape = BaseNodeShape<"user_node", UserNodeInterface>;
|
||||||
|
export type DeveloperNodeShape = BaseNodeShape<"developer_node", DeveloperNodeInterface>;
|
||||||
|
export type TeacherNodeShape = BaseNodeShape<"teacher_node", TeacherNodeInterface>;
|
||||||
|
export type StudentNodeShape = BaseNodeShape<"student_node", StudentNodeInterface>;
|
||||||
|
|
||||||
|
// Calendar node shapes
|
||||||
|
export type CalendarNodeShape = BaseNodeShape<"calendar_node", CalendarNodeInterface>;
|
||||||
|
export type CalendarYearNodeShape = BaseNodeShape<"calendar_year_node", CalendarYearNodeInterface>;
|
||||||
|
export type CalendarMonthNodeShape = BaseNodeShape<"calendar_month_node", CalendarMonthNodeInterface>;
|
||||||
|
export type CalendarWeekNodeShape = BaseNodeShape<"calendar_week_node", CalendarWeekNodeInterface>;
|
||||||
|
export type CalendarDayNodeShape = BaseNodeShape<"calendar_day_node", CalendarDayNodeInterface>;
|
||||||
|
export type CalendarTimeChunkNodeShape = BaseNodeShape<"calendar_time_chunk_node", CalendarTimeChunkNodeInterface>;
|
||||||
|
|
||||||
|
// School entity node shapes
|
||||||
|
export type SchoolNodeShape = BaseNodeShape<"school_node", SchoolNodeInterface>;
|
||||||
|
export type DepartmentNodeShape = BaseNodeShape<"department_node", DepartmentNodeInterface>;
|
||||||
|
export type RoomNodeShape = BaseNodeShape<"room_node", RoomNodeInterface>;
|
||||||
|
export type SubjectClassNodeShape = BaseNodeShape<"subject_class_node", SubjectClassNodeInterface>;
|
||||||
|
|
||||||
|
// Curriculum entity node shapes
|
||||||
|
export type PastoralStructureNodeShape = BaseNodeShape<"pastoral_structure_node", PastoralStructureNodeInterface>;
|
||||||
|
export type YearGroupNodeShape = BaseNodeShape<"year_group_node", YearGroupNodeInterface>;
|
||||||
|
export type CurriculumStructureNodeShape = BaseNodeShape<"curriculum_structure_node", CurriculumStructureNodeInterface>;
|
||||||
|
export type KeyStageNodeShape = BaseNodeShape<"key_stage_node", KeyStageNodeInterface>;
|
||||||
|
export type KeyStageSyllabusNodeShape = BaseNodeShape<"key_stage_syllabus_node", KeyStageSyllabusNodeInterface>;
|
||||||
|
export type YearGroupSyllabusNodeShape = BaseNodeShape<"year_group_syllabus_node", YearGroupSyllabusNodeInterface>;
|
||||||
|
export type SubjectNodeShape = BaseNodeShape<"subject_node", SubjectNodeInterface>;
|
||||||
|
export type TopicNodeShape = BaseNodeShape<"topic_node", TopicNodeInterface>;
|
||||||
|
export type TopicLessonNodeShape = BaseNodeShape<"topic_lesson_node", TopicLessonNodeInterface>;
|
||||||
|
export type LearningStatementNodeShape = BaseNodeShape<"learning_statement_node", LearningStatementNodeInterface>;
|
||||||
|
export type ScienceLabNodeShape = BaseNodeShape<"science_lab_node", ScienceLabNodeInterface>;
|
||||||
|
|
||||||
|
// School timetable entity node shapes
|
||||||
|
export type SchoolTimetableNodeShape = BaseNodeShape<"school_timetable_node", SchoolTimetableNodeInterface>;
|
||||||
|
export type AcademicYearNodeShape = BaseNodeShape<"academic_year_node", AcademicYearNodeInterface>;
|
||||||
|
export type AcademicTermNodeShape = BaseNodeShape<"academic_term_node", AcademicTermNodeInterface>;
|
||||||
|
export type AcademicWeekNodeShape = BaseNodeShape<"academic_week_node", AcademicWeekNodeInterface>;
|
||||||
|
export type AcademicDayNodeShape = BaseNodeShape<"academic_day_node", AcademicDayNodeInterface>;
|
||||||
|
export type AcademicPeriodNodeShape = BaseNodeShape<"academic_period_node", AcademicPeriodNodeInterface>;
|
||||||
|
export type RegistrationPeriodNodeShape = BaseNodeShape<"registration_period_node", RegistrationPeriodNodeInterface>;
|
||||||
|
|
||||||
|
// Teacher timetable entity node shapes
|
||||||
|
export type TeacherTimetableNodeShape = BaseNodeShape<"teacher_timetable_node", TeacherTimetableNodeInterface>;
|
||||||
|
export type TimetableLessonNodeShape = BaseNodeShape<"timetable_lesson_node", TimetableLessonNodeInterface>;
|
||||||
|
export type PlannedLessonNodeShape = BaseNodeShape<"planned_lesson_node", PlannedLessonNodeInterface>;
|
||||||
|
|
||||||
971
src/utils/tldraw/graph/graphShapeUtil.tsx
Normal file
971
src/utils/tldraw/graph/graphShapeUtil.tsx
Normal file
@ -0,0 +1,971 @@
|
|||||||
|
import { BaseNodeShapeUtil, BaseRelationshipShapeUtil } from './baseNodeShapeUtil'
|
||||||
|
import {
|
||||||
|
UserNodeShape,
|
||||||
|
DeveloperNodeShape,
|
||||||
|
TeacherNodeShape,
|
||||||
|
StudentNodeShape,
|
||||||
|
CalendarNodeShape,
|
||||||
|
CalendarYearNodeShape,
|
||||||
|
CalendarMonthNodeShape,
|
||||||
|
CalendarWeekNodeShape,
|
||||||
|
CalendarDayNodeShape,
|
||||||
|
CalendarTimeChunkNodeShape,
|
||||||
|
ScienceLabNodeShape,
|
||||||
|
KeyStageSyllabusNodeShape,
|
||||||
|
YearGroupNodeShape,
|
||||||
|
YearGroupSyllabusNodeShape,
|
||||||
|
CurriculumStructureNodeShape,
|
||||||
|
TopicNodeShape,
|
||||||
|
TopicLessonNodeShape,
|
||||||
|
LearningStatementNodeShape,
|
||||||
|
SchoolNodeShape,
|
||||||
|
TeacherTimetableNodeShape,
|
||||||
|
TimetableLessonNodeShape,
|
||||||
|
PlannedLessonNodeShape,
|
||||||
|
SchoolTimetableNodeShape,
|
||||||
|
SubjectClassNodeShape,
|
||||||
|
SubjectNodeShape,
|
||||||
|
AcademicDayNodeShape,
|
||||||
|
AcademicWeekNodeShape,
|
||||||
|
AcademicYearNodeShape,
|
||||||
|
AcademicTermNodeShape,
|
||||||
|
AcademicPeriodNodeShape,
|
||||||
|
RegistrationPeriodNodeShape,
|
||||||
|
PastoralStructureNodeShape,
|
||||||
|
KeyStageNodeShape,
|
||||||
|
RoomNodeShape,
|
||||||
|
DepartmentNodeShape,
|
||||||
|
} from './graph-shape-types'
|
||||||
|
import {
|
||||||
|
userNodeShapeProps,
|
||||||
|
developerNodeShapeProps,
|
||||||
|
teacherNodeShapeProps,
|
||||||
|
studentNodeShapeProps,
|
||||||
|
calendarNodeShapeProps,
|
||||||
|
calendarYearNodeShapeProps,
|
||||||
|
calendarMonthNodeShapeProps,
|
||||||
|
calendarWeekNodeShapeProps,
|
||||||
|
calendarDayNodeShapeProps,
|
||||||
|
calendarTimeChunkNodeShapeProps,
|
||||||
|
scienceLabNodeShapeProps,
|
||||||
|
keyStageSyllabusNodeShapeProps,
|
||||||
|
yearGroupNodeShapeProps,
|
||||||
|
yearGroupSyllabusNodeShapeProps,
|
||||||
|
curriculumStructureNodeShapeProps,
|
||||||
|
topicNodeShapeProps,
|
||||||
|
topicLessonNodeShapeProps,
|
||||||
|
learningStatementNodeShapeProps,
|
||||||
|
schoolNodeShapeProps,
|
||||||
|
teacherTimetableNodeShapeProps,
|
||||||
|
timetableLessonNodeShapeProps,
|
||||||
|
plannedLessonNodeShapeProps,
|
||||||
|
schoolTimetableNodeShapeProps,
|
||||||
|
subjectClassNodeShapeProps,
|
||||||
|
subjectNodeShapeProps,
|
||||||
|
academicDayNodeShapeProps,
|
||||||
|
academicWeekNodeShapeProps,
|
||||||
|
academicYearNodeShapeProps,
|
||||||
|
academicTermNodeShapeProps,
|
||||||
|
academicPeriodNodeShapeProps,
|
||||||
|
registrationPeriodNodeShapeProps,
|
||||||
|
pastoralStructureNodeShapeProps,
|
||||||
|
keyStageNodeShapeProps,
|
||||||
|
departmentNodeShapeProps,
|
||||||
|
roomNodeShapeProps
|
||||||
|
} from './graph-shape-props'
|
||||||
|
import {
|
||||||
|
userNodeShapeMigrations,
|
||||||
|
developerNodeShapeMigrations,
|
||||||
|
teacherNodeShapeMigrations,
|
||||||
|
studentNodeShapeMigrations,
|
||||||
|
calendarNodeShapeMigrations,
|
||||||
|
yearNodeShapeMigrations,
|
||||||
|
monthNodeShapeMigrations,
|
||||||
|
weekNodeShapeMigrations,
|
||||||
|
dayNodeShapeMigrations,
|
||||||
|
timeChunkNodeShapeMigrations,
|
||||||
|
keyStageSyllabusNodeShapeMigrations,
|
||||||
|
yearGroupNodeShapeMigrations,
|
||||||
|
yearGroupSyllabusNodeShapeMigrations,
|
||||||
|
curriculumStructureNodeShapeMigrations,
|
||||||
|
topicNodeShapeMigrations,
|
||||||
|
topicLessonNodeShapeMigrations,
|
||||||
|
learningStatementNodeShapeMigrations,
|
||||||
|
scienceLabNodeShapeMigrations,
|
||||||
|
schoolNodeShapeMigrations,
|
||||||
|
teacherTimetableNodeShapeMigrations,
|
||||||
|
timetableLessonNodeShapeMigrations,
|
||||||
|
plannedLessonNodeShapeMigrations,
|
||||||
|
schoolTimetableNodeShapeMigrations,
|
||||||
|
subjectClassNodeShapeMigrations,
|
||||||
|
subjectNodeShapeMigrations,
|
||||||
|
academicDayNodeShapeMigrations,
|
||||||
|
academicWeekNodeShapeMigrations,
|
||||||
|
academicYearNodeShapeMigrations,
|
||||||
|
academicTermNodeShapeMigrations,
|
||||||
|
academicPeriodNodeShapeMigrations,
|
||||||
|
registrationPeriodNodeShapeMigrations,
|
||||||
|
pastoralStructureNodeShapeMigrations,
|
||||||
|
roomNodeShapeMigrations,
|
||||||
|
departmentNodeShapeMigrations,
|
||||||
|
keyStageNodeShapeMigrations,
|
||||||
|
} from './graph-shape-migrations'
|
||||||
|
import { GeneralRelationshipShape } from './graph-relationship-types'
|
||||||
|
import { generalRelationshipShapeProps } from './graph-relationship-props'
|
||||||
|
import { generalRelationshipShapeMigrations } from './graph-relationship-migrations'
|
||||||
|
|
||||||
|
// User Nodes
|
||||||
|
export class UserNodeShapeUtil extends BaseNodeShapeUtil<UserNodeShape> {
|
||||||
|
static override type = 'user_node' as const
|
||||||
|
static override props = userNodeShapeProps
|
||||||
|
static override migrations = userNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): UserNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'blue',
|
||||||
|
__primarylabel__: 'User',
|
||||||
|
unique_id: '',
|
||||||
|
user_name: '',
|
||||||
|
user_email: '',
|
||||||
|
user_type: '',
|
||||||
|
user_id: '',
|
||||||
|
worker_node_data: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DeveloperNodeShapeUtil extends BaseNodeShapeUtil<DeveloperNodeShape> {
|
||||||
|
static override type = 'developer_node' as const
|
||||||
|
static override props = developerNodeShapeProps
|
||||||
|
static override migrations = developerNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): DeveloperNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Developer',
|
||||||
|
unique_id: '',
|
||||||
|
user_name: '',
|
||||||
|
user_email: '',
|
||||||
|
user_type: '',
|
||||||
|
user_id: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TeacherNodeShapeUtil extends BaseNodeShapeUtil<TeacherNodeShape> {
|
||||||
|
static override type = 'teacher_node' as const
|
||||||
|
static override props = teacherNodeShapeProps
|
||||||
|
static override migrations = teacherNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): TeacherNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Teacher',
|
||||||
|
unique_id: '',
|
||||||
|
teacher_code: '',
|
||||||
|
teacher_name_formal: '',
|
||||||
|
teacher_email: '',
|
||||||
|
worker_db_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StudentNodeShapeUtil extends BaseNodeShapeUtil<StudentNodeShape> {
|
||||||
|
static override type = 'student_node' as const
|
||||||
|
static override props = studentNodeShapeProps
|
||||||
|
static override migrations = studentNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): StudentNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Student',
|
||||||
|
unique_id: '',
|
||||||
|
student_code: '',
|
||||||
|
student_name_formal: '',
|
||||||
|
student_email: '',
|
||||||
|
worker_db_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calendar Nodes
|
||||||
|
export class CalendarNodeShapeUtil extends BaseNodeShapeUtil<CalendarNodeShape> {
|
||||||
|
static override type = 'calendar_node' as const
|
||||||
|
static override props = calendarNodeShapeProps
|
||||||
|
static override migrations = calendarNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar',
|
||||||
|
unique_id: '',
|
||||||
|
name: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CalendarYearNodeShapeUtil extends BaseNodeShapeUtil<CalendarYearNodeShape> {
|
||||||
|
static override type = 'calendar_year_node' as const
|
||||||
|
static override props = calendarYearNodeShapeProps
|
||||||
|
static override migrations = yearNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarYearNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar Year',
|
||||||
|
unique_id: '',
|
||||||
|
year: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CalendarMonthNodeShapeUtil extends BaseNodeShapeUtil<CalendarMonthNodeShape> {
|
||||||
|
static override type = 'calendar_month_node' as const
|
||||||
|
static override props = calendarMonthNodeShapeProps
|
||||||
|
static override migrations = monthNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarMonthNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar Month',
|
||||||
|
unique_id: '',
|
||||||
|
year: '',
|
||||||
|
month: '',
|
||||||
|
month_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CalendarWeekNodeShapeUtil extends BaseNodeShapeUtil<CalendarWeekNodeShape> {
|
||||||
|
static override type = 'calendar_week_node' as const
|
||||||
|
static override props = calendarWeekNodeShapeProps
|
||||||
|
static override migrations = weekNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarWeekNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar Week',
|
||||||
|
unique_id: '',
|
||||||
|
start_date: '',
|
||||||
|
week_number: '',
|
||||||
|
iso_week: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CalendarDayNodeShapeUtil extends BaseNodeShapeUtil<CalendarDayNodeShape> {
|
||||||
|
static override type = 'calendar_day_node' as const
|
||||||
|
static override props = calendarDayNodeShapeProps
|
||||||
|
static override migrations = dayNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarDayNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar Day',
|
||||||
|
unique_id: '',
|
||||||
|
date: '',
|
||||||
|
day_of_week: '',
|
||||||
|
iso_day: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CalendarTimeChunkNodeShapeUtil extends BaseNodeShapeUtil<CalendarTimeChunkNodeShape> {
|
||||||
|
static override type = 'calendar_time_chunk_node' as const
|
||||||
|
static override props = calendarTimeChunkNodeShapeProps
|
||||||
|
static override migrations = timeChunkNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CalendarTimeChunkNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Calendar Time Chunk',
|
||||||
|
unique_id: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// School Nodes
|
||||||
|
export class SubjectClassNodeShapeUtil extends BaseNodeShapeUtil<SubjectClassNodeShape> {
|
||||||
|
static override type = 'subject_class_node' as const
|
||||||
|
static override props = subjectClassNodeShapeProps
|
||||||
|
static override migrations = subjectClassNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): SubjectClassNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Subject Class',
|
||||||
|
unique_id: '',
|
||||||
|
subject_class_code: '',
|
||||||
|
year_group: '',
|
||||||
|
subject: '',
|
||||||
|
subject_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SchoolNodeShapeUtil extends BaseNodeShapeUtil<SchoolNodeShape> {
|
||||||
|
static override type = 'school_node' as const
|
||||||
|
static override props = schoolNodeShapeProps
|
||||||
|
static override migrations = schoolNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): SchoolNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'School',
|
||||||
|
unique_id: '',
|
||||||
|
school_uuid: '',
|
||||||
|
school_name: '',
|
||||||
|
school_website: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DepartmentNodeShapeUtil extends BaseNodeShapeUtil<DepartmentNodeShape> {
|
||||||
|
static override type = 'department_node' as const
|
||||||
|
static override props = departmentNodeShapeProps
|
||||||
|
static override migrations = departmentNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): DepartmentNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Department',
|
||||||
|
unique_id: '',
|
||||||
|
department_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RoomNodeShapeUtil extends BaseNodeShapeUtil<RoomNodeShape> {
|
||||||
|
static override type = 'room_node' as const
|
||||||
|
static override props = roomNodeShapeProps
|
||||||
|
static override migrations = roomNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): RoomNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Room',
|
||||||
|
unique_id: '',
|
||||||
|
room_name: '',
|
||||||
|
room_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Curriculum Nodes
|
||||||
|
export class PastoralStructureNodeShapeUtil extends BaseNodeShapeUtil<PastoralStructureNodeShape> {
|
||||||
|
static override type = 'pastoral_structure_node' as const
|
||||||
|
static override props = pastoralStructureNodeShapeProps
|
||||||
|
static override migrations = pastoralStructureNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): PastoralStructureNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 130,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Pastoral Structure',
|
||||||
|
unique_id: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class YearGroupNodeShapeUtil extends BaseNodeShapeUtil<YearGroupNodeShape> {
|
||||||
|
static override type = 'year_group_node' as const
|
||||||
|
static override props = yearGroupNodeShapeProps
|
||||||
|
static override migrations = yearGroupNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): YearGroupNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 150,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Year Group',
|
||||||
|
unique_id: '',
|
||||||
|
year_group: '',
|
||||||
|
year_group_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CurriculumStructureNodeShapeUtil extends BaseNodeShapeUtil<CurriculumStructureNodeShape> {
|
||||||
|
static override type = 'curriculum_structure_node' as const
|
||||||
|
static override props = curriculumStructureNodeShapeProps
|
||||||
|
static override migrations = curriculumStructureNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): CurriculumStructureNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 130,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Curriculum Structure',
|
||||||
|
unique_id: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyStageNodeShapeUtil extends BaseNodeShapeUtil<KeyStageNodeShape> {
|
||||||
|
static override type = 'key_stage_node' as const
|
||||||
|
static override props = keyStageNodeShapeProps
|
||||||
|
static override migrations = keyStageNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): KeyStageNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 150,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Key Stage',
|
||||||
|
unique_id: '',
|
||||||
|
key_stage_name: '',
|
||||||
|
key_stage: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyStageSyllabusNodeShapeUtil extends BaseNodeShapeUtil<KeyStageSyllabusNodeShape> {
|
||||||
|
static override type = 'key_stage_syllabus_node' as const
|
||||||
|
static override props = keyStageSyllabusNodeShapeProps
|
||||||
|
static override migrations = keyStageSyllabusNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): KeyStageSyllabusNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Key Stage Syllabus',
|
||||||
|
unique_id: '',
|
||||||
|
ks_syllabus_id: '',
|
||||||
|
ks_syllabus_name: '',
|
||||||
|
ks_syllabus_key_stage: '',
|
||||||
|
ks_syllabus_subject: '',
|
||||||
|
ks_syllabus_subject_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class YearGroupSyllabusNodeShapeUtil extends BaseNodeShapeUtil<YearGroupSyllabusNodeShape> {
|
||||||
|
static override type = 'year_group_syllabus_node' as const
|
||||||
|
static override props = yearGroupSyllabusNodeShapeProps
|
||||||
|
static override migrations = yearGroupSyllabusNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): YearGroupSyllabusNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Year Group Syllabus',
|
||||||
|
unique_id: '',
|
||||||
|
yr_syllabus_id: '',
|
||||||
|
yr_syllabus_name: '',
|
||||||
|
yr_syllabus_year_group: '',
|
||||||
|
yr_syllabus_subject: '',
|
||||||
|
yr_syllabus_subject_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SubjectNodeShapeUtil extends BaseNodeShapeUtil<SubjectNodeShape> {
|
||||||
|
static override type = 'subject_node' as const
|
||||||
|
static override props = subjectNodeShapeProps
|
||||||
|
static override migrations = subjectNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): SubjectNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Subject',
|
||||||
|
unique_id: '',
|
||||||
|
subject_code: '',
|
||||||
|
subject_name: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TopicNodeShapeUtil extends BaseNodeShapeUtil<TopicNodeShape> {
|
||||||
|
static override type = 'topic_node' as const
|
||||||
|
static override props = topicNodeShapeProps
|
||||||
|
static override migrations = topicNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): TopicNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 300,
|
||||||
|
h: 400,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Topic',
|
||||||
|
unique_id: '',
|
||||||
|
topic_id: '',
|
||||||
|
topic_title: '',
|
||||||
|
total_number_of_lessons_for_topic: '',
|
||||||
|
topic_type: '',
|
||||||
|
topic_assessment_type: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TopicLessonNodeShapeUtil extends BaseNodeShapeUtil<TopicLessonNodeShape> {
|
||||||
|
static override type = 'topic_lesson_node' as const
|
||||||
|
static override props = topicLessonNodeShapeProps
|
||||||
|
static override migrations = topicLessonNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): TopicLessonNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 300,
|
||||||
|
h: 500,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Topic Lesson',
|
||||||
|
unique_id: '',
|
||||||
|
topic_lesson_id: '',
|
||||||
|
topic_lesson_title: '',
|
||||||
|
topic_lesson_type: '',
|
||||||
|
topic_lesson_length: '',
|
||||||
|
topic_lesson_skills_learned: '',
|
||||||
|
topic_lesson_suggested_activities: '',
|
||||||
|
topic_lesson_weblinks: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LearningStatementNodeShapeUtil extends BaseNodeShapeUtil<LearningStatementNodeShape> {
|
||||||
|
static override type = 'learning_statement_node' as const
|
||||||
|
static override props = learningStatementNodeShapeProps
|
||||||
|
static override migrations = learningStatementNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): LearningStatementNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 180,
|
||||||
|
h: 300,
|
||||||
|
color: 'light-blue',
|
||||||
|
__primarylabel__: 'Learning Statement',
|
||||||
|
unique_id: '',
|
||||||
|
lesson_learning_statement_id: '',
|
||||||
|
lesson_learning_statement: '',
|
||||||
|
lesson_learning_statement_type: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScienceLabNodeShapeUtil extends BaseNodeShapeUtil<ScienceLabNodeShape> {
|
||||||
|
static override type = 'science_lab_node' as const
|
||||||
|
static override props = scienceLabNodeShapeProps
|
||||||
|
static override migrations = scienceLabNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): ScienceLabNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 300,
|
||||||
|
h: 400,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Science Lab',
|
||||||
|
unique_id: '',
|
||||||
|
science_lab_id: '',
|
||||||
|
science_lab_title: '',
|
||||||
|
science_lab_summary: '',
|
||||||
|
science_lab_requirements: '',
|
||||||
|
science_lab_procedure: '',
|
||||||
|
science_lab_safety: '',
|
||||||
|
science_lab_weblinks: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// School Timetable Nodes
|
||||||
|
export class SchoolTimetableNodeShapeUtil extends BaseNodeShapeUtil<SchoolTimetableNodeShape> {
|
||||||
|
static override type = 'school_timetable_node' as const
|
||||||
|
|
||||||
|
static override props = schoolTimetableNodeShapeProps
|
||||||
|
static override migrations = schoolTimetableNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): SchoolTimetableNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'School Timetable',
|
||||||
|
unique_id: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AcademicYearNodeShapeUtil extends BaseNodeShapeUtil<AcademicYearNodeShape> {
|
||||||
|
static override type = 'academic_year_node' as const
|
||||||
|
static override props = academicYearNodeShapeProps
|
||||||
|
static override migrations = academicYearNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): AcademicYearNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Academic Year',
|
||||||
|
unique_id: '',
|
||||||
|
year: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AcademicTermNodeShapeUtil extends BaseNodeShapeUtil<AcademicTermNodeShape> {
|
||||||
|
static override type = 'academic_term_node' as const
|
||||||
|
static override props = academicTermNodeShapeProps
|
||||||
|
static override migrations = academicTermNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): AcademicTermNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 300,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Academic Term',
|
||||||
|
unique_id: '',
|
||||||
|
term_name: '',
|
||||||
|
term_number: '',
|
||||||
|
start_date: '',
|
||||||
|
end_date: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AcademicWeekNodeShapeUtil extends BaseNodeShapeUtil<AcademicWeekNodeShape> {
|
||||||
|
static override type = 'academic_week_node' as const
|
||||||
|
static override props = academicWeekNodeShapeProps
|
||||||
|
static override migrations = academicWeekNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): AcademicWeekNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 300,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Academic Week',
|
||||||
|
unique_id: '',
|
||||||
|
start_date: '',
|
||||||
|
week_type: '',
|
||||||
|
academic_week_number: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AcademicDayNodeShapeUtil extends BaseNodeShapeUtil<AcademicDayNodeShape> {
|
||||||
|
static override type = 'academic_day_node' as const
|
||||||
|
static override props = academicDayNodeShapeProps
|
||||||
|
static override migrations = academicDayNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): AcademicDayNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Academic Day',
|
||||||
|
unique_id: '',
|
||||||
|
academic_day: '',
|
||||||
|
date: '',
|
||||||
|
day_of_week: '',
|
||||||
|
day_type: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AcademicPeriodNodeShapeUtil extends BaseNodeShapeUtil<AcademicPeriodNodeShape> {
|
||||||
|
static override type = 'academic_period_node' as const
|
||||||
|
static override props = academicPeriodNodeShapeProps
|
||||||
|
static override migrations = academicPeriodNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): AcademicPeriodNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 300,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Academic Period',
|
||||||
|
unique_id: '',
|
||||||
|
name: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RegistrationPeriodNodeShapeUtil extends BaseNodeShapeUtil<RegistrationPeriodNodeShape> {
|
||||||
|
static override type = 'registration_period_node' as const
|
||||||
|
static override props = registrationPeriodNodeShapeProps
|
||||||
|
static override migrations = registrationPeriodNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): RegistrationPeriodNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 200,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Registration Period',
|
||||||
|
unique_id: '',
|
||||||
|
name: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teacher Timetable Nodes
|
||||||
|
export class TeacherTimetableNodeShapeUtil extends BaseNodeShapeUtil<TeacherTimetableNodeShape> {
|
||||||
|
static override type = 'teacher_timetable_node' as const
|
||||||
|
static override props = teacherTimetableNodeShapeProps
|
||||||
|
static override migrations = teacherTimetableNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): TeacherTimetableNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 130,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Teacher Timetable',
|
||||||
|
unique_id: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TimetableLessonNodeShapeUtil extends BaseNodeShapeUtil<TimetableLessonNodeShape> {
|
||||||
|
static override type = 'timetable_lesson_node' as const
|
||||||
|
static override props = timetableLessonNodeShapeProps
|
||||||
|
static override migrations = timetableLessonNodeShapeMigrations
|
||||||
|
|
||||||
|
override isAspectRatioLocked = (_shape: TimetableLessonNodeShape) => true
|
||||||
|
override canResize = (_shape: TimetableLessonNodeShape) => true
|
||||||
|
|
||||||
|
getDefaultProps(): TimetableLessonNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 250,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Timetable Lesson',
|
||||||
|
unique_id: '',
|
||||||
|
subject_class: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PlannedLessonNodeShapeUtil extends BaseNodeShapeUtil<PlannedLessonNodeShape> {
|
||||||
|
static override type = 'planned_lesson_node' as const
|
||||||
|
static override props = plannedLessonNodeShapeProps
|
||||||
|
static override migrations = plannedLessonNodeShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): PlannedLessonNodeShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 250,
|
||||||
|
color: 'white',
|
||||||
|
__primarylabel__: 'Planned Lesson',
|
||||||
|
unique_id: '',
|
||||||
|
date: '',
|
||||||
|
start_time: '',
|
||||||
|
end_time: '',
|
||||||
|
period_code: '',
|
||||||
|
subject_class: '',
|
||||||
|
year_group: '',
|
||||||
|
subject: '',
|
||||||
|
teacher_code: '',
|
||||||
|
planning_status: '',
|
||||||
|
topic_code: '',
|
||||||
|
topic_name: '',
|
||||||
|
lesson_code: '',
|
||||||
|
lesson_name: '',
|
||||||
|
learning_statement_codes: '',
|
||||||
|
learning_statements: '',
|
||||||
|
learning_resource_codes: '',
|
||||||
|
learning_resources: '',
|
||||||
|
path: '',
|
||||||
|
created: '',
|
||||||
|
merged: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relationships
|
||||||
|
export class GeneralRelationshipShapeUtil extends BaseRelationshipShapeUtil<GeneralRelationshipShape> {
|
||||||
|
static override type = 'general_relationship' as const
|
||||||
|
static override props = generalRelationshipShapeProps
|
||||||
|
static override migrations = generalRelationshipShapeMigrations
|
||||||
|
|
||||||
|
getDefaultProps(): GeneralRelationshipShape['props'] {
|
||||||
|
return {
|
||||||
|
w: 200,
|
||||||
|
h: 250,
|
||||||
|
color: 'black',
|
||||||
|
__relationshiptype__: '',
|
||||||
|
source: '',
|
||||||
|
target: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const allShapeUtils = [
|
||||||
|
DeveloperNodeShapeUtil,
|
||||||
|
TeacherNodeShapeUtil,
|
||||||
|
StudentNodeShapeUtil,
|
||||||
|
UserNodeShapeUtil,
|
||||||
|
TeacherTimetableNodeShapeUtil,
|
||||||
|
TimetableLessonNodeShapeUtil,
|
||||||
|
PlannedLessonNodeShapeUtil,
|
||||||
|
SchoolNodeShapeUtil,
|
||||||
|
CalendarNodeShapeUtil,
|
||||||
|
CalendarYearNodeShapeUtil,
|
||||||
|
CalendarMonthNodeShapeUtil,
|
||||||
|
CalendarWeekNodeShapeUtil,
|
||||||
|
CalendarDayNodeShapeUtil,
|
||||||
|
CalendarTimeChunkNodeShapeUtil,
|
||||||
|
ScienceLabNodeShapeUtil,
|
||||||
|
KeyStageSyllabusNodeShapeUtil,
|
||||||
|
YearGroupSyllabusNodeShapeUtil,
|
||||||
|
CurriculumStructureNodeShapeUtil,
|
||||||
|
TopicNodeShapeUtil,
|
||||||
|
TopicLessonNodeShapeUtil,
|
||||||
|
LearningStatementNodeShapeUtil,
|
||||||
|
SchoolTimetableNodeShapeUtil,
|
||||||
|
AcademicYearNodeShapeUtil,
|
||||||
|
AcademicTermNodeShapeUtil,
|
||||||
|
AcademicWeekNodeShapeUtil,
|
||||||
|
AcademicDayNodeShapeUtil,
|
||||||
|
AcademicPeriodNodeShapeUtil,
|
||||||
|
RegistrationPeriodNodeShapeUtil,
|
||||||
|
DepartmentNodeShapeUtil,
|
||||||
|
RoomNodeShapeUtil,
|
||||||
|
PastoralStructureNodeShapeUtil,
|
||||||
|
YearGroupNodeShapeUtil,
|
||||||
|
KeyStageNodeShapeUtil
|
||||||
|
];
|
||||||
102
src/utils/tldraw/graph/graphStateUtil.tsx
Normal file
102
src/utils/tldraw/graph/graphStateUtil.tsx
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import dagre from '@dagrejs/dagre';
|
||||||
|
import { createShapeId, Editor } from 'tldraw';
|
||||||
|
|
||||||
|
const graphState = {
|
||||||
|
g: new dagre.graphlib.Graph(),
|
||||||
|
nodeData: new Map<string, any>(),
|
||||||
|
editor: null as Editor | null,
|
||||||
|
|
||||||
|
initGraph: () => {
|
||||||
|
graphState.g.setGraph({});
|
||||||
|
graphState.g.setDefaultEdgeLabel(() => ({}));
|
||||||
|
},
|
||||||
|
|
||||||
|
updateNodesWithDagre: () => {
|
||||||
|
dagre.layout(graphState.g);
|
||||||
|
// Update positions in nodeData after layout
|
||||||
|
graphState.g.nodes().forEach((id) => {
|
||||||
|
const node = graphState.g.node(id);
|
||||||
|
if (graphState.nodeData.has(id)) {
|
||||||
|
const fullNode = graphState.nodeData.get(id);
|
||||||
|
fullNode.x = node.x;
|
||||||
|
fullNode.y = node.y;
|
||||||
|
graphState.nodeData.set(id, fullNode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateShapesWithDagre: () => {
|
||||||
|
console.log("Updating shapes with dagre...");
|
||||||
|
if (!graphState.editor) {
|
||||||
|
console.error("Editor is not set. Call setEditor before updating shapes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Updating nodes with dagre...");
|
||||||
|
graphState.updateNodesWithDagre();
|
||||||
|
console.log("Nodes updated with dagre...");
|
||||||
|
|
||||||
|
console.log("Updating set of shapes with dagre...");
|
||||||
|
graphState.nodeData.forEach((shape, id) => {
|
||||||
|
console.log("Updating shape with dagre:", shape, id);
|
||||||
|
const node = graphState.g.node(id);
|
||||||
|
console.log("Node without w and h:", node);
|
||||||
|
const nodeWithWidthAndHeight = {
|
||||||
|
...node,
|
||||||
|
width: shape.w,
|
||||||
|
height: shape.h
|
||||||
|
}
|
||||||
|
console.log("Node with w and h:", nodeWithWidthAndHeight);
|
||||||
|
|
||||||
|
if (nodeWithWidthAndHeight) {
|
||||||
|
console.log("Updating shape:", shape);
|
||||||
|
|
||||||
|
graphState.editor!.updateShape({
|
||||||
|
id: createShapeId(node.label),
|
||||||
|
type: shape.type,
|
||||||
|
x: nodeWithWidthAndHeight.x - nodeWithWidthAndHeight.width / 2,
|
||||||
|
y: nodeWithWidthAndHeight.y - nodeWithWidthAndHeight.height / 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
addNode: (shape: any) => {
|
||||||
|
console.log("Adding shape to graphState:", shape);
|
||||||
|
const id = shape.props.unique_id;
|
||||||
|
console.log("Adding node to graphState:", id);
|
||||||
|
graphState.g.setNode(id, {
|
||||||
|
label: id,
|
||||||
|
width: shape.props.w,
|
||||||
|
height: shape.props.h
|
||||||
|
});
|
||||||
|
graphState.nodeData.set(id, shape);
|
||||||
|
},
|
||||||
|
|
||||||
|
addEdge: (source: string, target: string) => {
|
||||||
|
graphState.g.setEdge(source, target);
|
||||||
|
},
|
||||||
|
|
||||||
|
getNode: (id: string) => {
|
||||||
|
return graphState.nodeData.get(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllNodes: () => {
|
||||||
|
return Array.from(graphState.nodeData.values()).filter(item => {
|
||||||
|
// Check if the item has a type property and it's not an edge type
|
||||||
|
return item.type && !item.type.includes('relationship');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getEdges: () => {
|
||||||
|
return graphState.g.edges();
|
||||||
|
},
|
||||||
|
|
||||||
|
setEditor: (editor: Editor) => {
|
||||||
|
graphState.editor = editor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
graphState.initGraph();
|
||||||
|
|
||||||
|
export default graphState;
|
||||||
689
src/utils/tldraw/graph/nodeComponents.tsx
Normal file
689
src/utils/tldraw/graph/nodeComponents.tsx
Normal file
@ -0,0 +1,689 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { AllNodeShapes } from './graph-shape-types';
|
||||||
|
|
||||||
|
interface NodeComponentProps<T extends AllNodeShapes = AllNodeShapes> {
|
||||||
|
shape: T;
|
||||||
|
theme: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BaseNodeProps {
|
||||||
|
__primarylabel__: string;
|
||||||
|
unique_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TeacherNodeProps extends BaseNodeProps {
|
||||||
|
teacher_name_formal: string;
|
||||||
|
teacher_code: string;
|
||||||
|
teacher_email: string;
|
||||||
|
worker_db_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StudentNodeProps extends BaseNodeProps {
|
||||||
|
student_name_formal: string;
|
||||||
|
student_code: string;
|
||||||
|
student_email: string;
|
||||||
|
worker_db_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserNodeProps extends BaseNodeProps {
|
||||||
|
user_name: string;
|
||||||
|
user_email: string;
|
||||||
|
user_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarNodeProps extends BaseNodeProps {
|
||||||
|
name: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarNodeProps extends BaseNodeProps {
|
||||||
|
name: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarYearNodeProps extends BaseNodeProps {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarMonthNodeProps extends BaseNodeProps {
|
||||||
|
month_name: string;
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarWeekNodeProps extends BaseNodeProps {
|
||||||
|
start_date: string;
|
||||||
|
iso_week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarDayNodeProps extends BaseNodeProps {
|
||||||
|
day_of_week: string;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarTimeChunkNodeProps extends BaseNodeProps {
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarTimeChunkNodeProps extends BaseNodeProps {
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SchoolNodeProps extends BaseNodeProps {
|
||||||
|
school_name: string;
|
||||||
|
school_website: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DepartmentNodeProps extends BaseNodeProps {
|
||||||
|
department_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoomNodeProps extends BaseNodeProps {
|
||||||
|
room_name: string;
|
||||||
|
room_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubjectClassNodeProps extends BaseNodeProps {
|
||||||
|
subject_class_code: string;
|
||||||
|
year_group: string;
|
||||||
|
subject: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PastoralStructureNodeProps extends BaseNodeProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface YearGroupNodeProps extends BaseNodeProps {
|
||||||
|
year_group: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CurriculumStructureNodeProps extends BaseNodeProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeyStageNodeProps extends BaseNodeProps {
|
||||||
|
key_stage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeyStageSyllabusNodeProps extends BaseNodeProps {
|
||||||
|
ks_syllabus_id: string;
|
||||||
|
ks_syllabus_subject: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface YearGroupSyllabusNodeProps extends BaseNodeProps {
|
||||||
|
yr_syllabus_id: string;
|
||||||
|
yr_syllabus_subject: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubjectNodeProps extends BaseNodeProps {
|
||||||
|
subject_name: string;
|
||||||
|
subject_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TopicNodeProps extends BaseNodeProps {
|
||||||
|
topic_title: string;
|
||||||
|
topic_id: string;
|
||||||
|
total_number_of_lessons_for_topic: string;
|
||||||
|
topic_type: string;
|
||||||
|
topic_assessment_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TopicLessonNodeProps extends BaseNodeProps {
|
||||||
|
topic_lesson_title: string;
|
||||||
|
topic_lesson_id: string;
|
||||||
|
topic_lesson_type: string;
|
||||||
|
topic_lesson_length: string;
|
||||||
|
topic_lesson_suggested_activities: string;
|
||||||
|
topic_lesson_skills_learned: string;
|
||||||
|
topic_lesson_weblinks: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LearningStatementNodeProps extends BaseNodeProps {
|
||||||
|
lesson_learning_statement: string;
|
||||||
|
lesson_learning_statement_id: string;
|
||||||
|
lesson_learning_statement_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScienceLabNodeProps extends BaseNodeProps {
|
||||||
|
science_lab_title: string;
|
||||||
|
science_lab_id: string;
|
||||||
|
science_lab_summary: string;
|
||||||
|
science_lab_requirements: string;
|
||||||
|
science_lab_procedure: string;
|
||||||
|
science_lab_safety: string;
|
||||||
|
science_lab_weblinks: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SchoolTimetableNodeProps extends BaseNodeProps {
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcademicYearNodeProps extends BaseNodeProps {
|
||||||
|
year: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcademicTermNodeProps extends BaseNodeProps {
|
||||||
|
term_name: string;
|
||||||
|
term_number: string;
|
||||||
|
start_date: string;
|
||||||
|
end_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcademicWeekNodeProps extends BaseNodeProps {
|
||||||
|
start_date: string;
|
||||||
|
week_type: string;
|
||||||
|
academic_week_number: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcademicDayNodeProps extends BaseNodeProps {
|
||||||
|
day_of_week: string;
|
||||||
|
day_type: string;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcademicPeriodNodeProps extends BaseNodeProps {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegistrationPeriodNodeProps extends BaseNodeProps {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TeacherTimetableNodeProps extends BaseNodeProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimetableLessonNodeProps extends BaseNodeProps {
|
||||||
|
subject_class: string;
|
||||||
|
date: string;
|
||||||
|
period_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlannedLessonNodeProps extends BaseNodeProps {
|
||||||
|
subject_class: string;
|
||||||
|
date: string;
|
||||||
|
period_code: string;
|
||||||
|
planning_status: string;
|
||||||
|
teacher_code: string;
|
||||||
|
year_group: string;
|
||||||
|
subject: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => (
|
||||||
|
<>
|
||||||
|
<div className="w-full flex justify-center" style={{ marginBottom: '5px' }}>
|
||||||
|
<div
|
||||||
|
className="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center"
|
||||||
|
style={{ color: 'white', fontWeight: 'bold' }}
|
||||||
|
>
|
||||||
|
{(shape.props.__primarylabel__).toUpperCase()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Users
|
||||||
|
const UserNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as UserNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>User Name: {props.user_name}</div>
|
||||||
|
<div>User Email: {props.user_email}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DeveloperNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as UserNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>User Name: {props.user_name}</div>
|
||||||
|
<div>Use Email: {props.user_email}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TeacherNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as TeacherNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Teacher Name: {props.teacher_name_formal}</div>
|
||||||
|
<div>Teacher Code: {props.teacher_code}</div>
|
||||||
|
<div>Email: {props.teacher_email}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const StudentNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as StudentNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Student Name: {props.student_name_formal}</div>
|
||||||
|
<div>Student Code: {props.student_code}</div>
|
||||||
|
<div>Email: {props.student_email}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
const CalendarNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Calendar Name: {props.name}</div>
|
||||||
|
<div>Start Date: {props.start_date}</div>
|
||||||
|
<div>End Date: {props.end_date}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalendarYearNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarYearNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Year: {props.year}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalendarMonthNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarMonthNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Month: {props.month_name}</div>
|
||||||
|
<div>Year: {props.year}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalendarWeekNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarWeekNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Week Start Date: {props.start_date}</div>
|
||||||
|
<div>ISO Week: {props.iso_week}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalendarDayNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarDayNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Day of Week: {props.day_of_week}</div>
|
||||||
|
<div>Date: {props.date}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalendarTimeChunkNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CalendarTimeChunkNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Start Time: {props.start_time}</div>
|
||||||
|
<div>End Time: {props.end_time}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schools
|
||||||
|
const SchoolNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as SchoolNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>School Name: {props.school_name}</div>
|
||||||
|
<div>School Website: {props.school_website}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DepartmentNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as DepartmentNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Department Name: {props.department_name}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RoomNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as RoomNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Room Name: {props.room_name}</div>
|
||||||
|
<div>Room Code: {props.room_code}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubjectClassNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as SubjectClassNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Subject Class: {props.subject_class_code}</div>
|
||||||
|
<div>Year Group: {props.year_group}</div>
|
||||||
|
<div>Subject: {props.subject}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Curriculum
|
||||||
|
const PastoralStructureNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as PastoralStructureNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const YearGroupNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as YearGroupNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Year Group: {props.year_group}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CurriculumStructureNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as CurriculumStructureNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeyStageNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as KeyStageNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Key Stage: {props.key_stage}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeyStageSyllabusNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as KeyStageSyllabusNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Syllabus ID: {props.ks_syllabus_id}</div>
|
||||||
|
<div>Subject: {props.ks_syllabus_subject}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const YearGroupSyllabusNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as YearGroupSyllabusNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Syllabus ID: {props.yr_syllabus_id}</div>
|
||||||
|
<div>Subject: {props.yr_syllabus_subject}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubjectNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as SubjectNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Subject: {props.subject_name}</div>
|
||||||
|
<div>Code: {props.subject_code}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TopicNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as TopicNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Title: {props.topic_title}</div>
|
||||||
|
<div>ID: {props.topic_id}</div>
|
||||||
|
<div>Lessons: {props.total_number_of_lessons_for_topic}</div>
|
||||||
|
<div>Type: {props.topic_type}</div>
|
||||||
|
<div>Assessment Type: {props.topic_assessment_type}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TopicLessonNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as TopicLessonNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Title: {props.topic_lesson_title}</div>
|
||||||
|
<div>ID: {props.topic_lesson_id}</div>
|
||||||
|
<div>Type: {props.topic_lesson_type}</div>
|
||||||
|
<div>Length: {props.topic_lesson_length}</div>
|
||||||
|
<div>Suggested Activities: {props.topic_lesson_suggested_activities}</div>
|
||||||
|
<div>Skills Learned: {props.topic_lesson_skills_learned}</div>
|
||||||
|
<div>Web Links: {props.topic_lesson_weblinks}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const LearningStatementNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as LearningStatementNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Learning Statement: {props.lesson_learning_statement}</div>
|
||||||
|
<div>ID: {props.lesson_learning_statement_id}</div>
|
||||||
|
<div>Type: {props.lesson_learning_statement_type}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const ScienceLabNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as ScienceLabNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Title: {props.science_lab_title}</div>
|
||||||
|
<div>ID: {props.science_lab_id}</div>
|
||||||
|
<div>Summary: {props.science_lab_summary}</div>
|
||||||
|
<div>Requirements: {props.science_lab_requirements}</div>
|
||||||
|
<div>Procedure: {props.science_lab_procedure}</div>
|
||||||
|
<div>Safety: {props.science_lab_safety}</div>
|
||||||
|
<div>Web Links: {props.science_lab_weblinks}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// School Timetable
|
||||||
|
const SchoolTimetableNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as SchoolTimetableNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Start Date: {props.start_date}</div>
|
||||||
|
<div>End Date: {props.end_date}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AcademicYearNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as AcademicYearNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Year: {props.year}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AcademicTermNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as AcademicTermNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Term Name: {props.term_name}</div>
|
||||||
|
<div>Term Number: {props.term_number}</div>
|
||||||
|
<div>Start Date: {props.start_date}</div>
|
||||||
|
<div>End Date: {props.end_date}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AcademicWeekNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as AcademicWeekNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Start Date: {props.start_date}</div>
|
||||||
|
<div>Week Type: {props.week_type}</div>
|
||||||
|
<div>Academic Week Number: {props.academic_week_number}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AcademicDayNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as AcademicDayNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Day of Week: {props.day_of_week}</div>
|
||||||
|
<div>Day Type: {props.day_type}</div>
|
||||||
|
<div>Date: {props.date}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AcademicPeriodNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as AcademicPeriodNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Name: {props.name}</div>
|
||||||
|
<div>Date: {props.date}</div>
|
||||||
|
<div>Start Time: {props.start_time}</div>
|
||||||
|
<div>End Time: {props.end_time}</div>
|
||||||
|
<div>Period Code: {props.period_code}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const RegistrationPeriodNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as RegistrationPeriodNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Name: {props.name}</div>
|
||||||
|
<div>Date: {props.date}</div>
|
||||||
|
<div>Start Time: {props.start_time}</div>
|
||||||
|
<div>End Time: {props.end_time}</div>
|
||||||
|
<div>Period Code: {props.period_code}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Teacher Timetable
|
||||||
|
const TeacherTimetableNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as TeacherTimetableNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TimetableLessonNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as TimetableLessonNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Subject Class: {props.subject_class}</div>
|
||||||
|
<div>Date: {props.date}</div>
|
||||||
|
<div>Period Code: {props.period_code}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlannedLessonNodeComponent: React.FC<NodeComponentProps> = ({ shape, theme }) => {
|
||||||
|
const props = shape.props as PlannedLessonNodeProps;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultNodeComponent shape={shape} theme={theme} />
|
||||||
|
<div>Subject Class: {props.subject_class}</div>
|
||||||
|
<div>Year Group: {props.year_group}</div>
|
||||||
|
<div>Subject: {props.subject}</div>
|
||||||
|
<div>Teacher Code: {props.teacher_code}</div>
|
||||||
|
<div>Planning Status: {props.planning_status}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodeComponents: { [key: string]: React.FC<NodeComponentProps> } = {
|
||||||
|
user_node: UserNodeComponent,
|
||||||
|
teacher_node: TeacherNodeComponent,
|
||||||
|
student_node: StudentNodeComponent,
|
||||||
|
timetable_lesson_node: TimetableLessonNodeComponent,
|
||||||
|
developer_node: DeveloperNodeComponent,
|
||||||
|
school_node: SchoolNodeComponent,
|
||||||
|
department_node: DepartmentNodeComponent,
|
||||||
|
planned_lesson_node: PlannedLessonNodeComponent,
|
||||||
|
registration_period_node: RegistrationPeriodNodeComponent,
|
||||||
|
teacher_timetable_node: TeacherTimetableNodeComponent,
|
||||||
|
academic_year_node: AcademicYearNodeComponent,
|
||||||
|
academic_term_node: AcademicTermNodeComponent,
|
||||||
|
academic_week_node: AcademicWeekNodeComponent,
|
||||||
|
academic_day_node: AcademicDayNodeComponent,
|
||||||
|
academic_period_node: AcademicPeriodNodeComponent,
|
||||||
|
key_stage_node: KeyStageNodeComponent,
|
||||||
|
key_stage_syllabus_node: KeyStageSyllabusNodeComponent,
|
||||||
|
year_group_syllabus_node: YearGroupSyllabusNodeComponent,
|
||||||
|
subject_node: SubjectNodeComponent,
|
||||||
|
topic_node: TopicNodeComponent,
|
||||||
|
topic_lesson_node: TopicLessonNodeComponent,
|
||||||
|
learning_statement_node: LearningStatementNodeComponent,
|
||||||
|
science_lab_node: ScienceLabNodeComponent,
|
||||||
|
school_timetable_node: SchoolTimetableNodeComponent,
|
||||||
|
calendar_node: CalendarNodeComponent,
|
||||||
|
calendar_year_node: CalendarYearNodeComponent,
|
||||||
|
calendar_month_node: CalendarMonthNodeComponent,
|
||||||
|
calendar_week_node: CalendarWeekNodeComponent,
|
||||||
|
calendar_day_node: CalendarDayNodeComponent,
|
||||||
|
calendar_time_chunk_node: CalendarTimeChunkNodeComponent,
|
||||||
|
year_group_node: YearGroupNodeComponent,
|
||||||
|
pastoral_structure_node: PastoralStructureNodeComponent,
|
||||||
|
curriculum_structure_node: CurriculumStructureNodeComponent,
|
||||||
|
room_node: RoomNodeComponent,
|
||||||
|
subject_class_node: SubjectClassNodeComponent,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNodeComponent = (shape: AllNodeShapes, theme: any) => {
|
||||||
|
const Component = nodeComponents[shape.type] || DefaultNodeComponent;
|
||||||
|
return <Component shape={shape} theme={theme} />;
|
||||||
|
};
|
||||||
225
src/utils/userContext.tsx
Normal file
225
src/utils/userContext.tsx
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
import { ReactNode, createContext, useContext, useState, useEffect } from 'react';
|
||||||
|
import { UserNodeInterface } from '../types/graph_node_types';
|
||||||
|
import { TLUser } from 'tldraw';
|
||||||
|
|
||||||
|
export const getFromLocalStorage = (key: string) => {
|
||||||
|
const item = localStorage.getItem(key);
|
||||||
|
if (item === null || item === 'undefined') return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(item);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error parsing JSON for key ${key}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setToLocalStorage = (key: string, value: any) => {
|
||||||
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeFromLocalStorage = (key: string) => {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setStateAndStorage = (setter: React.Dispatch<React.SetStateAction<any>>, key: string, value: any) => {
|
||||||
|
setter(value);
|
||||||
|
setToLocalStorage(key, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AuthContext = createContext({
|
||||||
|
userRole: null as string | null,
|
||||||
|
firebaseIdToken: null as string | null,
|
||||||
|
msAccessToken: null as string | null,
|
||||||
|
neo4jDbName: null as string | null,
|
||||||
|
userNode: null as UserNodeInterface | null,
|
||||||
|
tldrawUserFilePath: null as string | null,
|
||||||
|
oneNoteNotebook: null as any,
|
||||||
|
isLoading: false,
|
||||||
|
error: null as string | null,
|
||||||
|
logout: async () => {},
|
||||||
|
getIdToken: async () => Promise.resolve('') as Promise<string>,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const [user, setUser] = useState<TLUser | null>(getFromLocalStorage('user'));
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
|
const [userRole, setUserRole] = useState<string | null>(getFromLocalStorage('userRole'));
|
||||||
|
const [firebaseIdToken, setToken] = useState<string | null>(getFromLocalStorage('firebaseIdToken'));
|
||||||
|
const [msAccessToken, setMsToken] = useState<string | null>(getFromLocalStorage('msAccessToken'));
|
||||||
|
const [neo4jDbName, setNeo4jDbName] = useState<string | null>(getFromLocalStorage('neo4jDbName'));
|
||||||
|
const [userNode, setUserNode] = useState<UserNodeInterface | null>(getFromLocalStorage('userNode'));
|
||||||
|
const [tldrawUserFilePath, setTldrawUserFilePath] = useState<string | null>(getFromLocalStorage('tldrawUserFilePath'));
|
||||||
|
const [oneNoteNotebook, setOneNoteNotebook] = useState<any>(getFromLocalStorage('oneNoteNotebook'));
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = auth.onAuthStateChanged(async (user) => {
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
if (user) {
|
||||||
|
console.log("AuthProvider - useEffect - User state changed:", user);
|
||||||
|
const storedUserRole = getFromLocalStorage('userRole');
|
||||||
|
const storedFirebaseIdToken = await user.getIdToken();
|
||||||
|
const storedMsAccessToken = getFromLocalStorage('msAccessToken');
|
||||||
|
const storedNeo4jDbName = getFromLocalStorage('neo4jDbName');
|
||||||
|
const storedUserNode = getFromLocalStorage('userNode');
|
||||||
|
const storedOneNoteNotebook = getFromLocalStorage('oneNoteNotebook');
|
||||||
|
|
||||||
|
setStateAndStorage(setUser, 'user', user);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', storedUserRole);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', storedFirebaseIdToken);
|
||||||
|
setStateAndStorage(setMsToken, 'msAccessToken', storedMsAccessToken);
|
||||||
|
setStateAndStorage(setNeo4jDbName, 'neo4jDbName', storedNeo4jDbName);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', storedUserNode);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', storedUserNode?.path);
|
||||||
|
setStateAndStorage(setOneNoteNotebook, 'oneNoteNotebook', storedOneNoteNotebook);
|
||||||
|
|
||||||
|
console.log("AuthProvider - useEffect - Updated state:", { user, userRole: storedUserRole });
|
||||||
|
} else {
|
||||||
|
setStateAndStorage(setUser, 'user', null);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', null);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', null);
|
||||||
|
setStateAndStorage(setMsToken, 'msAccessToken', null);
|
||||||
|
setStateAndStorage(setNeo4jDbName, 'neo4jDbName', null);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', null);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', null);
|
||||||
|
setStateAndStorage(setOneNoteNotebook, 'oneNoteNotebook', null);
|
||||||
|
|
||||||
|
removeFromLocalStorage('userRole');
|
||||||
|
removeFromLocalStorage('msAccessToken');
|
||||||
|
removeFromLocalStorage('neo4jDbName');
|
||||||
|
removeFromLocalStorage('userNode');
|
||||||
|
removeFromLocalStorage('oneNoteNotebook');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setError(error instanceof Error ? error.message : 'An unknown error occurred');
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => unsubscribe();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const login = async (email: string, password: string, role: string) => {
|
||||||
|
try {
|
||||||
|
const { user, firebaseIdToken, firestoreUserDoc } = await emailLogin(email, password);
|
||||||
|
const userRole = role || firestoreUserDoc?.userRole || null;
|
||||||
|
const userNode = await fetchUserNode(user.uid);
|
||||||
|
|
||||||
|
setStateAndStorage(setUser, 'user', user);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', userRole);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', firebaseIdToken);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', userNode);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', userNode.path);
|
||||||
|
return { user, firebaseIdToken, userNode, userRole, message: 'Login successful' };
|
||||||
|
} catch (error) {
|
||||||
|
setError(error instanceof Error ? error.message : 'An unknown error occurred');
|
||||||
|
return { user: null, firebaseIdToken: null, userNode: null, userRole: null, message: 'Login failed' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
console.log("Logging out...");
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
await logoutUser();
|
||||||
|
setStateAndStorage(setUser, 'user', null);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', null);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', null);
|
||||||
|
setStateAndStorage(setMsToken, 'msAccessToken', null);
|
||||||
|
setStateAndStorage(setNeo4jDbName, 'neo4jDbName', null);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', null);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', null);
|
||||||
|
setStateAndStorage(setOneNoteNotebook, 'oneNoteNotebook', null);
|
||||||
|
removeFromLocalStorage('user');
|
||||||
|
removeFromLocalStorage('firebaseIdToken');
|
||||||
|
removeFromLocalStorage('msAccessToken');
|
||||||
|
removeFromLocalStorage('neo4jDbName');
|
||||||
|
removeFromLocalStorage('userNode');
|
||||||
|
removeFromLocalStorage('tldrawUserFilePath');
|
||||||
|
removeFromLocalStorage('oneNoteNotebook');
|
||||||
|
} catch (error) {
|
||||||
|
setError(error instanceof Error ? error.message : 'An unknown error occurred');
|
||||||
|
} finally {
|
||||||
|
console.log("Finished logging out");
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerUser = async (email: string, password: string, username: string, userRole: string): Promise<{ user: User | null; firebaseIdToken: string | null; userNode: UserNodeInterface | null; userRole: string | null; message: string | null }> => {
|
||||||
|
try {
|
||||||
|
const { user, firebaseIdToken, neo4jDbName, userNode, tldrawUserFilePath } = await registerUserWithEmailAndPassword(email, password, username, userRole);
|
||||||
|
setStateAndStorage(setUser, 'user', user);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', userRole);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', firebaseIdToken);
|
||||||
|
setStateAndStorage(setNeo4jDbName, 'neo4jDbName', neo4jDbName);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', userNode);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', userNode.path);
|
||||||
|
return { user, firebaseIdToken, userNode, userRole, message: 'Email user registered successfully' };
|
||||||
|
} catch (error) {
|
||||||
|
return { user: null, firebaseIdToken: null, userNode: null, userRole: null, message: error instanceof Error ? error.message : 'An unknown error occurred' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerOrLoginWithMicrosoft = async (role: string): Promise<{ user: User | null; firebaseIdToken: string | null; msAccessToken: string | null; userNode: UserNodeInterface | null; userRole: string | null; message: string | null; oneNoteNotebook: any }> => {
|
||||||
|
try {
|
||||||
|
console.log("registerOrLoginWithMicrosoft - Starting");
|
||||||
|
console.log(`Ready to sign in with Microsoft as ${role}`);
|
||||||
|
const { user, firebaseIdToken, msAccessToken, neo4jDbName, userNode, oneNoteNotebook, isNewUser } = await signInWithMicrosoft(role);
|
||||||
|
setStateAndStorage(setUser, 'user', user || null);
|
||||||
|
setStateAndStorage(setUserRole, 'userRole', role);
|
||||||
|
setStateAndStorage(setToken, 'firebaseIdToken', firebaseIdToken || null);
|
||||||
|
setStateAndStorage(setMsToken, 'msAccessToken', msAccessToken || null);
|
||||||
|
setStateAndStorage(setNeo4jDbName, 'neo4jDbName', neo4jDbName || null);
|
||||||
|
setStateAndStorage(setUserNode, 'userNode', userNode || null);
|
||||||
|
setStateAndStorage(setTldrawUserFilePath, 'tldrawUserFilePath', userNode?.path || null);
|
||||||
|
setStateAndStorage(setOneNoteNotebook, 'oneNoteNotebook', oneNoteNotebook || null);
|
||||||
|
|
||||||
|
console.log(`Signed in with Microsoft as ${role}`);
|
||||||
|
console.log("OneNote Notebook:", oneNoteNotebook);
|
||||||
|
setIsLoading(false);
|
||||||
|
return { user, userRole: role, firebaseIdToken, msAccessToken, userNode, oneNoteNotebook, message: isNewUser ? 'User registered successfully with Microsoft' : 'User logged in successfully with Microsoft' };
|
||||||
|
} catch (error) {
|
||||||
|
setError(error instanceof Error ? error.message : 'An unknown error occurred');
|
||||||
|
setIsLoading(false);
|
||||||
|
return { user: null, userRole: null, firebaseIdToken: null, msAccessToken: null, userNode: null, oneNoteNotebook: null, message: 'Failed to sign in with Microsoft' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getIdToken = async () => {
|
||||||
|
if (user) {
|
||||||
|
return await user.getIdToken(true);
|
||||||
|
}
|
||||||
|
throw new Error('User not authenticated');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider
|
||||||
|
value={{
|
||||||
|
user,
|
||||||
|
userRole,
|
||||||
|
firebaseIdToken,
|
||||||
|
msAccessToken,
|
||||||
|
userNode,
|
||||||
|
tldrawUserFilePath,
|
||||||
|
oneNoteNotebook,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
registerUser,
|
||||||
|
registerOrLoginWithMicrosoft,
|
||||||
|
error,
|
||||||
|
isLoading,
|
||||||
|
neo4jDbName,
|
||||||
|
clearError: () => setError(null),
|
||||||
|
getIdToken,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAuth = () => useContext(AuthContext);
|
||||||
35
tsconfig.base.json
Normal file
35
tsconfig.base.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"display": "Default",
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"incremental": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": ["dom", "DOM.Iterable", "esnext"],
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"types": ["node", "@types/jest"]
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
"include": ["src", "scripts", "vite.config.mts"],
|
||||||
|
"exclude": ["node_modules", "dist", ".tsbuild*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"types": ["bun-types", "node"],
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
||||||
16
vite.config.mts
Normal file
16
vite.config.mts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import react from '@vitejs/plugin-react-swc'
|
||||||
|
import path from 'path'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
|
export default defineConfig(() => ({
|
||||||
|
plugins: [react({ tsDecorators: true })],
|
||||||
|
root: path.join(__dirname, 'src/client'),
|
||||||
|
publicDir: path.join(__dirname, 'public'),
|
||||||
|
server: {
|
||||||
|
port: 5000,
|
||||||
|
host: '0.0.0.0', // Expose the server to the network
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
exclude: ['assets'],
|
||||||
|
},
|
||||||
|
}))
|
||||||
Loading…
x
Reference in New Issue
Block a user