diff --git a/.gitignore b/.gitignore index 61233810..61a1afa9 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,6 @@ dev/*.ipynb # Jest coverage reports and a side effect coverage junit.xml + +# Interfaces generated from json-schema +src/workflows/_interface diff --git a/package.json b/package.json index 8c60bbe5..f92e21e1 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "build:labextension": "jupyter labextension build .", "build:labextension:dev": "jupyter labextension build --development True .", "build:lib": "tsc", + "build:schema:js": "json2ts -i src/workflows/schema -o src/workflows/_interface --no-unknownAny --unreachableDefinitions --cwd ./src/workflows/schema", "clean": "jlpm clean:lib", "clean:lib": "rimraf lib tsconfig.tsbuildinfo", "clean:lintcache": "rimraf .eslintcache .stylelintcache", @@ -74,6 +75,7 @@ "@mui/system": "^5.10.6", "@types/react-dom": "^18.0.5", "cronstrue": "^2.12.0", + "json-schema-to-typescript": "^15.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", "tzdata": "^1.0.33" diff --git a/src/workflows/schema/workflow.schema.json b/src/workflows/schema/workflow.schema.json new file mode 100644 index 00000000..0af54a62 --- /dev/null +++ b/src/workflows/schema/workflow.schema.json @@ -0,0 +1,111 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Workflow", + "type": "object", + "properties": { + "schemaVersion": { + "type": "string", + "default": "0.0.1" + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/definitions/Task" + }, + "description": "Worfklow tasks." + }, + "name": { + "type": "string", + "description": "The name of the workflow." + }, + "parameters": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional parameters for the workflow." + }, + "schedule": { + "type": "string", + "description": "Optional schedule in cron format." + }, + "timezone": { + "type": "string", + "description": "Timezone for the schedule." + } + }, + "required": [ + "tasks", + "name" + ], + "definitions": { + "Task": { + "type": "object", + "properties": { + "input_uri": { + "type": "string", + "description": "The URI of the input file." + }, + "runtime_environment_name": { + "type": "string", + "description": "Name of the runtime environment." + }, + "runtime_environment_parameters": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Parameters for the runtime environment." + }, + "output_formats": { + "type": "array", + "items": { + "type": "string" + } + }, + "parameters": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Task-specific parameters." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for categorizing the job." + }, + "name": { + "type": "string", + "description": "Name of the job." + }, + "compute_type": { + "type": "string", + "description": "Type of compute resource to use." + }, + "package_input_folder": { + "type": "boolean", + "description": "Whether to package the input folder." + }, + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DAG node IDs of tasks this task depends on." + }, + "node_id": { + "type": "string", + "description": "DAG node ID of this task." + } + }, + "required": [ + "input_uri", + "name", + "node_id" + ] + } + } +} diff --git a/src/workflows/workflowDoc.ts b/src/workflows/workflowDoc.ts new file mode 100644 index 00000000..bc46526b --- /dev/null +++ b/src/workflows/workflowDoc.ts @@ -0,0 +1,44 @@ +import { YDocument } from '@jupyter/ydoc'; +import * as Y from 'yjs'; +import { Workflow, Task } from './_interface/workflow.schema'; + +export class WorkflowDoc extends YDocument implements Workflow { + private _tasks: Y.Array>; + private _name: Y.Text; + private _parameters: Y.Map; + private _schedule: Y.Text; + private _timezone: Y.Text; + + constructor() { + super(); + + this._tasks = this.ydoc.getArray>('tasks'); + this._name = this.ydoc.getText('name'); + this._parameters = this.ydoc.getMap('parameters'); + this._schedule = this.ydoc.getText('schedule'); + this._timezone = this.ydoc.getText('timezone'); + + this._tasks.observeDeep(this._tasksObserver); + //TODO: add other observers + } + + // Getter and setter methods + get tasks(): Task[] { + return this._tasks.map(task => task.toJSON() as Task); + } + + set tasks(value: Task[]) { + this.transact(() => { + this._tasks.delete(0, this._tasks.length); + value.forEach(task => { + this._tasks.push([Y.Map.from(Object.entries(task))]); + }); + }); + } + + //TODO: add other getters/setters + + private _tasksObserver = (events: Y.YEvent[]) => { + // TODO: Handle task changes + }; +} diff --git a/yarn.lock b/yarn.lock index e50f85cf..0e1e80d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,6 +25,17 @@ __metadata: languageName: node linkType: hard +"@apidevtools/json-schema-ref-parser@npm:^11.5.5": + version: 11.7.2 + resolution: "@apidevtools/json-schema-ref-parser@npm:11.7.2" + dependencies: + "@jsdevtools/ono": ^7.1.3 + "@types/json-schema": ^7.0.15 + js-yaml: ^4.1.0 + checksum: 44096e5cd5a03b17ee5eb0a3b9e9a4db85d87da8ae2abda264eae615f2a43e3e6ba5ca208e1161d4d946755b121c10a9550e88792a725951f2c4cff6df0d8a19 + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -3321,6 +3332,13 @@ __metadata: languageName: node linkType: hard +"@jsdevtools/ono@npm:^7.1.3": + version: 7.1.3 + resolution: "@jsdevtools/ono@npm:7.1.3" + checksum: 2297fcd472ba810bffe8519d2249171132844c7174f3a16634f9260761c8c78bc0428a4190b5b6d72d45673c13918ab9844d706c3ed4ef8f62ab11a2627a08ad + languageName: node + linkType: hard + "@jupyter/ydoc@npm:^1.0.2": version: 1.0.2 resolution: "@jupyter/ydoc@npm:1.0.2" @@ -3839,6 +3857,7 @@ __metadata: eslint-config-prettier: ^6.15.0 eslint-plugin-prettier: ^3.1.4 jest: ^29 + json-schema-to-typescript: ^15.0.3 mkdirp: ^1.0.3 npm-run-all: ^4.1.5 prettier: ^2.1.1 @@ -4751,6 +4770,13 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.9": version: 7.0.12 resolution: "@types/json-schema@npm:7.0.12" @@ -4758,6 +4784,13 @@ __metadata: languageName: node linkType: hard +"@types/lodash@npm:^4.17.7": + version: 4.17.13 + resolution: "@types/lodash@npm:4.17.13" + checksum: d0bf8fbd950be71946e0076b30fd40d492293baea75f05931b6b5b906fd62583708c6229abdb95b30205ad24ce1ed2f48bc9d419364f682320edd03405cc0c7e + languageName: node + linkType: hard + "@types/minimist@npm:^1.2.0": version: 1.2.2 resolution: "@types/minimist@npm:1.2.2" @@ -5465,6 +5498,13 @@ __metadata: languageName: node linkType: hard +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -6967,6 +7007,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.4.2": + version: 6.4.2 + resolution: "fdir@npm:6.4.2" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 517ad31c495f1c0778238eef574a7818788efaaf2ce1969ffa18c70793e2951a9763dfa2e6720b8fcef615e602a3cbb47f9b8aea9da0b02147579ab36043f22f + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -7722,7 +7774,7 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1": +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: @@ -8446,6 +8498,17 @@ __metadata: languageName: node linkType: hard +"js-yaml@npm:^4.1.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" + dependencies: + argparse: ^2.0.1 + bin: + js-yaml: bin/js-yaml.js + checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a + languageName: node + linkType: hard + "jsdom@npm:^20.0.0": version: 20.0.3 resolution: "jsdom@npm:20.0.3" @@ -8537,6 +8600,25 @@ __metadata: languageName: node linkType: hard +"json-schema-to-typescript@npm:^15.0.3": + version: 15.0.3 + resolution: "json-schema-to-typescript@npm:15.0.3" + dependencies: + "@apidevtools/json-schema-ref-parser": ^11.5.5 + "@types/json-schema": ^7.0.15 + "@types/lodash": ^4.17.7 + is-glob: ^4.0.3 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + minimist: ^1.2.8 + prettier: ^3.2.5 + tinyglobby: ^0.2.9 + bin: + json2ts: dist/src/cli.js + checksum: e2337655d4a6f9ec0baccecda1e6d29bfdc5c04afed03d27669e87652334c1db5b8f7b3ad84623ad987ebe3e83e931dc181380bcd8b03d21ee3812a1f8a56239 + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -9022,6 +9104,13 @@ __metadata: languageName: node linkType: hard +"minimist@npm:^1.2.8": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 + languageName: node + linkType: hard + "minimist@npm:~1.2.0": version: 1.2.6 resolution: "minimist@npm:1.2.6" @@ -9571,6 +9660,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: a7a5188c954f82c6585720e9143297ccd0e35ad8072231608086ca950bee672d51b0ef676254af0788205e59bd4e4deb4e7708769226bed725bf13370a7d1464 + languageName: node + linkType: hard + "pidtree@npm:^0.3.0": version: 0.3.1 resolution: "pidtree@npm:0.3.1" @@ -9730,6 +9826,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.2.5": + version: 3.4.2 + resolution: "prettier@npm:3.4.2" + bin: + prettier: bin/prettier.cjs + checksum: 061c84513db62d3944c8dc8df36584dad82883ce4e49efcdbedd8703dce5b173c33fd9d2a4e1725d642a3b713c932b55418342eaa347479bc4a9cca114a04cd0 + languageName: node + linkType: hard + "pretty-format@npm:^29.0.0, pretty-format@npm:^29.6.1": version: 29.6.1 resolution: "pretty-format@npm:29.6.1" @@ -11004,6 +11109,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.9": + version: 0.2.10 + resolution: "tinyglobby@npm:0.2.10" + dependencies: + fdir: ^6.4.2 + picomatch: ^4.0.2 + checksum: 7e2ffe262ebc149036bdef37c56b32d02d52cf09efa7d43dbdab2ea3c12844a4da881058835ce4c74d1891190e5ad5ec5133560a11ec8314849b68ad0d99d3f4 + languageName: node + linkType: hard + "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5"