diff --git a/angular.json b/angular.json index cc6bb425e..f2f5a0297 100644 --- a/angular.json +++ b/angular.json @@ -108,7 +108,9 @@ "dist/common/assets/fonts/material-design-icons/material-icons.css", "node_modules/codemirror/lib/codemirror.css", "node_modules/ol/ol.css", - "./node_modules/vis-timeline/dist/vis-timeline-graph2d.min.css" + "./node_modules/vis-timeline/dist/vis-timeline-graph2d.min.css", + "node_modules/workflow-editor/src/workflow_editor/static/widget.css", + "node_modules/@fortawesome/fontawesome-free/css/all.min.css" ], "scripts": ["node_modules/vis-timeline/peer/esm/vis-timeline-graph2d.min.js"], "vendorChunk": true, diff --git a/package-lock.json b/package-lock.json index eb4b0c611..b24a711ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", "@egjs/hammerjs": "^2.0.17", + "@fortawesome/fontawesome-free": "^5.15.4", "@geoengine/openapi-client": "0.0.10", "codemirror": "~5.65.16", "d3": "~7.9.0", @@ -43,6 +44,7 @@ "vis-data": "7.1.9", "vis-timeline": "7.7.3", "vis-util": "5.0.7", + "workflow-editor": "git+https://github.com/1lutz/workflow-editor.git", "xss": "1.0.15", "zone.js": "~0.14.4" }, @@ -2964,6 +2966,22 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dagrejs/dagre": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.4.tgz", + "integrity": "sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==", + "dependencies": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==", + "engines": { + "node": ">17.0.0" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -3489,6 +3507,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@geoengine/openapi-client": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/@geoengine/openapi-client/-/openapi-client-0.0.10.tgz", @@ -3718,6 +3745,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@json-editor/json-editor": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@json-editor/json-editor/-/json-editor-2.15.1.tgz", + "integrity": "sha512-Z4KFXpL7I9wrKD94c1PcIwFfCvUzYhwM0jH2ihP2OSH8wut0FnqzCfKCL0gdNHG3A2UVsyVJBoU9Iwsc0xB6zQ==", + "dependencies": { + "core-js": "^3.27.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -5093,6 +5131,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@puppeteer/browsers": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz", @@ -8052,6 +8100,24 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -8343,6 +8409,11 @@ } ] }, + "node_modules/capability": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz", + "integrity": "sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==" + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -8815,6 +8886,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.36.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", @@ -10623,6 +10704,16 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-polyfill": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz", + "integrity": "sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==", + "dependencies": { + "capability": "^0.2.5", + "o3": "^1.0.3", + "u3": "^0.1.1" + } + }, "node_modules/es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -14159,6 +14250,14 @@ "node >= 0.2.0" ] }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "engines": { + "node": "*" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -14590,6 +14689,11 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/litegraph.js": { + "version": "0.7.18", + "resolved": "https://registry.npmjs.org/litegraph.js/-/litegraph.js-0.7.18.tgz", + "integrity": "sha512-1WEwjOO58j4FcLX8DvsuMXM371MEq4Y+8pBr3q2pBhJ9nDkwBtBd9Gj6bxArBKhW6i42bSOyv9ybeuez6NAxoQ==" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -16369,6 +16473,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/o3": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz", + "integrity": "sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==", + "dependencies": { + "capability": "^0.2.5" + } + }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -20195,6 +20307,11 @@ "node": ">=14.17" } }, + "node_modules/u3": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz", + "integrity": "sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==" + }, "node_modules/ua-parser-js": { "version": "0.7.35", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", @@ -21571,6 +21688,28 @@ "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.3.tgz", "integrity": "sha512-ZnV3yH8/k58ZPACOXeiHaMuXIiaTk1t0hSUVisbO0t4RjA5wPpUytcxeyiN2h+LZRrmuHIh/1UlrR9e7DHDvTw==" }, + "node_modules/workflow-editor": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/1lutz/workflow-editor.git#af6d7d29e2da77c9f123d253c3672ba0135b8ad8", + "dependencies": { + "@dagrejs/dagre": "^1.1.3", + "@json-editor/json-editor": "^2.14.0", + "bootstrap": "^5.3.2", + "error-polyfill": "^0.1.3", + "jsonschema": "^1.4.1", + "litegraph.js": "^0.7.18", + "yaml": "^2.4.5", + "zod": "^3.23.4" + } + }, + "node_modules/workflow-editor/node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -21756,6 +21895,17 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -23736,6 +23886,19 @@ } } }, + "@dagrejs/dagre": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.4.tgz", + "integrity": "sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==", + "requires": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==" + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -24010,6 +24173,11 @@ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true }, + "@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==" + }, "@geoengine/openapi-client": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/@geoengine/openapi-client/-/openapi-client-0.0.10.tgz", @@ -24180,6 +24348,14 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@json-editor/json-editor": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@json-editor/json-editor/-/json-editor-2.15.1.tgz", + "integrity": "sha512-Z4KFXpL7I9wrKD94c1PcIwFfCvUzYhwM0jH2ihP2OSH8wut0FnqzCfKCL0gdNHG3A2UVsyVJBoU9Iwsc0xB6zQ==", + "requires": { + "core-js": "^3.27.2" + } + }, "@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -25350,6 +25526,12 @@ } } }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true + }, "@puppeteer/browsers": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz", @@ -27705,6 +27887,12 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "requires": {} + }, "bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -27901,6 +28089,11 @@ "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true }, + "capability": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz", + "integrity": "sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -28277,6 +28470,11 @@ } } }, + "core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==" + }, "core-js-compat": { "version": "3.36.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", @@ -29647,6 +29845,16 @@ "is-arrayish": "^0.2.1" } }, + "error-polyfill": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz", + "integrity": "sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==", + "requires": { + "capability": "^0.2.5", + "o3": "^1.0.3", + "u3": "^0.1.1" + } + }, "es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -32272,6 +32480,11 @@ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "dev": true }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==" + }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -32616,6 +32829,11 @@ "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", "dev": true }, + "litegraph.js": { + "version": "0.7.18", + "resolved": "https://registry.npmjs.org/litegraph.js/-/litegraph.js-0.7.18.tgz", + "integrity": "sha512-1WEwjOO58j4FcLX8DvsuMXM371MEq4Y+8pBr3q2pBhJ9nDkwBtBd9Gj6bxArBKhW6i42bSOyv9ybeuez6NAxoQ==" + }, "loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -33848,6 +34066,14 @@ } } }, + "o3": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz", + "integrity": "sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==", + "requires": { + "capability": "^0.2.5" + } + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -36720,6 +36946,11 @@ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, + "u3": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz", + "integrity": "sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==" + }, "ua-parser-js": { "version": "0.7.35", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", @@ -37766,6 +37997,27 @@ "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.3.tgz", "integrity": "sha512-ZnV3yH8/k58ZPACOXeiHaMuXIiaTk1t0hSUVisbO0t4RjA5wPpUytcxeyiN2h+LZRrmuHIh/1UlrR9e7DHDvTw==" }, + "workflow-editor": { + "version": "git+ssh://git@github.com/1lutz/workflow-editor.git#af6d7d29e2da77c9f123d253c3672ba0135b8ad8", + "from": "workflow-editor@git+https://github.com/1lutz/workflow-editor.git", + "requires": { + "@dagrejs/dagre": "^1.1.3", + "@json-editor/json-editor": "^2.14.0", + "bootstrap": "^5.3.2", + "error-polyfill": "^0.1.3", + "jsonschema": "^1.4.1", + "litegraph.js": "^0.7.18", + "yaml": "^2.4.5", + "zod": "^3.23.4" + }, + "dependencies": { + "zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" + } + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -37897,6 +38149,11 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==" + }, "yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 290de086a..96a3263fb 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", "@egjs/hammerjs": "^2.0.17", + "@fortawesome/fontawesome-free": "^5.15.4", "@geoengine/openapi-client": "0.0.10", "codemirror": "~5.65.16", "d3": "~7.9.0", @@ -76,6 +77,7 @@ "vis-data": "7.1.9", "vis-timeline": "7.7.3", "vis-util": "5.0.7", + "workflow-editor": "git+https://github.com/1lutz/workflow-editor.git", "xss": "1.0.15", "zone.js": "~0.14.4" }, diff --git a/projects/core/src/lib/core.module.ts b/projects/core/src/lib/core.module.ts index 78dc199d4..f95e53a83 100644 --- a/projects/core/src/lib/core.module.ts +++ b/projects/core/src/lib/core.module.ts @@ -148,6 +148,8 @@ import {MapResolutionExtentOverlayComponent} from './map/map-info/map-resolution import {DownloadLayerComponent} from './download-layer/download-layer.component'; import {BandwiseExpressionOperatorComponent} from './operators/dialogs/bandwise-expression-operator/bandwise-expression-operator.component'; import {BandNeighborhoodAggregateComponent} from './operators/dialogs/band-neighborhood-aggregate/band-neighborhood-aggregate.component'; +import {WorkflowEditorComponent} from "./workflow-editor/workflow-editor.component"; +import {CreateWorkflowComponent} from "./datasets/create-workflow/create-workflow.component"; export const MATERIAL_MODULES = [ MatAutocompleteModule, @@ -195,6 +197,7 @@ const CORE_PIPES = [ const CORE_COMPONENTS = [ AddDataComponent, AddWorkflowComponent, + CreateWorkflowComponent, AutocompleteSelectDirective, BackendStatusPageComponent, BoxPlotOperatorComponent, @@ -232,7 +235,6 @@ const CORE_COMPONENTS = [ LayerListMenuComponent, LayerSelectionComponent, LineageGraphComponent, - LineageGraphComponent, LineSimplificationComponent, LoadProjectComponent, LoginComponent, @@ -301,6 +303,7 @@ const CORE_COMPONENTS = [ WorkspaceSettingsComponent, ZoomHandlesComponent, + WorkflowEditorComponent ]; @NgModule({ diff --git a/projects/core/src/lib/datasets/add-data/add-data.component.ts b/projects/core/src/lib/datasets/add-data/add-data.component.ts index 20ed4a2db..026efc0cc 100644 --- a/projects/core/src/lib/datasets/add-data/add-data.component.ts +++ b/projects/core/src/lib/datasets/add-data/add-data.component.ts @@ -6,6 +6,7 @@ import {LayoutService, SidenavConfig} from '../../layout.service'; import {AddWorkflowComponent} from '../add-workflow/add-workflow.component'; import {DrawFeaturesComponent} from '../draw-features/draw-features.component'; import {UploadComponent} from '../upload/upload.component'; +import {CreateWorkflowComponent} from "../create-workflow/create-workflow.component"; export interface AddDataButton { name: string; @@ -98,4 +99,16 @@ export class AddDataComponent { sidenavConfig: {component: AddWorkflowComponent, keepParent: true}, }; } + + /** + * Create workflow dialog + */ + static createWorkflowEditorButton(): AddDataButton { + return { + name: 'Create Workflow using Editor', + description: 'Add a new workflow by graph editor', + icon: 'build', + sidenavConfig: {component: CreateWorkflowComponent, keepParent: true}, + }; + } } diff --git a/projects/core/src/lib/datasets/add-workflow/add-workflow.component.ts b/projects/core/src/lib/datasets/add-workflow/add-workflow.component.ts index 2602b16b4..fbf15dcd3 100644 --- a/projects/core/src/lib/datasets/add-workflow/add-workflow.component.ts +++ b/projects/core/src/lib/datasets/add-workflow/add-workflow.component.ts @@ -1,10 +1,11 @@ import {Component, ChangeDetectionStrategy} from '@angular/core'; import {UntypedFormGroup, UntypedFormControl, Validators} from '@angular/forms'; -import {GeoEngineErrorDict, RasterResultDescriptorDict, UUID, VectorResultDescriptorDict} from '../../backend/backend.model'; +import {UUID} from '../../backend/backend.model'; import {NotificationService} from '../../notification.service'; import {ProjectService} from '../../project/project.service'; import {RandomColorService} from '../../util/services/random-color.service'; -import {RasterLayer, RasterSymbology, VectorLayer, createVectorSymbology, isValidUuid} from '@geoengine/common'; +import {isValidUuid} from '@geoengine/common'; +import {DatasetService} from "../dataset.service"; @Component({ selector: 'geoengine-add-workflow', @@ -19,6 +20,7 @@ export class AddWorkflowComponent { protected readonly projectService: ProjectService, protected readonly notificationService: NotificationService, protected readonly randomColorService: RandomColorService, + protected readonly datasetService: DatasetService, ) { this.form = new UntypedFormGroup({ layerName: new UntypedFormControl('New Layer', Validators.required), @@ -30,71 +32,22 @@ export class AddWorkflowComponent { const layerName: string = this.form.controls.layerName.value; const workflowId: UUID = this.form.controls.workflowId.value; - this.projectService.getWorkflowMetaData(workflowId).subscribe( - (resultDescriptorDict) => { - const keys = Object.keys(resultDescriptorDict); + this.datasetService.createLayerFromWorkflow(layerName, workflowId).subscribe( + layer => { + this.projectService.addLayer(layer); + }, + error => { + let errorMessage = `No workflow found for id: ${workflowId}`; - if (keys.includes('columns')) { - this.addVectorLayer(layerName, workflowId, resultDescriptorDict as VectorResultDescriptorDict); - } else if (keys.includes('bands')) { - this.addRasterLayer(layerName, workflowId, resultDescriptorDict as RasterResultDescriptorDict); + if ("error" in error) { + if (error.error !== 'NoWorkflowForGivenId') { + errorMessage = `Unknown error -> ${error.error}: ${error.message}`; + } } else { - // TODO: implement plots, etc. - this.notificationService.error('Adding this workflow type is unimplemented, yet'); + errorMessage = error.message; } - }, - (requestError) => this.handleError(requestError.error, workflowId), + this.notificationService.error(errorMessage); + } ); } - - private addVectorLayer(layerName: string, workflowId: UUID, resultDescriptor: VectorResultDescriptorDict): void { - const layer = new VectorLayer({ - name: layerName, - workflowId, - isVisible: true, - isLegendVisible: false, - symbology: createVectorSymbology(resultDescriptor.dataType, this.randomColorService.getRandomColorRgba()), - }); - - this.projectService.addLayer(layer); - } - - private addRasterLayer(layerName: string, workflowId: UUID, _resultDescriptor: RasterResultDescriptorDict): void { - const layer = new RasterLayer({ - name: layerName, - workflowId, - isVisible: true, - isLegendVisible: false, - symbology: RasterSymbology.fromRasterSymbologyDict({ - type: 'raster', - opacity: 1.0, - rasterColorizer: { - type: 'singleBand', - band: 0, - bandColorizer: { - type: 'linearGradient', - breakpoints: [ - {value: 1, color: [0, 0, 0, 255]}, - {value: 255, color: [255, 255, 255, 255]}, - ], - overColor: [255, 255, 255, 127], - underColor: [0, 0, 0, 127], - noDataColor: [0, 0, 0, 0], - }, - }, - }), - }); - - this.projectService.addLayer(layer); - } - - private handleError(error: GeoEngineErrorDict, workflowId: UUID): void { - let errorMessage = `No workflow found for id: ${workflowId}`; - - if (error.error !== 'NoWorkflowForGivenId') { - errorMessage = `Unknown error -> ${error.error}: ${error.message}`; - } - - this.notificationService.error(errorMessage); - } } diff --git a/projects/core/src/lib/datasets/create-workflow/create-workflow.component.html b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.html new file mode 100644 index 000000000..8a918b969 --- /dev/null +++ b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.html @@ -0,0 +1,21 @@ +Create Workflow via Editor + + +

+ Here you can add a new layer by creating a new workflow using an interactive graph-based editor. +

+
+ +
+ + layer Name + + Must not be empty + + +
+ +
+
diff --git a/projects/core/src/lib/datasets/create-workflow/create-workflow.component.scss b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.scss new file mode 100644 index 000000000..ebcbe1e2f --- /dev/null +++ b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.scss @@ -0,0 +1,17 @@ +:host { + display: block; + padding: 1rem; +} + +mat-form-field, +button { + width: 100% !important; +} + +.error { + color: var(--geoengine-warn-color, red); +} + +button { + margin-top: 1rem; +} diff --git a/projects/core/src/lib/datasets/create-workflow/create-workflow.component.ts b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.ts new file mode 100644 index 000000000..9144e3407 --- /dev/null +++ b/projects/core/src/lib/datasets/create-workflow/create-workflow.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import {UntypedFormControl, UntypedFormGroup, Validators} from "@angular/forms"; +import {MatDialog} from "@angular/material/dialog"; +import {WorkflowEditorComponent} from "../../workflow-editor/workflow-editor.component"; +import {LayoutService} from "../../layout.service"; + +@Component({ + selector: 'geoengine-create-workflow', + templateUrl: './create-workflow.component.html', + styleUrl: './create-workflow.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CreateWorkflowComponent { + readonly form: UntypedFormGroup; + + constructor( + protected readonly dialog: MatDialog, + protected readonly layoutService: LayoutService + ) { + this.form = new UntypedFormGroup({ + layerName: new UntypedFormControl('New Layer', Validators.required) + }); + } + + openEditor(): void { + this.layoutService.setSidenavContentComponent(undefined); + const layerName: string = this.form.controls.layerName.value; + this.dialog.open(WorkflowEditorComponent, {data: {layerOrNewName: layerName}}); + } +} diff --git a/projects/core/src/lib/datasets/dataset.service.ts b/projects/core/src/lib/datasets/dataset.service.ts index 6fee0a38a..b1a000807 100644 --- a/projects/core/src/lib/datasets/dataset.service.ts +++ b/projects/core/src/lib/datasets/dataset.service.ts @@ -8,12 +8,12 @@ import { AutoCreateDatasetDict, CreateDatasetDict, DatasetNameResponseDict, - MetaDataSuggestionDict, + MetaDataSuggestionDict, RasterResultDescriptorDict, SuggestMetaDataDict, UploadFileLayersResponseDict, UploadFilesResponseDict, UploadResponseDict, - UUID, + UUID, VectorResultDescriptorDict, } from '../backend/backend.model'; import {RandomColorService} from '../util/services/random-color.service'; import {ProjectService} from '../project/project.service'; @@ -31,6 +31,7 @@ import { VectorResultDescriptor, VectorSymbology, colorToDict, + createVectorSymbology, } from '@geoengine/common'; import {Workflow as WorkflowDict} from '@geoengine/openapi-client'; @@ -44,7 +45,8 @@ export class DatasetService { protected userService: UserService, protected projectService: ProjectService, protected randomColorService: RandomColorService, - ) {} + ) { + } getDatasets(offset = 0, limit = 20): Observable> { return this.userService.getSessionStream().pipe( @@ -59,6 +61,7 @@ export class DatasetService { map((dict) => Dataset.fromDict(dict)), ); } + upload(form: FormData): Observable> { return this.userService.getSessionTokenForRequest().pipe(mergeMap((token) => this.backend.upload(token, form))); } @@ -103,6 +106,60 @@ export class DatasetService { return this.projectService.registerWorkflow(workflow).pipe(map((workflowId) => this.createLayer(workflowId, dataset))); } + createLayerFromWorkflow(layerName: string, workflowId: UUID): Observable { + return this.projectService.getWorkflowMetaData(workflowId).pipe( + map(resultDescriptorDict => { + const keys = Object.keys(resultDescriptorDict); + + if (keys.includes('columns')) { + return this.createVectorLayer(layerName, workflowId, resultDescriptorDict as VectorResultDescriptorDict); + } else if (keys.includes('bands')) { + return this.createRasterLayer(layerName, workflowId, resultDescriptorDict as RasterResultDescriptorDict); + } else { + // TODO: implement plots, etc. + throw new Error('Adding this workflow type is unimplemented, yet'); + } + }) + ); + } + + private createVectorLayer(layerName: string, workflowId: UUID, resultDescriptor: VectorResultDescriptorDict): VectorLayer { + return new VectorLayer({ + name: layerName, + workflowId, + isVisible: true, + isLegendVisible: false, + symbology: createVectorSymbology(resultDescriptor.dataType, this.randomColorService.getRandomColorRgba()), + }); + } + + private createRasterLayer(layerName: string, workflowId: UUID, _resultDescriptor: RasterResultDescriptorDict): RasterLayer { + return new RasterLayer({ + name: layerName, + workflowId, + isVisible: true, + isLegendVisible: false, + symbology: RasterSymbology.fromRasterSymbologyDict({ + type: 'raster', + opacity: 1.0, + rasterColorizer: { + type: 'singleBand', + band: 0, + bandColorizer: { + type: 'linearGradient', + breakpoints: [ + {value: 1, color: [0, 0, 0, 255]}, + {value: 255, color: [255, 255, 255, 255]}, + ], + overColor: [255, 255, 255, 127], + underColor: [0, 0, 0, 127], + noDataColor: [0, 0, 0, 0], + }, + }, + }), + }); + } + createLayer(workflowId: string, dataset: Dataset): Layer { if (dataset.resultDescriptor.getTypeString() === 'Raster') { const symbology = dataset.symbology as RasterSymbology; @@ -112,23 +169,23 @@ export class DatasetService { symbology: symbology ? symbology : RasterSymbology.fromRasterSymbologyDict({ - type: 'raster', - opacity: 1.0, - rasterColorizer: { - type: 'singleBand', - band: 0, - bandColorizer: { - type: 'linearGradient', - breakpoints: [ - {value: 1, color: [0, 0, 0, 255]}, - {value: 255, color: [255, 255, 255, 255]}, - ], - overColor: [255, 255, 255, 127], - underColor: [0, 0, 0, 127], - noDataColor: [0, 0, 0, 0], - }, - }, - }), + type: 'raster', + opacity: 1.0, + rasterColorizer: { + type: 'singleBand', + band: 0, + bandColorizer: { + type: 'linearGradient', + breakpoints: [ + {value: 1, color: [0, 0, 0, 255]}, + {value: 255, color: [255, 255, 255, 255]}, + ], + overColor: [255, 255, 255, 127], + underColor: [0, 0, 0, 127], + noDataColor: [0, 0, 0, 0], + }, + }, + }), isLegendVisible: false, isVisible: true, }); @@ -142,63 +199,63 @@ export class DatasetService { symbology = (dataset.symbology as PointSymbology) ? (dataset.symbology as PointSymbology) : ClusteredPointSymbology.fromPointSymbologyDict({ - type: 'point', - radius: { - type: 'static', - value: PointSymbology.DEFAULT_POINT_RADIUS, - }, - stroke: { - width: { - type: 'static', - value: 1, - }, - color: { - type: 'static', - color: [0, 0, 0, 255], - }, - }, - fillColor: { - type: 'static', - color: colorToDict(this.randomColorService.getRandomColorRgba()), - }, - }); + type: 'point', + radius: { + type: 'static', + value: PointSymbology.DEFAULT_POINT_RADIUS, + }, + stroke: { + width: { + type: 'static', + value: 1, + }, + color: { + type: 'static', + color: [0, 0, 0, 255], + }, + }, + fillColor: { + type: 'static', + color: colorToDict(this.randomColorService.getRandomColorRgba()), + }, + }); break; case VectorDataTypes.MultiLineString: symbology = (dataset.symbology as LineSymbology) ? (dataset.symbology as LineSymbology) : LineSymbology.fromLineSymbologyDict({ - type: 'line', - stroke: { - width: {type: 'static', value: 1}, - color: { - type: 'static', - color: colorToDict(this.randomColorService.getRandomColorRgba()), - }, - }, - autoSimplified: true, - }); + type: 'line', + stroke: { + width: {type: 'static', value: 1}, + color: { + type: 'static', + color: colorToDict(this.randomColorService.getRandomColorRgba()), + }, + }, + autoSimplified: true, + }); break; case VectorDataTypes.MultiPolygon: symbology = (dataset.symbology as PolygonSymbology) ? (dataset.symbology as PolygonSymbology) : PolygonSymbology.fromPolygonSymbologyDict({ - type: 'polygon', - stroke: { - width: { - type: 'static', - value: 1, - }, - color: { - type: 'static', - color: [0, 0, 0, 255], - }, - }, - fillColor: { - type: 'static', - color: colorToDict(this.randomColorService.getRandomColorRgba()), - }, - autoSimplified: true, - }); + type: 'polygon', + stroke: { + width: { + type: 'static', + value: 1, + }, + color: { + type: 'static', + color: [0, 0, 0, 255], + }, + }, + fillColor: { + type: 'static', + color: colorToDict(this.randomColorService.getRandomColorRgba()), + }, + autoSimplified: true, + }); break; default: throw Error('unknown symbology type'); diff --git a/projects/core/src/lib/layers/layer-list/layer-list-element/layer-list-element.component.html b/projects/core/src/lib/layers/layer-list/layer-list-element/layer-list-element.component.html index f8a5e46c2..5373b6cf5 100644 --- a/projects/core/src/lib/layers/layer-list/layer-list-element/layer-list-element.component.html +++ b/projects/core/src/lib/layers/layer-list/layer-list-element/layer-list-element.component.html @@ -20,9 +20,9 @@ Hide Legend - + + diff --git a/projects/core/src/lib/workflow-editor/workflow-editor.component.scss b/projects/core/src/lib/workflow-editor/workflow-editor.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/projects/core/src/lib/workflow-editor/workflow-editor.component.ts b/projects/core/src/lib/workflow-editor/workflow-editor.component.ts new file mode 100644 index 000000000..ed745e5bb --- /dev/null +++ b/projects/core/src/lib/workflow-editor/workflow-editor.component.ts @@ -0,0 +1,137 @@ +import {Component, ChangeDetectionStrategy, ViewChild, ElementRef, AfterViewInit, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Layer} from '@geoengine/common'; +import {ProjectService} from "../project/project.service"; +import {render, WidgetModel} from "workflow-editor"; +import {UserService} from "../users/user.service"; +import {BehaviorSubject, mergeMap} from "rxjs"; +import {map} from "rxjs/operators"; +import {NotificationService} from "../notification.service"; +import {DatasetService} from "../datasets/dataset.service"; + +class WidgetModelWrapper { + data: WidgetModel = {} as any; + listeners: Record void)[]> = {}; + widget_manager: undefined; + + get(key: K): WidgetModel[K] { + return this.data[key]; + } + + set(key: K, value: WidgetModel[K]): void { + const oldValue = this.data[key]; + + if (oldValue !== value) { + this.data[key] = value; + this.listeners["change:" + key]?.forEach(listener => listener.call(this, null, [])); + } + } + + off(_eventName?: string, _callback?: (...args: any[]) => void): void { + throw new Error('Function not implemented.'); + } + + on(eventName: string, callback: (msg: any, buffers: DataView[]) => void): void { + let selectedListeners = this.listeners[eventName]; + + if (selectedListeners) { + selectedListeners.push(callback); + } else { + this.listeners[eventName] = [callback]; + } + } + + save_changes(): void { + //noop + } + + send(_content: any, _callbacks?: any, _buffers?: ArrayBuffer[] | ArrayBufferView[] | undefined): void { + throw new Error('Function not implemented.'); + } +} + +@Component({ + selector: 'geoengine-workflow-editor', + templateUrl: './workflow-editor.component.html', + styleUrls: ['./workflow-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class WorkflowEditorComponent implements AfterViewInit { + readonly title: string; + readonly layerName: string; + readonly layer?: Layer; + + @ViewChild("widget") + readonly widgetRef!: ElementRef; + readonly loading$; + readonly isValid$ = new BehaviorSubject(false); + readonly widgetModel = new WidgetModelWrapper(); + + constructor( + private elementRef: ElementRef, + private projectService: ProjectService, + private userService: UserService, + private dialogRef: MatDialogRef, + private notificationService: NotificationService, + private datasetService: DatasetService, + @Inject(MAT_DIALOG_DATA) private config: { layerOrNewName: Layer | string }, + ) { + if (typeof this.config.layerOrNewName === "string") { + this.layerName = this.config.layerOrNewName; + this.loading$ = new BehaviorSubject(false); + } else { + this.layer = this.config.layerOrNewName; + this.layerName = this.layer.name; + this.loading$ = new BehaviorSubject(true); + } + this.title = `Workflow Editor for ${this.layerName}`; + this.userService.getSessionStream().subscribe(session => { + this.widgetModel.set("token", session.sessionToken); + this.widgetModel.set("serverUrl", session.apiConfiguration.basePath); + }); + this.widgetModel.on("change:workflow", () => { + const workflow = this.widgetModel.get("workflow"); + this.isValid$.next(workflow != null); + }); + } + + ngAfterViewInit(): void { + if (this.layer) { + this.projectService.getWorkflow(this.layer.workflowId).subscribe(workflow => { + this.widgetModel.set("workflow", workflow as any); + render({ + model: this.widgetModel, + el: this.widgetRef.nativeElement + }); + this.loading$.next(false); + }); + } else { + render({ + model: this.widgetModel, + el: this.widgetRef.nativeElement + }); + } + } + + onSave() { + const layerCopy = this.layer; + + if (layerCopy) { + this.projectService.registerWorkflow(this.widgetModel.get("workflow")!).pipe( + map(workflowId => this.projectService.changeLayer(layerCopy, { + workflowId + })) + ).subscribe(() => { + this.dialogRef.close(); + this.notificationService.info(`Updated layer »${this.layerName}«`); + }); + } else { + this.projectService.registerWorkflow(this.widgetModel.get("workflow")!).pipe( + mergeMap(workflowId => this.datasetService.createLayerFromWorkflow(this.layerName, workflowId)), + map(layer => this.projectService.addLayer(layer)) + ).subscribe(() => { + this.dialogRef.close(); + }) + } + } +} diff --git a/projects/core/src/public-api.ts b/projects/core/src/public-api.ts index df7f87638..926949ff6 100644 --- a/projects/core/src/public-api.ts +++ b/projects/core/src/public-api.ts @@ -23,6 +23,7 @@ export * from './lib/util/services/random-color.service'; // Components export * from './lib/datasets/add-data/add-data.component'; export * from './lib/datasets/add-workflow/add-workflow.component'; +export * from './lib/datasets/create-workflow/create-workflow.component'; export * from './lib/datasets/dataset-list/dataset-list.component'; export * from './lib/datasets/dataset/dataset.component'; export * from './lib/datasets/drag-and-drop/drag-and-drop.component'; @@ -96,6 +97,7 @@ export * from './lib/project/notifications/notifications.component'; export * from './lib/project/save-project-as/save-project-as.component'; export * from './lib/project/workspace-settings/workspace-settings.component'; export * from './lib/provenance/lineage-graph/lineage-graph.component'; +export * from './lib/workflow-editor/workflow-editor.component'; export * from './lib/provenance/table/provenance-table.component'; export * from './lib/sidenav/navigation/navigation.component'; export * from './lib/sidenav/sidenav-container/sidenav-container.component'; diff --git a/projects/dashboards/gfbio/src/app/app.component.ts b/projects/dashboards/gfbio/src/app/app.component.ts index dbf69f2f2..98d09f77c 100644 --- a/projects/dashboards/gfbio/src/app/app.component.ts +++ b/projects/dashboards/gfbio/src/app/app.component.ts @@ -248,6 +248,7 @@ export class AppComponent implements OnInit, AfterViewInit { AddDataComponent.createUploadButton(), AddDataComponent.createDrawFeaturesButton(), AddDataComponent.createAddWorkflowByIdButton(), + AddDataComponent.createWorkflowEditorButton() ]), ); } diff --git a/projects/gis/src/app/main/main.component.ts b/projects/gis/src/app/main/main.component.ts index 7235d0458..eb1af0db0 100644 --- a/projects/gis/src/app/main/main.component.ts +++ b/projects/gis/src/app/main/main.component.ts @@ -36,7 +36,6 @@ import { TimeConfigComponent, PlotListComponent, SidenavConfig, - SpatialReferenceService, LayerCollectionService, TaskListComponent, } from '@geoengine/core'; @@ -87,7 +86,6 @@ export class MainComponent implements OnInit, AfterViewInit { private readonly activatedRoute: ActivatedRoute, private readonly notificationService: NotificationService, private readonly mapService: MapService, - private readonly spatialReferenceService: SpatialReferenceService, ) { vcRef.length; // eslint-disable-line @typescript-eslint/no-unused-expressions @@ -233,6 +231,7 @@ export class MainComponent implements OnInit, AfterViewInit { AddDataComponent.createUploadButton(), AddDataComponent.createDrawFeaturesButton(), AddDataComponent.createAddWorkflowByIdButton(), + AddDataComponent.createWorkflowEditorButton() ]), ); }