From c0c2bed07d41bdd4d1e038db864e9bcd9cce5e87 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Tue, 13 Jan 2026 18:55:13 +0200 Subject: [PATCH 1/3] chore: update source files and configuration --- package-lock.json | 343 +++++++----------- package.json | 68 ++-- scripts/generate-mixins.ts | 46 +++ src/js/ExecutionUnitInput.ts | 89 +++++ src/js/RuntimeItemsUILogicMixin.ts | 87 +++++ src/js/context/context.js | 47 --- .../context/mixins/ApplicationContextMixin.js | 19 - .../context/mixins/ApplicationContextMixin.ts | 27 ++ .../mixins/ContextAndRenderFieldsMixin.ts | 53 +++ .../mixins/ImportantSettingsProviderMixin.ts | 50 +++ src/js/context/mixins/JobContextMixin.js | 36 -- src/js/context/mixins/JobContextMixin.ts | 27 ++ src/js/context/mixins/MaterialContextMixin.js | 41 --- src/js/context/mixins/MaterialContextMixin.ts | 35 ++ .../context/mixins/MaterialsContextMixin.js | 18 - .../context/mixins/MaterialsContextMixin.ts | 24 ++ .../mixins/MaterialsSetContextMixin.js | 24 -- .../mixins/MaterialsSetContextMixin.ts | 35 ++ .../context/mixins/MethodDataContextMixin.js | 48 --- .../context/mixins/MethodDataContextMixin.ts | 36 ++ src/js/context/mixins/WorkflowContextMixin.js | 25 -- src/js/context/mixins/WorkflowContextMixin.ts | 31 ++ src/js/context/providers.js | 140 ------- src/js/context/providers.ts | 183 ++++++++++ .../BoundaryConditionsFormDataProvider.js | 72 ---- .../BoundaryConditionsFormDataProvider.ts | 67 ++++ .../CollinearMagnetizationContextProvider.js | 105 ------ .../CollinearMagnetizationContextProvider.ts | 115 ++++++ .../Hubbard/HubbardContextProvider.ts | 73 ++++ .../Hubbard/HubbardContextProviderLegacy.ts | 73 ++++ .../Hubbard/HubbardJContextProvider.ts | 62 ++++ .../Hubbard/HubbardUContextProvider.ts | 61 ++++ .../HubbardVContextProvider.ts} | 82 ++--- .../providers/HubbardContextProviderLegacy.js | 67 ---- .../providers/HubbardJContextProvider.js | 65 ---- .../providers/HubbardUContextProvider.js | 95 ----- .../providers/IonDynamicsContextProvider.js | 44 --- .../providers/IonDynamicsContextProvider.ts | 49 +++ .../providers/MLSettingsContextProvider.js | 45 --- .../providers/MLSettingsContextProvider.ts | 54 +++ .../MLTrainTestSplitContextProvider.js | 43 --- .../MLTrainTestSplitContextProvider.ts | 51 +++ .../context/providers/NEBFormDataProvider.js | 33 -- .../context/providers/NEBFormDataProvider.ts | 42 +++ ...nCollinearMagnetizationContextProvider.ts} | 160 ++++---- .../PlanewaveCutoffsContextProvider.js | 65 ---- .../PlanewaveCutoffsContextProvider.ts | 69 ++++ .../PointsGrid/IGridFormDataManager.ts | 9 + .../PointsGrid/KGridFormDataManager.ts | 7 + .../PointsGrid/PointsGridFormDataProvider.ts | 328 +++++++++++++++++ .../PointsGrid/QGridFormDataManager.ts | 9 + .../providers/PointsGridFormDataProvider.js | 271 -------------- .../ExplicitKPath2PIBAFormDataManager.ts | 11 + .../ExplicitKPathFormDataManager.ts | 9 + .../PointsPath/IPathFormDataManager.ts | 7 + .../PointsPath/KPathFormDataManager.ts | 7 + .../PointsPath/PointsPathFormDataProvider.ts | 163 +++++++++ .../PointsPath/QPathFormDataManager.ts | 7 + .../providers/PointsPathFormDataProvider.js | 163 --------- .../context/providers/base/ContextProvider.ts | 107 ++++++ .../providers/base/JSONSchemaDataProvider.ts | 33 ++ .../base/JSONSchemaFormDataProvider.ts | 40 ++ .../ExecutableContextProvider.js | 17 - .../espresso/QENEBContextProvider.js | 58 --- .../espresso/QENEBContextProvider.ts | 111 ++++++ .../espresso/QEPWXContextProvider.js | 168 --------- .../espresso/QEPWXContextProvider.ts | 159 ++++++++ .../NWChemTotalEnergyContextProvider.js | 89 ----- .../NWChemTotalEnergyContextProvider.ts | 95 +++++ .../vasp/VASPContextProvider.js | 58 --- .../vasp/VASPContextProvider.ts | 99 +++++ .../vasp/VASPNEBContextProvider.js | 48 --- .../vasp/VASPNEBContextProvider.ts | 93 +++++ .../providers/{settings.js => settings.ts} | 6 +- src/js/{enums.js => enums.ts} | 14 + src/js/generated/AssertionUnitSchemaMixin.ts | 34 ++ src/js/generated/AssignmentUnitSchemaMixin.ts | 40 ++ src/js/generated/BaseUnitSchemaMixin.ts | 64 ++++ src/js/generated/ConditionUnitSchemaMixin.ts | 58 +++ .../ExecutionUnitInputSchemaMixin.ts | 36 ++ src/js/generated/ExecutionUnitSchemaMixin.ts | 52 +++ src/js/generated/IOUnitSchemaMixin.ts | 40 ++ src/js/generated/MapUnitSchemaMixin.ts | 34 ++ src/js/generated/ProcessingUnitSchemaMixin.ts | 40 ++ src/js/generated/ReduceUnitSchemaMixin.ts | 34 ++ src/js/generated/StatusSchemaMixin.ts | 28 ++ src/js/generated/SubworkflowSchemaMixin.ts | 52 +++ .../generated/SubworkflowUnitSchemaMixin.ts | 22 ++ src/js/index.js | 4 +- src/js/patch.js | 12 - .../{subworkflow.js => subworkflow.ts} | 176 ++++----- src/js/units/AssertionUnit.ts | 30 ++ src/js/units/AssignmentUnit.ts | 31 ++ src/js/units/BaseUnit.ts | 121 ++++++ src/js/units/ConditionUnit.ts | 36 ++ src/js/units/ExecutionUnit.ts | 203 +++++++++++ src/js/units/IOUnit.ts | 17 + src/js/units/MapUnit.ts | 35 ++ src/js/units/ProcessingUnit.ts | 36 ++ src/js/units/ReduceUnit.ts | 20 + src/js/units/SubworkflowUnit.ts | 20 + src/js/units/assertion.js | 29 -- src/js/units/assignment.js | 34 -- src/js/units/base.js | 97 ----- src/js/units/condition.js | 47 --- src/js/units/execution.js | 267 -------------- src/js/units/factory.js | 53 --- src/js/units/factory.ts | 55 +++ src/js/units/index.js | 25 -- src/js/units/index.ts | 25 ++ src/js/units/io.js | 163 --------- src/js/units/map.js | 33 -- src/js/units/processing.js | 39 -- src/js/units/reduce.js | 17 - src/js/units/subworkflow.js | 15 - tsconfig.json | 7 + types/periodic-table.d.ts | 46 +++ 117 files changed, 4354 insertions(+), 3183 deletions(-) create mode 100644 scripts/generate-mixins.ts create mode 100644 src/js/ExecutionUnitInput.ts create mode 100644 src/js/RuntimeItemsUILogicMixin.ts delete mode 100644 src/js/context/context.js delete mode 100644 src/js/context/mixins/ApplicationContextMixin.js create mode 100644 src/js/context/mixins/ApplicationContextMixin.ts create mode 100644 src/js/context/mixins/ContextAndRenderFieldsMixin.ts create mode 100644 src/js/context/mixins/ImportantSettingsProviderMixin.ts delete mode 100644 src/js/context/mixins/JobContextMixin.js create mode 100644 src/js/context/mixins/JobContextMixin.ts delete mode 100644 src/js/context/mixins/MaterialContextMixin.js create mode 100644 src/js/context/mixins/MaterialContextMixin.ts delete mode 100644 src/js/context/mixins/MaterialsContextMixin.js create mode 100644 src/js/context/mixins/MaterialsContextMixin.ts delete mode 100644 src/js/context/mixins/MaterialsSetContextMixin.js create mode 100644 src/js/context/mixins/MaterialsSetContextMixin.ts delete mode 100644 src/js/context/mixins/MethodDataContextMixin.js create mode 100644 src/js/context/mixins/MethodDataContextMixin.ts delete mode 100644 src/js/context/mixins/WorkflowContextMixin.js create mode 100644 src/js/context/mixins/WorkflowContextMixin.ts delete mode 100644 src/js/context/providers.js create mode 100644 src/js/context/providers.ts delete mode 100644 src/js/context/providers/BoundaryConditionsFormDataProvider.js create mode 100644 src/js/context/providers/BoundaryConditionsFormDataProvider.ts delete mode 100644 src/js/context/providers/CollinearMagnetizationContextProvider.js create mode 100644 src/js/context/providers/CollinearMagnetizationContextProvider.ts create mode 100644 src/js/context/providers/Hubbard/HubbardContextProvider.ts create mode 100644 src/js/context/providers/Hubbard/HubbardContextProviderLegacy.ts create mode 100644 src/js/context/providers/Hubbard/HubbardJContextProvider.ts create mode 100644 src/js/context/providers/Hubbard/HubbardUContextProvider.ts rename src/js/context/providers/{HubbardVContextProvider.js => Hubbard/HubbardVContextProvider.ts} (53%) delete mode 100644 src/js/context/providers/HubbardContextProviderLegacy.js delete mode 100644 src/js/context/providers/HubbardJContextProvider.js delete mode 100644 src/js/context/providers/HubbardUContextProvider.js delete mode 100644 src/js/context/providers/IonDynamicsContextProvider.js create mode 100644 src/js/context/providers/IonDynamicsContextProvider.ts delete mode 100644 src/js/context/providers/MLSettingsContextProvider.js create mode 100644 src/js/context/providers/MLSettingsContextProvider.ts delete mode 100644 src/js/context/providers/MLTrainTestSplitContextProvider.js create mode 100644 src/js/context/providers/MLTrainTestSplitContextProvider.ts delete mode 100644 src/js/context/providers/NEBFormDataProvider.js create mode 100644 src/js/context/providers/NEBFormDataProvider.ts rename src/js/context/providers/{NonCollinearMagnetizationContextProvider.js => NonCollinearMagnetizationContextProvider.ts} (64%) delete mode 100644 src/js/context/providers/PlanewaveCutoffsContextProvider.js create mode 100644 src/js/context/providers/PlanewaveCutoffsContextProvider.ts create mode 100644 src/js/context/providers/PointsGrid/IGridFormDataManager.ts create mode 100644 src/js/context/providers/PointsGrid/KGridFormDataManager.ts create mode 100644 src/js/context/providers/PointsGrid/PointsGridFormDataProvider.ts create mode 100644 src/js/context/providers/PointsGrid/QGridFormDataManager.ts delete mode 100644 src/js/context/providers/PointsGridFormDataProvider.js create mode 100644 src/js/context/providers/PointsPath/ExplicitKPath2PIBAFormDataManager.ts create mode 100644 src/js/context/providers/PointsPath/ExplicitKPathFormDataManager.ts create mode 100644 src/js/context/providers/PointsPath/IPathFormDataManager.ts create mode 100644 src/js/context/providers/PointsPath/KPathFormDataManager.ts create mode 100644 src/js/context/providers/PointsPath/PointsPathFormDataProvider.ts create mode 100644 src/js/context/providers/PointsPath/QPathFormDataManager.ts delete mode 100644 src/js/context/providers/PointsPathFormDataProvider.js create mode 100644 src/js/context/providers/base/ContextProvider.ts create mode 100644 src/js/context/providers/base/JSONSchemaDataProvider.ts create mode 100644 src/js/context/providers/base/JSONSchemaFormDataProvider.ts delete mode 100644 src/js/context/providers/by_application/ExecutableContextProvider.js delete mode 100644 src/js/context/providers/by_application/espresso/QENEBContextProvider.js create mode 100644 src/js/context/providers/by_application/espresso/QENEBContextProvider.ts delete mode 100644 src/js/context/providers/by_application/espresso/QEPWXContextProvider.js create mode 100644 src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts delete mode 100644 src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.js create mode 100644 src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.ts delete mode 100644 src/js/context/providers/by_application/vasp/VASPContextProvider.js create mode 100644 src/js/context/providers/by_application/vasp/VASPContextProvider.ts delete mode 100644 src/js/context/providers/by_application/vasp/VASPNEBContextProvider.js create mode 100644 src/js/context/providers/by_application/vasp/VASPNEBContextProvider.ts rename src/js/context/providers/{settings.js => settings.ts} (84%) rename src/js/{enums.js => enums.ts} (81%) create mode 100644 src/js/generated/AssertionUnitSchemaMixin.ts create mode 100644 src/js/generated/AssignmentUnitSchemaMixin.ts create mode 100644 src/js/generated/BaseUnitSchemaMixin.ts create mode 100644 src/js/generated/ConditionUnitSchemaMixin.ts create mode 100644 src/js/generated/ExecutionUnitInputSchemaMixin.ts create mode 100644 src/js/generated/ExecutionUnitSchemaMixin.ts create mode 100644 src/js/generated/IOUnitSchemaMixin.ts create mode 100644 src/js/generated/MapUnitSchemaMixin.ts create mode 100644 src/js/generated/ProcessingUnitSchemaMixin.ts create mode 100644 src/js/generated/ReduceUnitSchemaMixin.ts create mode 100644 src/js/generated/StatusSchemaMixin.ts create mode 100644 src/js/generated/SubworkflowSchemaMixin.ts create mode 100644 src/js/generated/SubworkflowUnitSchemaMixin.ts delete mode 100644 src/js/patch.js rename src/js/subworkflows/{subworkflow.js => subworkflow.ts} (68%) create mode 100644 src/js/units/AssertionUnit.ts create mode 100644 src/js/units/AssignmentUnit.ts create mode 100644 src/js/units/BaseUnit.ts create mode 100644 src/js/units/ConditionUnit.ts create mode 100644 src/js/units/ExecutionUnit.ts create mode 100644 src/js/units/IOUnit.ts create mode 100644 src/js/units/MapUnit.ts create mode 100644 src/js/units/ProcessingUnit.ts create mode 100644 src/js/units/ReduceUnit.ts create mode 100644 src/js/units/SubworkflowUnit.ts delete mode 100644 src/js/units/assertion.js delete mode 100644 src/js/units/assignment.js delete mode 100644 src/js/units/base.js delete mode 100644 src/js/units/condition.js delete mode 100644 src/js/units/execution.js delete mode 100644 src/js/units/factory.js create mode 100644 src/js/units/factory.ts delete mode 100644 src/js/units/index.js create mode 100644 src/js/units/index.ts delete mode 100644 src/js/units/io.js delete mode 100644 src/js/units/map.js delete mode 100644 src/js/units/processing.js delete mode 100644 src/js/units/reduce.js delete mode 100644 src/js/units/subworkflow.js create mode 100644 tsconfig.json create mode 100644 types/periodic-table.d.ts diff --git a/package-lock.json b/package-lock.json index c6811feb..a5922381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,44 +9,47 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "@babel/cli": "7.16.0", - "@babel/core": "7.16.0", - "@babel/eslint-parser": "7.16.3", - "@babel/plugin-proposal-class-properties": "7.16.0", - "@babel/preset-env": "7.16.4", - "@babel/preset-react": "7.16.7", - "@babel/register": "^7.16.0", - "@babel/runtime-corejs3": "7.16.8", "@exabyte-io/periodic-table.js": "2022.6.8-0", + "@types/json-schema": "^7.0.15", + "@types/nunjucks": "^3.2.6", + "@types/react-jsonschema-form": "^1.7.13", "crypto-js": "^4.2.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "mixwith": "^0.1.1", + "nunjucks": "^3.2.4", + "ts-node": "^10.9.2", + "typescript": "^5.6.6", "underscore": "^1.13.3", "underscore.string": "^3.3.4", "v20": "^0.1.0" }, "devDependencies": { "@exabyte-io/eslint-config": "2025.5.13-0", - "@mat3ra/ade": "2025.11.26-0", - "@mat3ra/code": "2025.10.24-0", - "@mat3ra/esse": "2025.11.26-0", + "@mat3ra/ade": "git+https://github.com/Exabyte-io/ade#6d494337d83e1b22fe272ff74cc1b6842a7c6561", + "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#3a7eab6a28db4a85711795e84ace3c74f7681577", "@mat3ra/ide": "2025.11.19-0", - "@mat3ra/made": "2025.7.15-0", + "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", "@mat3ra/mode": "2025.11.13-0", "@mat3ra/standata": "git+https://github.com/Exabyte-io/standata.git#3c5b6365a6a5fcfbbd4e5da3a30cd5dd4c0301ee", + "@mat3ra/tsconfig": "2024.6.3-0", "@mat3ra/utils": "2025.9.20-0", + "@types/crypto-js": "^4.2.2", "chai": "^4.3.4", - "eslint": "7.32.0", - "eslint-config-airbnb": "19.0.2", + "eslint": "^7.32.0", + "eslint-config-airbnb": "^19.0.2", "eslint-config-prettier": "^8.5.0", - "eslint-import-resolver-exports": "^1.0.0-beta.2", - "eslint-plugin-import": "2.25.3", - "eslint-plugin-jsdoc": "37.1.0", - "eslint-plugin-jsx-a11y": "6.5.1", + "eslint-import-resolver-exports": "^1.0.0-beta.5", + "eslint-import-resolver-meteor": "^0.4.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsdoc": "^37.1.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-mui-path-imports": "0.0.15", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "7.30.0", - "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-react": "^7.30.0", + "eslint-plugin-simple-import-sort": "^7.0.0", "husky": "^7.0.4", "lint-staged": "^12.1.2", "mocha": "^9.1.3", @@ -1045,6 +1048,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1830,6 +1834,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1845,6 +1850,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -1864,6 +1870,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" @@ -1879,6 +1886,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -2207,6 +2215,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7", @@ -2247,6 +2256,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz", "integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==", + "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -2272,23 +2282,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs2": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.28.4.tgz", - "integrity": "sha512-chjPHn3p+okNMesTjKU/pnpVT06oiJG1sVDJHTkAwYTCnVdM/2V5LI5xz3Y2y7MNngn8fQ19fpXjV3f9Jqun9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-js": "^2.6.12" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/runtime-corejs3": { "version": "7.16.8", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz", "integrity": "sha512-3fKhuICS1lMz0plI5ktOE/yEtBRMVxplzRkdn6mJQ197XiY0JnrzYV0+Mxozq3JZ8SBV9Ecurmw1XsGbwOf+Sg==", + "dev": true, "license": "MIT", "dependencies": { "core-js-pure": "^3.20.2", @@ -2347,7 +2345,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -2360,7 +2357,6 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2805,16 +2801,13 @@ "license": "MIT" }, "node_modules/@mat3ra/ade": { - "version": "2025.11.26-0", - "resolved": "https://registry.npmjs.org/@mat3ra/ade/-/ade-2025.11.26-0.tgz", - "integrity": "sha512-lz1c2henlUmZqzcKAczkYXwosN9Oqyqe05mkpdgGf6AACcHldr0Vh99d/6TnPM9dm5l0BU86F+LYHTJRVUKEiA==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/ade.git#6d494337d83e1b22fe272ff74cc1b6842a7c6561", + "integrity": "sha512-6c0/WS3y8i1Su1PDiIQKWkAktlFlJN8etFHGVUmYBWEwb7yFlg4fGccvOpLAhqga5Yk/SPcA7NEuMB+BwnpyXQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@types/react-jsonschema-form": "^1.7.13", - "lodash": "^4.17.21", - "nunjucks": "^3.2.4", - "react-jsonschema-form": "^1.8.1" + "lodash": "^4.17.21" }, "engines": { "node": ">=20.0.0" @@ -2828,9 +2821,9 @@ } }, "node_modules/@mat3ra/code": { - "version": "2025.10.24-0", - "resolved": "https://registry.npmjs.org/@mat3ra/code/-/code-2025.10.24-0.tgz", - "integrity": "sha512-hR53j/PgRHQxl+ROm92pQHeMXkWL110VcF+gFovKyjlhhkzSR1oG07fpLFIguIEJ2kbvKAZ0CXDnZIaIUVwFGQ==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", + "integrity": "sha512-lxmiLW3kCYWc2of2BWbrE+NNU4DcRNGtaJYJ7C9UA7y2JQXjuHYX1dqCDh5hN3A6esu8giEOXsBwf+b64M9EYQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2868,9 +2861,9 @@ } }, "node_modules/@mat3ra/esse": { - "version": "2025.11.26-0", - "resolved": "https://registry.npmjs.org/@mat3ra/esse/-/esse-2025.11.26-0.tgz", - "integrity": "sha512-m0KZ3E8n+RvJR7cWeGstcJCXt7qxO0eCiZ97ojbBg5H2smTKLBfh4g5UF5ylJnk5PaArcPcRtLYwHcOxuPZHuA==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#3a7eab6a28db4a85711795e84ace3c74f7681577", + "integrity": "sha512-rxEVn6+BkRYQ4dRK6fLZj/5lxkwB6JepmF2XjYJ3VTg2hyFey4ZdxRsFQNMXjLIOWU4B4QtErQ+m+iHnGewu3Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3705,15 +3698,29 @@ } }, "node_modules/@mat3ra/esse/node_modules/typed-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", + "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", "dev": true, "license": "MIT", "engines": { "node": ">= 18" } }, + "node_modules/@mat3ra/esse/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@mat3ra/ide": { "version": "2025.11.19-0", "resolved": "https://registry.npmjs.org/@mat3ra/ide/-/ide-2025.11.19-0.tgz", @@ -3743,9 +3750,9 @@ } }, "node_modules/@mat3ra/made": { - "version": "2025.7.15-0", - "resolved": "https://registry.npmjs.org/@mat3ra/made/-/made-2025.7.15-0.tgz", - "integrity": "sha512-6mpQnpxrQ8FEP8mO+0N8oa36tURxeNM7N2zHthzz6gZlqYNf5ipJp9F6vHEqMLZ30RSIib4/oCmK3UQI4MBzAA==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", + "integrity": "sha512-07+f5AUKW1SpkftRqr84/s/KSP114PmuT5cAH30Pn+V3OTIfQrvf5vBWuRjYuoDg/HK2UZzqmv2FE/dY43gfTw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3887,6 +3894,20 @@ "dev": true, "license": "MIT" }, + "node_modules/@mat3ra/made/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@mat3ra/made/node_modules/underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", @@ -3930,20 +3951,6 @@ "@mat3ra/standata": "*" } }, - "node_modules/@mat3ra/mode/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@mat3ra/standata": { "version": "0.0.0", "resolved": "git+ssh://git@github.com/Exabyte-io/standata.git#3c5b6365a6a5fcfbbd4e5da3a30cd5dd4c0301ee", @@ -4008,6 +4015,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@mat3ra/standata/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@mat3ra/tsconfig": { + "version": "2024.6.3-0", + "resolved": "https://registry.npmjs.org/@mat3ra/tsconfig/-/tsconfig-2024.6.3-0.tgz", + "integrity": "sha512-dA3gKDSl9+vlZvot1DN+UXfZPgxPSyHkZrkfVCTOWvzwm/3NdJ4cTzrTxjBIWUrZukpVVtH5ao8FbXLB6RDQzQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@mat3ra/utils": { "version": "2025.9.20-0", "resolved": "https://registry.npmjs.org/@mat3ra/utils/-/utils-2025.9.20-0.tgz", @@ -4162,6 +4193,20 @@ "node": ">= 18" } }, + "node_modules/@mat3ra/utils/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -4238,28 +4283,24 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, "license": "MIT" }, "node_modules/@types/chai": { @@ -4279,6 +4320,13 @@ "@types/chai": "*" } }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", @@ -4290,7 +4338,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/json-schema-merge-allof": { @@ -4338,17 +4385,21 @@ "version": "20.19.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz", "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@types/nunjucks": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@types/nunjucks/-/nunjucks-3.2.6.tgz", + "integrity": "sha512-pHiGtf83na1nCzliuAdq8GowYiXvH5l931xZ0YEHaLMNFgynpEqx+IPStlu7UaDkehfvl01e4x/9Tpwhy7Ue3w==", + "license": "MIT" + }, "node_modules/@types/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.6.tgz", - "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", - "dev": true, + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -4358,7 +4409,6 @@ "version": "1.7.13", "resolved": "https://registry.npmjs.org/@types/react-jsonschema-form/-/react-jsonschema-form-1.7.13.tgz", "integrity": "sha512-C2jgO7/ow76oCSfUK++jKKox17R0A7ryMYNE5hJ2dR1Ske9jhuvjIlurvzMePh+Xjk8wey0nzB2C7HFKe2pRdg==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "*", @@ -4661,7 +4711,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "dev": true, "license": "MIT" }, "node_modules/acorn": { @@ -4689,7 +4738,6 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -4702,7 +4750,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -4873,7 +4920,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -5022,7 +5068,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, "license": "MIT" }, "node_modules/assertion-error": { @@ -5657,15 +5702,6 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "dev": true, - "hasInstallScript": true, - "license": "MIT" - }, "node_modules/core-js-compat": { "version": "3.46.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", @@ -5683,6 +5719,7 @@ "version": "3.46.0", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.46.0.tgz", "integrity": "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "funding": { @@ -5694,7 +5731,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -5731,7 +5767,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, "license": "MIT" }, "node_modules/dag-map": { @@ -6357,7 +6392,6 @@ "integrity": "sha512-BSqvgt6QZvk9EGhDGnM4azgbxyBD8b0y6FYA52WFzpWpHcZV9ys8PxM33bx8dlCy3HyopRLLsMUnlhTpZzsZmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "object-assign": "^4.0.1", "resolve": "^1.1.6" @@ -6642,7 +6676,6 @@ "integrity": "sha512-u61kgRBtUAG+zoApuf8oWuW6mf3SIfrpMq/gSQEM2h/3qzkqvWXB4RRmPzVryS6bpeXT0QsW8rFcdcMVnoz0hw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "requireindex": "^1.2.0" }, @@ -9181,7 +9214,6 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, "license": "ISC" }, "node_modules/math-intrinsics": { @@ -9573,7 +9605,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "a-sync-waterfall": "^1.0.0", @@ -9599,7 +9630,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -10455,17 +10485,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -10473,62 +10492,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-jsonschema-form": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/react-jsonschema-form/-/react-jsonschema-form-1.8.1.tgz", - "integrity": "sha512-aaDloxNAcGXOOOcdKOxxqEEn5oDlPUZgWcs8unXXB9vjBRgCF8rCm/wVSv1u2G5ih0j/BX6Ewd/WjI2g00lPdg==", - "deprecated": "react-jsonschema-form has been moved to @rjsf/core", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime-corejs2": "^7.4.5", - "ajv": "^6.7.0", - "core-js": "^2.5.7", - "lodash": "^4.17.15", - "prop-types": "^15.5.8", - "react-is": "^16.8.4", - "react-lifecycles-compat": "^3.0.4", - "shortid": "^2.2.14" - }, - "engines": { - "node": ">=6", - "npm": ">=2.14.7" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-jsonschema-form/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/react-jsonschema-form/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "dev": true, - "license": "MIT" - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -10587,6 +10550,7 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/regexp.prototype.flags": { @@ -10712,7 +10676,6 @@ "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.5" } @@ -11038,35 +11001,6 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.17", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", - "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8" - } - }, - "node_modules/shortid/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -11705,7 +11639,6 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -11749,7 +11682,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -11762,7 +11694,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -11991,17 +11922,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -12046,7 +11976,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -12160,7 +12089,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, "license": "MIT" }, "node_modules/valid-url": { @@ -12536,7 +12464,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index d273a68d..6edb1e54 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "test": "nyc --reporter=text mocha --recursive --bail --require @babel/register/lib --require tests/js/setup.js tests/js", "lint": "eslint src/js tests/js && prettier --write src/js tests/js", "lint:fix": "eslint --fix --cache src/js tests/js && prettier --write src/js tests/js", - "transpile": "babel --out-dir dist/js src/js", + "transpile": "tsc --project tsconfig.json", "prettier": "prettier --check src/js tests/js", - "prepare": "husky install || exit 0" + "prepare": "husky install || exit 0", + "generate-mixins": "ts-node scripts/generate-mixins.ts" }, "repository": { "type": "git", @@ -29,44 +30,47 @@ "license": "Apache-2.0", "homepage": "https://github.com/Exabyte-io/wode", "dependencies": { - "@babel/cli": "7.16.0", - "@babel/core": "7.16.0", - "@babel/eslint-parser": "7.16.3", - "@babel/plugin-proposal-class-properties": "7.16.0", - "@babel/preset-env": "7.16.4", - "@babel/preset-react": "7.16.7", - "@babel/register": "^7.16.0", - "@babel/runtime-corejs3": "7.16.8", "@exabyte-io/periodic-table.js": "2022.6.8-0", + "@types/json-schema": "^7.0.15", + "@types/nunjucks": "^3.2.6", + "@types/react-jsonschema-form": "^1.7.13", "crypto-js": "^4.2.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "mixwith": "^0.1.1", + "nunjucks": "^3.2.4", + "ts-node": "^10.9.2", + "typescript": "^5.6.6", "underscore": "^1.13.3", "underscore.string": "^3.3.4", "v20": "^0.1.0" }, "devDependencies": { - "@mat3ra/ade": "2025.11.26-0", "@exabyte-io/eslint-config": "2025.5.13-0", + "@mat3ra/ade": "git+https://github.com/Exabyte-io/ade#6d494337d83e1b22fe272ff74cc1b6842a7c6561", + "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#3a7eab6a28db4a85711795e84ace3c74f7681577", "@mat3ra/ide": "2025.11.19-0", + "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", "@mat3ra/mode": "2025.11.13-0", - "@mat3ra/utils": "2025.9.20-0", - "@mat3ra/code": "2025.10.24-0", - "@mat3ra/esse": "2025.11.26-0", - "@mat3ra/made": "2025.7.15-0", "@mat3ra/standata": "git+https://github.com/Exabyte-io/standata.git#3c5b6365a6a5fcfbbd4e5da3a30cd5dd4c0301ee", + "@mat3ra/tsconfig": "2024.6.3-0", + "@mat3ra/utils": "2025.9.20-0", + "@types/crypto-js": "^4.2.2", "chai": "^4.3.4", - "eslint": "7.32.0", - "eslint-config-airbnb": "19.0.2", + "eslint": "^7.32.0", + "eslint-config-airbnb": "^19.0.2", "eslint-config-prettier": "^8.5.0", - "eslint-import-resolver-exports": "^1.0.0-beta.2", - "eslint-plugin-import": "2.25.3", - "eslint-plugin-jsdoc": "37.1.0", - "eslint-plugin-jsx-a11y": "6.5.1", + "eslint-import-resolver-exports": "^1.0.0-beta.5", + "eslint-import-resolver-meteor": "^0.4.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsdoc": "^37.1.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-mui-path-imports": "0.0.15", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "7.30.0", - "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-react": "^7.30.0", + "eslint-plugin-simple-import-sort": "^7.0.0", "husky": "^7.0.4", "lint-staged": "^12.1.2", "mocha": "^9.1.3", @@ -75,19 +79,25 @@ }, "peerDependencies": { "@mat3ra/ade": "*", + "@mat3ra/code": "*", + "@mat3ra/esse": "*", "@mat3ra/ide": "*", + "@mat3ra/made": "*", "@mat3ra/mode": "*", "@mat3ra/standata": "*", - "@mat3ra/utils": "*", - "@mat3ra/code": "*", - "@mat3ra/esse": "*", - "@mat3ra/made": "*" + "@mat3ra/utils": "*" }, "engines": { "node": ">=20.0.0" }, "lint-staged": { - "src/js/**/*.js": ["eslint --cache --fix", "prettier --write"], - "tests/js/**/*.js": ["eslint --cache --fix", "prettier --write"] + "src/js/**/*.js": [ + "eslint --cache --fix", + "prettier --write" + ], + "tests/js/**/*.js": [ + "eslint --cache --fix", + "prettier --write" + ] } } diff --git a/scripts/generate-mixins.ts b/scripts/generate-mixins.ts new file mode 100644 index 00000000..b62604b4 --- /dev/null +++ b/scripts/generate-mixins.ts @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +/** + * Script to generate mixin properties from JSON schema + * + * This script generates mixin functions for property/holder, property/meta_holder, + * and property/proto_holder schemas automatically. + * + * Usage: + * npx ts-node scripts/generate-mixin-properties.ts + */ + +import generateSchemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; +import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; +import type { JSONSchema7 } from "json-schema"; + +/** + * Output file paths for each schema + */ +const OUTPUT_PATHS = { + "workflow/unit/mixins/base": "src/js/generated/BaseUnitSchemaMixin.ts", + "system/status": "src/js/generated/StatusSchemaMixin.ts", + "workflow/unit/mixins/assertion": "src/js/generated/AssertionUnitSchemaMixin.ts", + "workflow/unit/mixins/assignment": "src/js/generated/AssignmentUnitSchemaMixin.ts", + "workflow/unit/mixins/condition": "src/js/generated/ConditionUnitSchemaMixin.ts", + "workflow/unit/mixins/execution": "src/js/generated/ExecutionUnitSchemaMixin.ts", + "workflow/unit/mixins/io": "src/js/generated/IOUnitSchemaMixin.ts", + "workflow/unit/mixins/map": "src/js/generated/MapUnitSchemaMixin.ts", + "workflow/unit/mixins/processing": "src/js/generated/ProcessingUnitSchemaMixin.ts", + "workflow/unit/mixins/reduce": "src/js/generated/ReduceUnitSchemaMixin.ts", + "workflow/unit/mixins/subworkflow": "src/js/generated/SubworkflowUnitSchemaMixin.ts", + "workflow/unit/input/-inputItem": "src/js/generated/ExecutionUnitInputSchemaMixin.ts", + "workflow/subworkflow/mixin": "src/js/generated/SubworkflowSchemaMixin.ts", +}; + +function main() { + // Type assertion to handle schema compatibility - the schemas from esse may have slightly different types + const result = generateSchemaMixin(allSchemas as JSONSchema7[], OUTPUT_PATHS); + + if (result.errorCount > 0) { + process.exit(1); + } +} + +// Run the script if it's executed directly +main(); diff --git a/src/js/ExecutionUnitInput.ts b/src/js/ExecutionUnitInput.ts new file mode 100644 index 00000000..0f6a0d62 --- /dev/null +++ b/src/js/ExecutionUnitInput.ts @@ -0,0 +1,89 @@ +import { Template } from "@mat3ra/ade"; +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; +import type { TemplateSchema } from "@mat3ra/esse/dist/js/types"; +import nunjucks from "nunjucks"; + +import { providers } from "./context/providers"; +import type { ContextItem, ContextProviderConfig } from "./context/providers/base/ContextProvider"; +import type ContextProvider from "./context/providers/base/ContextProvider"; +import type { ExecutionUnitInputSchemaMixin } from "./generated/ExecutionUnitInputSchemaMixin"; + +type Schema = ExecutionUnitInputSchemaMixin; + +type Base = typeof InMemoryEntity & Constructor; + +type ConstructorConfig = Schema | (Omit & { template: Template }); + +export default class ExecutionUnitInput extends (InMemoryEntity as Base) implements Schema { + declare _json: Schema & AnyObject; + + declare toJSON: () => Schema & AnyObject; + + declare toJSONQuick: () => Schema & AnyObject; + + static get jsonSchema() { + return JSONSchemasInterface.getSchemaById("workflow/unit/input/-inputItem"); + } + + contextProvidersInstances: ContextProvider[] = []; + + readonly templateInstance: Template; + + static createFromTemplate(template: Template | TemplateSchema) { + return new ExecutionUnitInput({ + template, + rendered: template.content, + isManuallyChanged: false, + }); + } + + constructor(config: ConstructorConfig) { + const { template } = config; + const templateInstance = template instanceof Template ? template : new Template(template); + + super({ ...config, template: templateInstance.toJSON() }); + + this.templateInstance = templateInstance; + } + + setContext(context: ContextItem[]) { + this.contextProvidersInstances = this.template.contextProviders.map(({ name }) => { + if (!providers) { + throw new Error("Providers config not set"); + } + + const ContextProvider = providers[name as keyof typeof providers]; + const contextItem = context.find((c) => c.name === name); + + if (!contextItem) { + throw new Error(`Context item for provider ${name} not found`); + } + + return new ContextProvider(contextItem); + }); + + return this; + } + + render() { + if (this.isManuallyChanged) { + return this; + } + + const fullContext = this.getFullContext(); + const rendered = nunjucks.compile(this.template.content).render(fullContext); + + this.rendered = rendered || this.template.content; + + return this; + } + + getFullContext() { + return this.contextProvidersInstances.map((contextProvider) => { + return contextProvider.getContextItem(); + }); + } +} diff --git a/src/js/RuntimeItemsUILogicMixin.ts b/src/js/RuntimeItemsUILogicMixin.ts new file mode 100644 index 00000000..09a9d2e7 --- /dev/null +++ b/src/js/RuntimeItemsUILogicMixin.ts @@ -0,0 +1,87 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { RuntimeItems } from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; +import type { NameResultSchema } from "@mat3ra/code/dist/js/utils/object"; +import type { RuntimeItemsSchema } from "@mat3ra/esse/dist/js/types"; + +type ItemKey = "results" | "monitors" | "preProcessors" | "postProcessors"; + +export type RuntimeItemsUILogic = { + setRuntimeItemsToDefaultValues(): void; + _initRuntimeItems(config?: Partial): void; + toggleRuntimeItem(key: ItemKey, data: NameResultSchema, isAdding: boolean): void; + toggleResult(data: NameResultSchema, isAdding: boolean): void; + toggleMonitor(data: NameResultSchema, isAdding: boolean): void; + togglePreProcessor(data: NameResultSchema, isAdding: boolean): void; + togglePostProcessor(data: NameResultSchema, isAdding: boolean): void; + getResultByName(name: string): NameResultSchema | undefined; + get resultNames(): string[]; + get monitorNames(): string[]; + get postProcessorNames(): string[]; + get preProcessorNames(): string[]; +}; + +type RuntimeItemsUILogicPrivate = { + toggleRuntimeItem(key: ItemKey, data: NameResultSchema, isAdding: boolean): void; +}; + +type Base = InMemoryEntity & + RuntimeItems & { + defaultResults: NameResultSchema[]; + defaultMonitors: NameResultSchema[]; + defaultPreProcessors: NameResultSchema[]; + defaultPostProcessors: NameResultSchema[]; + }; + +// @ts-expect-error +const propertiesMixn: Base & RuntimeItemsUILogic & RuntimeItemsUILogicPrivate = { + setRuntimeItemsToDefaultValues() { + this.results = this.defaultResults; + this.monitors = this.defaultMonitors; + this.preProcessors = this.defaultPreProcessors; + this.postProcessors = this.defaultPostProcessors; + }, + _initRuntimeItems(config) { + this.results = config?.results || this.defaultResults; + this.monitors = config?.monitors || this.defaultMonitors; + this.preProcessors = config?.preProcessors || this.defaultPreProcessors; + this.postProcessors = config?.postProcessors || this.defaultPostProcessors; + }, + toggleRuntimeItem(key: ItemKey, data: NameResultSchema, isAdding: boolean) { + if (isAdding) { + this[key] = [...this[key], data]; + } else { + this[key] = this[key].filter((x) => x.name !== data.name); + } + }, + toggleResult(data: NameResultSchema, isAdding: boolean) { + this.toggleRuntimeItem("results", data, isAdding); + }, + toggleMonitor(data: NameResultSchema, isAdding: boolean) { + this.toggleRuntimeItem("monitors", data, isAdding); + }, + togglePreProcessor(data: NameResultSchema, isAdding: boolean) { + this.toggleRuntimeItem("preProcessors", data, isAdding); + }, + togglePostProcessor(data: NameResultSchema, isAdding: boolean) { + this.toggleRuntimeItem("postProcessors", data, isAdding); + }, + get resultNames() { + return this.results.map((r) => r.name); + }, + get monitorNames() { + return this.monitors.map((r) => r?.name); + }, + get postProcessorNames() { + return this.postProcessors.map((r) => r.name); + }, + get preProcessorNames() { + return this.preProcessors.map((r) => r.name); + }, + getResultByName(name: string) { + return this.results.find((r) => r.name === name); + }, +}; + +export function runtimeItemsUILogicMixin(item: T) { + Object.defineProperties(item, Object.getOwnPropertyDescriptors(propertiesMixn)); +} diff --git a/src/js/context/context.js b/src/js/context/context.js deleted file mode 100644 index 86a6eb0c..00000000 --- a/src/js/context/context.js +++ /dev/null @@ -1,47 +0,0 @@ -import { BoundaryConditionsFormDataProvider } from "./providers/BoundaryConditionsFormDataProvider"; -import QENEBContextProvider from "./providers/by_application/espresso/QENEBContextProvider"; -import QEPWXContextProvider from "./providers/by_application/espresso/QEPWXContextProvider"; -import NWChemTotalEnergyContextProvider from "./providers/by_application/nwchem/NWChemTotalEnergyContextProvider"; -import VASPContextProvider from "./providers/by_application/vasp/VASPContextProvider"; -import VASPNEBContextProvider from "./providers/by_application/vasp/VASPNEBContextProvider"; -import { CollinearMagnetizationContextProvider } from "./providers/CollinearMagnetizationContextProvider"; -import { HubbardContextProviderLegacy } from "./providers/HubbardContextProviderLegacy"; -import { HubbardJContextProvider } from "./providers/HubbardJContextProvider"; -import { HubbardUContextProvider } from "./providers/HubbardUContextProvider"; -import { HubbardVContextProvider } from "./providers/HubbardVContextProvider"; -import { IonDynamicsContextProvider } from "./providers/IonDynamicsContextProvider"; -import { MLSettingsContextProvider } from "./providers/MLSettingsContextProvider"; -import { MLTrainTestSplitContextProvider } from "./providers/MLTrainTestSplitContextProvider"; -import { NEBFormDataProvider } from "./providers/NEBFormDataProvider"; -import { NonCollinearMagnetizationContextProvider } from "./providers/NonCollinearMagnetizationContextProvider"; -import { PlanewaveCutoffsContextProvider } from "./providers/PlanewaveCutoffsContextProvider"; -import { PointsGridFormDataProvider } from "./providers/PointsGridFormDataProvider"; -import { - ExplicitPointsPath2PIBAFormDataProvider, - ExplicitPointsPathFormDataProvider, - PointsPathFormDataProvider, -} from "./providers/PointsPathFormDataProvider"; - -export default { - BoundaryConditionsFormDataProvider, - MLSettingsContextProvider, - MLTrainTestSplitContextProvider, - NEBFormDataProvider, - PlanewaveCutoffsContextProvider, - PointsGridFormDataProvider, - PointsPathFormDataProvider, - ExplicitPointsPathFormDataProvider, - ExplicitPointsPath2PIBAFormDataProvider, - HubbardJContextProvider, - HubbardUContextProvider, - HubbardVContextProvider, - HubbardContextProviderLegacy, - IonDynamicsContextProvider, - CollinearMagnetizationContextProvider, - NonCollinearMagnetizationContextProvider, - VASPContextProvider, - VASPNEBContextProvider, - QEPWXContextProvider, - QENEBContextProvider, - NWChemTotalEnergyContextProvider, -}; diff --git a/src/js/context/mixins/ApplicationContextMixin.js b/src/js/context/mixins/ApplicationContextMixin.js deleted file mode 100644 index 76484ad4..00000000 --- a/src/js/context/mixins/ApplicationContextMixin.js +++ /dev/null @@ -1,19 +0,0 @@ -import { globalSettings } from "../providers/settings"; - -export function applicationContextMixin(item) { - const properties = { - _application: undefined, - - initApplicationContextMixin() { - this._application = - (this.config.context && this.config.context.application) || - globalSettings.Application.createDefault(); - }, - - get application() { - return this._application; - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/ApplicationContextMixin.ts b/src/js/context/mixins/ApplicationContextMixin.ts new file mode 100644 index 00000000..45d7475a --- /dev/null +++ b/src/js/context/mixins/ApplicationContextMixin.ts @@ -0,0 +1,27 @@ +import type { Application } from "@mat3ra/ade"; + +import type ContextProvider from "../providers/base/ContextProvider"; +import { globalSettings } from "../providers/settings"; + +export type ApplicationContextMixin = { + readonly application: Application; + initApplicationContextMixin(externalContext: ApplicationExternalContext): void; +}; + +type PrivateProperties = { + application?: Application; +}; + +export type ApplicationExternalContext = { application?: Application }; + +export function applicationContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: Provider & ApplicationContextMixin & PrivateProperties = { + initApplicationContextMixin(externalContext: ApplicationExternalContext) { + this.application = + externalContext.application ?? globalSettings.Application.createDefault(); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/ContextAndRenderFieldsMixin.ts b/src/js/context/mixins/ContextAndRenderFieldsMixin.ts new file mode 100644 index 00000000..ea4c7653 --- /dev/null +++ b/src/js/context/mixins/ContextAndRenderFieldsMixin.ts @@ -0,0 +1,53 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; + +export type Context = AnyObject; + +export type ContextMixin = { + context: Context; // persistent context + renderingContext: Context; + getRenderingContext(): Context; + updateRenderingContext(ctx: Context): void; + getPersistentContext(): Context; + updatePersistentContext(ctx: Context): void; + getCombinedContext(): Context; +}; + +type AbstractBase = { + render(ctx: Context): void; +}; + +export function contextMixin( + item: T, +): asserts item is T & ContextMixin { + // @ts-expect-error + const properties: InMemoryEntity & ContextMixin = { + get context() { + return this.requiredProp("context"); + }, + set context(ctx: Context) { + this.setProp("context", ctx); + }, + renderingContext: {}, + updateRenderingContext(ctx: Context) { + this.context = { ...this.renderingContext, ...ctx }; + }, + getRenderingContext() { + return this.renderingContext; + }, + getPersistentContext() { + return this.context; + }, + updatePersistentContext(ctx: Context) { + this.context = { ...ctx }; + }, + getCombinedContext() { + return { + ...this.getPersistentContext(), + ...this.getRenderingContext(), + }; + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/ImportantSettingsProviderMixin.ts b/src/js/context/mixins/ImportantSettingsProviderMixin.ts new file mode 100644 index 00000000..21f1d989 --- /dev/null +++ b/src/js/context/mixins/ImportantSettingsProviderMixin.ts @@ -0,0 +1,50 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { deepClone } from "@mat3ra/code/dist/js/utils/clone"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; + +export interface ContextProvider { + domain?: string; +} + +export type ImportantSettingsProvider = { + important: object; + setImportant(key: string, value: unknown): void; + importantSettingsProviders: ContextProvider[]; + isImportantEdited: boolean | undefined; +}; + +type AbstractBase = { + contextProviders: ContextProvider[]; +}; + +export type ImportantSettingsProviderInMemoryEntityConstructor = + Constructor; + +export function importantSettingsProviderMixin( + item: T, +): asserts item is T & ImportantSettingsProvider { + // @ts-expect-error + const properties: InMemoryEntity & AbstractBase & ImportantSettingsProvider = { + get important() { + return deepClone(this._json.important || {}); + }, + + setImportant(key: string, value: unknown) { + this.setProp("important", { [key]: value }); + }, + + get importantSettingsProviders() { + return this.contextProviders.filter((p) => p.domain === "important"); + }, + + get isImportantEdited() { + return this.prop("important.isEdited"); + }, + + set isImportantEdited(bool) { + this.setProp("important", Object.assign(this.important, { isEdited: bool })); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/JobContextMixin.js b/src/js/context/mixins/JobContextMixin.js deleted file mode 100644 index 19213fef..00000000 --- a/src/js/context/mixins/JobContextMixin.js +++ /dev/null @@ -1,36 +0,0 @@ -const defaultJob = { - workflow: { - subworkflows: [], - units: [], - }, - status: "pre-submission", - compute: { - queue: "D", - nodes: 1, - ppn: 1, - timeLimit: "3600", - }, - _project: { - _id: "", - }, -}; - -export function jobContextMixin(item) { - const properties = { - isEdited: false, - - _job: defaultJob, - - get job() { - return this._job; - }, - - initJobContextMixin() { - const { config } = this; - this._job = (config.context && config.context.job) || defaultJob; - this.isEdited = false; // we always get the `defaultData` (recalculated from scratch, not persistent) - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/JobContextMixin.ts b/src/js/context/mixins/JobContextMixin.ts new file mode 100644 index 00000000..49798e4c --- /dev/null +++ b/src/js/context/mixins/JobContextMixin.ts @@ -0,0 +1,27 @@ +import type { JobSchema } from "@mat3ra/esse/dist/js/types"; + +import type ContextProvider from "../providers/base/ContextProvider"; + +export type JobContextMixin = { + isEdited: boolean; + job: JobSchema; + initJobContextMixin(externalContext: JobExternalContext): void; +}; + +export type JobExternalContext = { + job: JobSchema; +}; + +export default function jobContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: ContextProvider & JobContextMixin = { + isEdited: false, + + initJobContextMixin(externalContext: JobExternalContext) { + this.job = externalContext.job; + this.isEdited = false; // we always get the `defaultData` (recalculated from scratch, not persistent) + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/MaterialContextMixin.js b/src/js/context/mixins/MaterialContextMixin.js deleted file mode 100644 index 6c0d6530..00000000 --- a/src/js/context/mixins/MaterialContextMixin.js +++ /dev/null @@ -1,41 +0,0 @@ -import { globalSettings } from "../providers/settings"; - -export function materialContextMixin(item) { - const properties = { - _material: undefined, - - updateMaterialHash() { - if (this.isEditedIsSetToFalseOnMaterialUpdate) this.isEdited = false; - this.extraData = { materialHash: this.material.hash }; - }, - - // Workaround: Material.createDefault() used to initiate workflow reducer and hence here too - // does not have an id. Here we catch when such material is used and avoid resetting isEdited - get isMaterialCreatedDefault() { - return !this.material.id; - }, - - get isMaterialUpdated() { - return Boolean(this.extraData && this.extraData.materialHash !== this.material.hash); - }, - - get material() { - if (!this._material) { - throw new Error("Material is not set"); - } - return this._material; - }, - - initMaterialContextMixin() { - this._material = this.config.context && this.config.context.material; - - if (!this._material) { - this._material = globalSettings.Material.createDefault(); - } - - this.updateMaterialHash(); - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/MaterialContextMixin.ts b/src/js/context/mixins/MaterialContextMixin.ts new file mode 100644 index 00000000..6346e1db --- /dev/null +++ b/src/js/context/mixins/MaterialContextMixin.ts @@ -0,0 +1,35 @@ +import type { OrderedInMemoryEntityInSet } from "@mat3ra/code/dist/js/entity/set/ordered/OrderedInMemoryEntityInSetMixin"; +import { Material } from "@mat3ra/made/dist/js/material"; + +import type ContextProvider from "../providers/base/ContextProvider"; + +export type OrderedMaterial = OrderedInMemoryEntityInSet & Material; + +export type MaterialContextMixin = { + readonly isMaterialCreatedDefault: boolean; + readonly isMaterialUpdated: boolean; + material: OrderedMaterial; + extraData?: { materialHash: string }; + initMaterialContextMixin(externalContext: MaterialExternalContext): void; + updateMaterialHash(): void; +}; + +export type MaterialExternalContext = { + material: OrderedMaterial; +}; + +export default function materialContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: ContextProvider & MaterialContextMixin = { + updateMaterialHash() { + this.extraData = { materialHash: this.material.hash }; + }, + + initMaterialContextMixin(externalContext: MaterialExternalContext) { + this.material = externalContext.material; + this.updateMaterialHash(); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/MaterialsContextMixin.js b/src/js/context/mixins/MaterialsContextMixin.js deleted file mode 100644 index 9ebc2e59..00000000 --- a/src/js/context/mixins/MaterialsContextMixin.js +++ /dev/null @@ -1,18 +0,0 @@ -import { globalSettings } from "../providers/settings"; - -export function materialsContextMixin(item) { - const properties = { - get materials() { - return this._materials; - }, - initMaterialsContextMixin() { - const materials = this.config.context?.materials; - this._materials = - materials && materials.length - ? materials - : [globalSettings.Material.createDefault()]; - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/MaterialsContextMixin.ts b/src/js/context/mixins/MaterialsContextMixin.ts new file mode 100644 index 00000000..d41478c5 --- /dev/null +++ b/src/js/context/mixins/MaterialsContextMixin.ts @@ -0,0 +1,24 @@ +import type ContextProvider from "../providers/base/ContextProvider"; +import type { OrderedMaterial } from "./MaterialContextMixin"; + +export type MaterialsContextMixin = { + materials: OrderedMaterial[]; + initMaterialsContextMixin(externalContext: MaterialsExternalContext): void; +}; + +export type MaterialsExternalContext = { + materials: OrderedMaterial[]; +}; + +export default function materialsContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: ContextProvider & MaterialsContextMixin = { + materials: [], + + initMaterialsContextMixin(externalContext: MaterialsExternalContext) { + this.materials = externalContext.materials; + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/MaterialsSetContextMixin.js b/src/js/context/mixins/MaterialsSetContextMixin.js deleted file mode 100644 index 35bef4fc..00000000 --- a/src/js/context/mixins/MaterialsSetContextMixin.js +++ /dev/null @@ -1,24 +0,0 @@ -import { compareEntitiesInOrderedSetForSorting } from "@mat3ra/code/dist/js/entity/set/ordered/utils"; - -export function materialsSetContextMixin(item) { - const properties = { - _materialsSet: undefined, - - get materialsSet() { - return this._materialsSet; - }, - - initMaterialsSetContextMixin() { - this._materialsSet = this.config.context?.materialsSet; - }, - - sortMaterialsByIndexInSet(materials = []) { - // DO NOT SORT IN PLACE AS IT CHANGES THE ORDER IN `this.materials` AND HAS SIDE EFFECTS (MaterialViewer). - return materials.concat().sort((a, b) => { - return compareEntitiesInOrderedSetForSorting(a, b, this.materialsSet._id, false); - }); - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/MaterialsSetContextMixin.ts b/src/js/context/mixins/MaterialsSetContextMixin.ts new file mode 100644 index 00000000..11113801 --- /dev/null +++ b/src/js/context/mixins/MaterialsSetContextMixin.ts @@ -0,0 +1,35 @@ +import { compareEntitiesInOrderedSetForSorting } from "@mat3ra/code/dist/js/entity/set/ordered/utils"; + +import type { OrderedMaterial } from "./MaterialContextMixin"; + +type MaterialsSet = { + _id: string; +}; + +export type MaterialsSetContextMixin = { + materialsSet: MaterialsSet; + initMaterialsSetContextMixin(externalContext: MaterialsSetContextProvider): void; + sortMaterialsByIndexInSet(materials?: OrderedMaterial[]): OrderedMaterial[]; +}; + +type MaterialsSetContextProvider = { + materialsSet: MaterialsSet; +}; + +export default function materialsSetContextMixin(item: MaterialsSetContextProvider) { + // @ts-expect-error + const properties: MaterialsSetContextProvider & MaterialsSetContextMixin = { + initMaterialsSetContextMixin(externalContext: MaterialsSetContextProvider) { + this.materialsSet = externalContext.materialsSet; + }, + + sortMaterialsByIndexInSet(materials: OrderedMaterial[] = []) { + // DO NOT SORT IN PLACE AS IT CHANGES THE ORDER IN `this.materials` AND HAS SIDE EFFECTS (MaterialViewer). + return materials.concat().sort((a, b) => { + return compareEntitiesInOrderedSetForSorting(a, b, this.materialsSet._id, false); + }); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/MethodDataContextMixin.js b/src/js/context/mixins/MethodDataContextMixin.js deleted file mode 100644 index 4443de20..00000000 --- a/src/js/context/mixins/MethodDataContextMixin.js +++ /dev/null @@ -1,48 +0,0 @@ -import CryptoJS from "crypto-js"; - -export function methodDataContextMixin(item) { - const properties = { - _methodData: undefined, - - isEdited: false, - - methodDataHash: undefined, - - extraData: undefined, - - initMethodDataContextMixin() { - this._methodData = (this.config.context && this.config.context.methodData) || {}; - this.isEdited = Boolean(this.config.isEdited); - }, - - /* @summary Replace the logic in constructor with this in order to enable passing `methodDataHash` between - * subsequent initializations of the derived class. Not used at present and kept for the record. - */ - _initMethodDataHash() { - this.methodDataHash = CryptoJS.MD5(JSON.stringify(this.methodData)).toString(); - this.extraData = { methodDataHash: this.methodDataHash }; - if (!this._methodData) { - this._methodData = {}; - this.isEdited = false; - // Commented out to reduce effect on performance. Uncomment for debugging purposes. - // TODO: remove on next refactoring or convert to log - // console.warn("MethodDataContextMixin: methodData is undefined or null"); - } else if (this.isMethodDataUpdated) { - this.isEdited = false; - } else { - // eslint-disable-next-line no-undef - this.isEdited = config.isEdited; - } - }, - - get methodData() { - return this._methodData; - }, - - get isMethodDataUpdated() { - return Boolean(this.extraData && this.extraData.methodDataHash !== this.methodDataHash); - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/MethodDataContextMixin.ts b/src/js/context/mixins/MethodDataContextMixin.ts new file mode 100644 index 00000000..c9d78a44 --- /dev/null +++ b/src/js/context/mixins/MethodDataContextMixin.ts @@ -0,0 +1,36 @@ +import type { BaseMethod } from "@mat3ra/esse/dist/js/types"; +import type { AtomicElementValue } from "@mat3ra/made/dist/js/basis/elements"; + +import type ContextProvider from "../providers/base/ContextProvider"; + +// TODO: create a task to define correct type for MethodData +type MethodData = BaseMethod["data"] & { + pseudo?: { element: AtomicElementValue; filename?: string; path?: string }[]; +}; + +export type MethodDataContextMixin = { + methodData: MethodData; + isEdited: boolean; + initMethodDataContextMixin(externalContext: MethodDataExternalContext): void; +}; + +export type MethodDataExternalContext = { + methodData?: MethodData; + isEdited?: boolean; +}; + +export default function methodDataContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: ContextProvider & MethodDataContextMixin = { + methodData: {}, + + isEdited: false, + + initMethodDataContextMixin(externalContext: MethodDataExternalContext) { + this.methodData = externalContext.methodData || {}; + this.isEdited = Boolean(externalContext?.isEdited); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/mixins/WorkflowContextMixin.js b/src/js/context/mixins/WorkflowContextMixin.js deleted file mode 100644 index c66c290c..00000000 --- a/src/js/context/mixins/WorkflowContextMixin.js +++ /dev/null @@ -1,25 +0,0 @@ -const defaultWorkflow = { - subworkflows: [], - units: [], - hasRelaxation: false, -}; - -export function workflowContextMixin(item) { - const properties = { - isEdited: false, - - _workflow: defaultWorkflow, - - get workflow() { - return this._workflow; - }, - - initWorkflowContextMixin() { - const { config } = this; // as WorkflowConfig; - this._workflow = (config.context && config.context.workflow) || defaultWorkflow; - this.isEdited = false; // we always get the `defaultData` (recalculated from scratch, not persistent) - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} diff --git a/src/js/context/mixins/WorkflowContextMixin.ts b/src/js/context/mixins/WorkflowContextMixin.ts new file mode 100644 index 00000000..a583d131 --- /dev/null +++ b/src/js/context/mixins/WorkflowContextMixin.ts @@ -0,0 +1,31 @@ +import type { WorkflowSchema } from "@mat3ra/esse/dist/js/types"; + +import type ContextProvider from "../providers/base/ContextProvider"; + +type Workflow = WorkflowSchema & { + hasRelaxation?: boolean; +}; + +export type WorkflowContextMixin = { + isEdited: boolean; + workflow: Workflow; + initWorkflowContextMixin(externalContext: WorkflowExternalContext): void; +}; + +export type WorkflowExternalContext = { + workflow: Workflow; +}; + +export default function workflowContextMixin(item: ContextProvider) { + // @ts-expect-error + const properties: ContextProvider & WorkflowContextMixin = { + isEdited: false, + + initWorkflowContextMixin(externalContext: WorkflowExternalContext) { + this.workflow = externalContext.workflow; + this.isEdited = false; + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/context/providers.js b/src/js/context/providers.js deleted file mode 100644 index 34157b35..00000000 --- a/src/js/context/providers.js +++ /dev/null @@ -1,140 +0,0 @@ -import context from "./context"; - -const { - BoundaryConditionsFormDataProvider, - MLSettingsContextProvider, - MLTrainTestSplitContextProvider, - NEBFormDataProvider, - PlanewaveCutoffsContextProvider, - PointsGridFormDataProvider, - PointsPathFormDataProvider, - ExplicitPointsPathFormDataProvider, - ExplicitPointsPath2PIBAFormDataProvider, - HubbardJContextProvider, - HubbardUContextProvider, - HubbardVContextProvider, - HubbardContextProviderLegacy, - IonDynamicsContextProvider, - CollinearMagnetizationContextProvider, - NonCollinearMagnetizationContextProvider, - VASPContextProvider, - VASPNEBContextProvider, - QEPWXContextProvider, - QENEBContextProvider, - NWChemTotalEnergyContextProvider, -} = context; - -const CONTEXT_DOMAINS = { - important: "important", // used to generate `ImportantSettings` form -}; - -const _makeImportant = (config) => Object.assign(config, { domain: CONTEXT_DOMAINS.important }); - -/** ******************************** - * Method-based context providers * - ********************************* */ - -export const wodeProviders = { - // NOTE: subworkflow-level data manager. Will override the unit-level data with the same name via subworkflow context. - PlanewaveCutoffDataManager: { - providerCls: PlanewaveCutoffsContextProvider, - config: _makeImportant({ name: "cutoffs", entityName: "subworkflow" }), - }, - KGridFormDataManager: { - providerCls: PointsGridFormDataProvider, - config: _makeImportant({ name: "kgrid" }), - }, - QGridFormDataManager: { - providerCls: PointsGridFormDataProvider, - config: _makeImportant({ name: "qgrid", divisor: 5 }), // Using less points for Qgrid by default - }, - IGridFormDataManager: { - providerCls: PointsGridFormDataProvider, - config: _makeImportant({ name: "igrid", divisor: 0.2 }), // Using more points for interpolated grid by default - }, - QPathFormDataManager: { - providerCls: PointsPathFormDataProvider, - config: _makeImportant({ name: "qpath" }), - }, - IPathFormDataManager: { - providerCls: PointsPathFormDataProvider, - config: _makeImportant({ name: "ipath" }), - }, - KPathFormDataManager: { - providerCls: PointsPathFormDataProvider, - config: _makeImportant({ name: "kpath" }), - }, - ExplicitKPathFormDataManager: { - providerCls: ExplicitPointsPathFormDataProvider, - config: _makeImportant({ name: "explicitKPath" }), - }, - ExplicitKPath2PIBAFormDataManager: { - providerCls: ExplicitPointsPath2PIBAFormDataProvider, - config: _makeImportant({ name: "explicitKPath2PIBA" }), - }, - HubbardJContextManager: { - providerCls: HubbardJContextProvider, - config: _makeImportant({ name: "hubbard_j" }), - }, - HubbardUContextManager: { - providerCls: HubbardUContextProvider, - config: _makeImportant({ name: "hubbard_u" }), - }, - HubbardVContextManager: { - providerCls: HubbardVContextProvider, - config: _makeImportant({ name: "hubbard_v" }), - }, - HubbardContextManagerLegacy: { - providerCls: HubbardContextProviderLegacy, - config: _makeImportant({ name: "hubbard_legacy" }), - }, - // NEBFormDataManager context is stored under the same key (`input`) as InputDataManager contexts. - NEBFormDataManager: { - providerCls: NEBFormDataProvider, - config: _makeImportant({ name: "neb" }), - }, - BoundaryConditionsFormDataManager: { - providerCls: BoundaryConditionsFormDataProvider, - config: _makeImportant({ name: "boundaryConditions" }), - }, - MLSettingsDataManager: { - providerCls: MLSettingsContextProvider, - config: _makeImportant({ name: "mlSettings" }), - }, - MLTrainTestSplitDataManager: { - providerCls: MLTrainTestSplitContextProvider, - config: _makeImportant({ name: "mlTrainTestSplit" }), - }, - IonDynamicsContextProvider: { - providerCls: IonDynamicsContextProvider, - config: _makeImportant({ name: "dynamics" }), - }, - CollinearMagnetizationDataManager: { - providerCls: CollinearMagnetizationContextProvider, - config: _makeImportant({ name: "collinearMagnetization" }), - }, - NonCollinearMagnetizationDataManager: { - providerCls: NonCollinearMagnetizationContextProvider, - config: _makeImportant({ name: "nonCollinearMagnetization" }), - }, - QEPWXInputDataManager: { - providerCls: QEPWXContextProvider, - config: { name: "input" }, - }, - QENEBInputDataManager: { - providerCls: QENEBContextProvider, - config: { name: "input" }, - }, - VASPInputDataManager: { - providerCls: VASPContextProvider, - config: { name: "input" }, - }, - VASPNEBInputDataManager: { - providerCls: VASPNEBContextProvider, - config: { name: "input" }, - }, - NWChemInputDataManager: { - providerCls: NWChemTotalEnergyContextProvider, - config: { name: "input" }, - }, -}; diff --git a/src/js/context/providers.ts b/src/js/context/providers.ts new file mode 100644 index 00000000..ec304edd --- /dev/null +++ b/src/js/context/providers.ts @@ -0,0 +1,183 @@ +// import type { ContextProviderNameEnum as ProviderName } from "@mat3ra/esse/dist/js/types"; + +// import type ContextProvider from "./providers/base/ContextProvider"; +// import type { ContextItem } from "./providers/base/ContextProvider"; +import BoundaryConditionsFormDataProvider from "./providers/BoundaryConditionsFormDataProvider"; +import QENEBContextProvider from "./providers/by_application/espresso/QENEBContextProvider"; +import QEPWXContextProvider from "./providers/by_application/espresso/QEPWXContextProvider"; +import NWChemTotalEnergyContextProvider from "./providers/by_application/nwchem/NWChemTotalEnergyContextProvider"; +import VASPContextProvider from "./providers/by_application/vasp/VASPContextProvider"; +import VASPNEBContextProvider from "./providers/by_application/vasp/VASPNEBContextProvider"; +import CollinearMagnetizationContextProvider from "./providers/CollinearMagnetizationContextProvider"; +import HubbardContextProviderLegacy from "./providers/Hubbard/HubbardContextProviderLegacy"; +import HubbardJContextProvider from "./providers/Hubbard/HubbardJContextProvider"; +import HubbardUContextProvider from "./providers/Hubbard/HubbardUContextProvider"; +import HubbardVContextProvider from "./providers/Hubbard/HubbardVContextProvider"; +import IonDynamicsContextProvider from "./providers/IonDynamicsContextProvider"; +import MLSettingsContextProvider from "./providers/MLSettingsContextProvider"; +import MLTrainTestSplitContextProvider from "./providers/MLTrainTestSplitContextProvider"; +import NEBFormDataProvider from "./providers/NEBFormDataProvider"; +import NonCollinearMagnetizationContextProvider from "./providers/NonCollinearMagnetizationContextProvider"; +import PlanewaveCutoffsContextProvider from "./providers/PlanewaveCutoffsContextProvider"; +import IGridFormDataManager from "./providers/PointsGrid/IGridFormDataManager"; +import KGridFormDataManager from "./providers/PointsGrid/KGridFormDataManager"; +import QGridFormDataManager from "./providers/PointsGrid/QGridFormDataManager"; +import ExplicitKPath2PIBAFormDataManager from "./providers/PointsPath/ExplicitKPath2PIBAFormDataManager"; +import ExplicitKPathFormDataManager from "./providers/PointsPath/ExplicitKPathFormDataManager"; +import IPathFormDataManager from "./providers/PointsPath/IPathFormDataManager"; +import KPathFormDataManager from "./providers/PointsPath/KPathFormDataManager"; +import QPathFormDataManager from "./providers/PointsPath/QPathFormDataManager"; + +// const CONTEXT_DOMAINS = { +// important: "important", // used to generate `ImportantSettings` form +// }; + +// export type ProvidersConfig = Record< +// ProviderName, +// new ( +// config: ContextItem, +// domain?: string, +// entityName?: "unit" | "subworkflow", +// ) => ContextProvider +// >; + +/** ******************************** + * Method-based context providers * + ********************************* */ + +// export const wodeProviders = { +// // NOTE: subworkflow-level data manager. Will override the unit-level data with the same name via subworkflow context. +// PlanewaveCutoffDataManager: { +// providerCls: PlanewaveCutoffsContextProvider, +// config: _makeImportant({ name: "cutoffs", entityName: "subworkflow" }), +// }, +// KGridFormDataManager: { +// providerCls: PointsGridFormDataProvider, +// config: _makeImportant({ name: "kgrid" }), +// }, +// QGridFormDataManager: { +// providerCls: PointsGridFormDataProvider, +// config: _makeImportant({ name: "qgrid", divisor: 5 }), // Using less points for Qgrid by default +// }, +// IGridFormDataManager: { +// providerCls: PointsGridFormDataProvider, +// config: _makeImportant({ name: "igrid", divisor: 0.2 }), // Using more points for interpolated grid by default +// }, +// QPathFormDataManager: { +// providerCls: PointsPathFormDataProvider, +// config: _makeImportant({ name: "qpath" }), +// }, +// IPathFormDataManager: { +// providerCls: PointsPathFormDataProvider, +// config: _makeImportant({ name: "ipath" }), +// }, +// KPathFormDataManager: { +// providerCls: PointsPathFormDataProvider, +// config: _makeImportant({ name: "kpath" }), +// }, +// ExplicitKPathFormDataManager: { +// providerCls: ExplicitPointsPathFormDataProvider, +// config: _makeImportant({ name: "explicitKPath" }), +// }, +// ExplicitKPath2PIBAFormDataManager: { +// providerCls: ExplicitPointsPath2PIBAFormDataProvider, +// config: _makeImportant({ name: "explicitKPath2PIBA" }), +// }, +// HubbardJContextManager: { +// providerCls: HubbardJContextProvider, +// config: _makeImportant({ name: "hubbard_j" }), +// }, +// HubbardUContextManager: { +// providerCls: HubbardUContextProvider, +// config: _makeImportant({ name: "hubbard_u" }), +// }, +// HubbardVContextManager: { +// providerCls: HubbardVContextProvider, +// config: _makeImportant({ name: "hubbard_v" }), +// }, +// HubbardContextManagerLegacy: { +// providerCls: HubbardContextProviderLegacy, +// config: _makeImportant({ name: "hubbard_legacy" }), +// }, +// // NEBFormDataManager context is stored under the same key (`input`) as InputDataManager contexts. +// NEBFormDataManager: { +// providerCls: NEBFormDataProvider, +// config: _makeImportant({ name: "neb" }), +// }, +// BoundaryConditionsFormDataManager: { +// providerCls: BoundaryConditionsFormDataProvider, +// config: _makeImportant({ name: "boundaryConditions" }), +// }, +// MLSettingsDataManager: { +// providerCls: MLSettingsContextProvider, +// config: _makeImportant({ name: "mlSettings" }), +// }, +// MLTrainTestSplitDataManager: { +// providerCls: MLTrainTestSplitContextProvider, +// config: _makeImportant({ name: "mlTrainTestSplit" }), +// }, +// IonDynamicsContextProvider: { +// providerCls: IonDynamicsContextProvider, +// config: _makeImportant({ name: "dynamics" }), +// }, +// CollinearMagnetizationDataManager: { +// providerCls: CollinearMagnetizationContextProvider, +// config: _makeImportant({ name: "collinearMagnetization" }), +// }, +// NonCollinearMagnetizationDataManager: { +// providerCls: NonCollinearMagnetizationContextProvider, +// config: _makeImportant({ name: "nonCollinearMagnetization" }), +// }, +// QEPWXInputDataManager: { +// providerCls: QEPWXContextProvider, +// config: { name: "input" }, +// }, +// QENEBInputDataManager: { +// providerCls: QENEBContextProvider, +// config: { name: "input" }, +// }, +// VASPInputDataManager: { +// providerCls: VASPContextProvider, +// config: { name: "input" }, +// }, +// VASPNEBInputDataManager: { +// providerCls: VASPNEBContextProvider, +// config: { name: "input" }, +// }, +// NWChemInputDataManager: { +// providerCls: NWChemTotalEnergyContextProvider, +// config: { name: "input" }, +// }, +// }; + +export const newWodeProviders = { + PlanewaveCutoffDataManager: PlanewaveCutoffsContextProvider, + + KGridFormDataManager, + QGridFormDataManager, + IGridFormDataManager, + + QPathFormDataManager, + IPathFormDataManager, + KPathFormDataManager, + ExplicitKPathFormDataManager, + ExplicitKPath2PIBAFormDataManager, + + HubbardJContextManager: HubbardJContextProvider, + HubbardUContextManager: HubbardUContextProvider, + HubbardVContextManager: HubbardVContextProvider, + HubbardContextManagerLegacy: HubbardContextProviderLegacy, + NEBFormDataManager: NEBFormDataProvider, + BoundaryConditionsFormDataManager: BoundaryConditionsFormDataProvider, + MLSettingsDataManager: MLSettingsContextProvider, + MLTrainTestSplitDataManager: MLTrainTestSplitContextProvider, + IonDynamicsContextProvider, + CollinearMagnetizationDataManager: CollinearMagnetizationContextProvider, + NonCollinearMagnetizationDataManager: NonCollinearMagnetizationContextProvider, + + QEPWXInputDataManager: QEPWXContextProvider, + QENEBInputDataManager: QENEBContextProvider, + VASPInputDataManager: VASPContextProvider, + VASPNEBInputDataManager: VASPNEBContextProvider, + NWChemInputDataManager: NWChemTotalEnergyContextProvider, +}; diff --git a/src/js/context/providers/BoundaryConditionsFormDataProvider.js b/src/js/context/providers/BoundaryConditionsFormDataProvider.js deleted file mode 100644 index 1f166d49..00000000 --- a/src/js/context/providers/BoundaryConditionsFormDataProvider.js +++ /dev/null @@ -1,72 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import { Made } from "@mat3ra/made"; -import { Utils } from "@mat3ra/utils"; - -import { materialContextMixin } from "../mixins/MaterialContextMixin"; - -export class BoundaryConditionsFormDataProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/boundary-conditions-data-provider"; - - constructor(config) { - super(config); - this.initMaterialContextMixin(); - } - - get boundaryConditions() { - return this.material.metadata.boundaryConditions || {}; - } - - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { - type: this.boundaryConditions.type || "pbc", - offset: this.boundaryConditions.offset || 0, - electricField: 0, - targetFermiEnergy: 0, - }; - } - - get jsonSchemaPatchConfig() { - const defaults = this.defaultData; - return { - type: { default: defaults.type }, - offset: { default: defaults.offset }, - electricField: { default: defaults.electricField }, - targetFermiEnergy: { default: defaults.targetFermiEnergy }, - }; - } - - // TODO: MOVE to WA/wove instantiation - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - type: { "ui:disabled": true }, - offset: { "ui:disabled": true }, - electricField: {}, - targetFermiEnergy: {}, - }; - } - - // eslint-disable-next-line class-methods-use-this - get humanName() { - return "Boundary Conditions"; - } - - yieldDataForRendering() { - const data = Utils.clone.deepClone(this.yieldData()); - data.boundaryConditions.offset *= Made.coefficients.ANGSTROM_TO_BOHR; - data.boundaryConditions.targetFermiEnergy *= Made.coefficients.EV_TO_RY; - data.boundaryConditions.electricField *= Made.coefficients.EV_A_TO_RY_BOHR; - return data; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -materialContextMixin(BoundaryConditionsFormDataProvider.prototype); diff --git a/src/js/context/providers/BoundaryConditionsFormDataProvider.ts b/src/js/context/providers/BoundaryConditionsFormDataProvider.ts new file mode 100644 index 00000000..daa1008a --- /dev/null +++ b/src/js/context/providers/BoundaryConditionsFormDataProvider.ts @@ -0,0 +1,67 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { BoundaryConditionsDataProviderSchema } from "@mat3ra/esse/dist/js/types"; + +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "./base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./base/JSONSchemaDataProvider"; + +type Name = "boundaryConditions"; +type Data = BoundaryConditionsDataProviderSchema; +type ExternalContext = JinjaExternalContext & MaterialExternalContext; +type Base = typeof JSONSchemaDataProvider & + Constructor; + +const jsonSchemaId = "context-providers-directory/boundary-conditions-data-provider"; + +export default class BoundaryConditionsFormDataProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "boundaryConditions"; + + readonly domain: Domain = "important"; + + readonly humanName = "Boundary Conditions"; + + readonly uiSchema = { + type: { "ui:disabled": true }, + offset: { "ui:disabled": true }, + electricField: {}, + targetFermiEnergy: {}, + }; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + } + + getDefaultData(): Data { + return { + type: this.material?.metadata?.boundaryConditions?.type || "pbc", + offset: this.material?.metadata?.boundaryConditions?.offset || 0, + electricField: 0, + targetFermiEnergy: 0, + }; + } + + // yieldDataForRendering() { + // const data = Utils.clone.deepClone(this.getContextItem()); + // data.boundaryConditions.offset *= Made.coefficients.ANGSTROM_TO_BOHR; + // data.boundaryConditions.targetFermiEnergy *= Made.coefficients.EV_TO_RY; + // data.boundaryConditions.electricField *= Made.coefficients.EV_A_TO_RY_BOHR; + // return data; + // } + + get jsonSchema() { + const defaults = this.getDefaultData(); + return JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + type: { default: defaults.type }, + offset: { default: defaults.offset }, + electricField: { default: defaults.electricField }, + targetFermiEnergy: { default: defaults.targetFermiEnergy }, + }); + } +} + +materialContextMixin(BoundaryConditionsFormDataProvider.prototype); diff --git a/src/js/context/providers/CollinearMagnetizationContextProvider.js b/src/js/context/providers/CollinearMagnetizationContextProvider.js deleted file mode 100644 index c1bab35b..00000000 --- a/src/js/context/providers/CollinearMagnetizationContextProvider.js +++ /dev/null @@ -1,105 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import lodash from "lodash"; - -import { materialContextMixin } from "../mixins/MaterialContextMixin"; - -export class CollinearMagnetizationContextProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/collinear-magnetization-context-provider"; - - constructor(config) { - super(config); - - this.initMaterialContextMixin(); - - this.firstElement = - this.uniqueElementsWithLabels?.length > 0 ? this.uniqueElementsWithLabels[0] : ""; - this.isTotalMagnetization = lodash.get(this.data, "isTotalMagnetization", false); - } - - get uniqueElementsWithLabels() { - const elementsWithLabelsArray = this.material?.Basis?.elementsWithLabelsArray || []; - return [...new Set(elementsWithLabelsArray)]; - } - - indexOfElement = (element) => { - return this.uniqueElementsWithLabels.indexOf(element) + 1; - }; - - get defaultData() { - return { - startingMagnetization: [ - { - index: 1, - atomicSpecies: this.firstElement, - value: 0.0, - }, - ], - isTotalMagnetization: false, - totalMagnetization: 0.0, - }; - } - - get jsonSchemaPatchConfig() { - return { - "properties.startingMagnetization": { - maxItems: this.uniqueElementsWithLabels.length, - }, - "properties.startingMagnetization.items.properties.atomicSpecies": { - enum: this.uniqueElementsWithLabels, - default: this.firstElement, - }, - "properties.startingMagnetization.items.properties.value": { - default: 0.0, - }, - "properties.isTotalMagnetization": { - default: false, - }, - "properties.totalMagnetization": { - default: 0.0, - }, - }; - } - - transformData = (data) => { - const startingMagnetizationWithIndex = data.startingMagnetization.map((row) => ({ - ...row, - index: this.indexOfElement(row.atomicSpecies), - })); - - return { - ...data, - startingMagnetization: startingMagnetizationWithIndex, - }; - }; - - get uiSchemaStyled() { - return { - startingMagnetization: { - items: { - atomicSpecies: { - "ui:classNames": "col-xs-3", - }, - value: { - "ui:classNames": "col-xs-6", - }, - }, - "ui:readonly": this.isTotalMagnetization, - }, - isTotalMagnetization: {}, - totalMagnetization: { - "ui:classNames": "col-xs-6", - "ui:readonly": !this.isTotalMagnetization, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -materialContextMixin(CollinearMagnetizationContextProvider.prototype); diff --git a/src/js/context/providers/CollinearMagnetizationContextProvider.ts b/src/js/context/providers/CollinearMagnetizationContextProvider.ts new file mode 100644 index 00000000..4ab7b989 --- /dev/null +++ b/src/js/context/providers/CollinearMagnetizationContextProvider.ts @@ -0,0 +1,115 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { CollinearMagnetizationContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "./base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./base/JSONSchemaDataProvider"; + +type Name = "collinearMagnetization"; +type Data = CollinearMagnetizationContextProviderSchema; +type ExternalContext = JinjaExternalContext & MaterialExternalContext; +type Base = typeof JSONSchemaDataProvider & + Constructor; + +const jsonSchemaId = "context-providers-directory/collinear-magnetization-context-provider"; + +export default class CollinearMagnetizationContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "collinearMagnetization"; + + readonly domain: Domain = "important"; + + readonly jsonSchema: JSONSchema7 | undefined; + + private readonly isTotalMagnetization: boolean; + + private readonly firstElement: string; + + private readonly uniqueElementsWithLabels: string[]; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + + this.uniqueElementsWithLabels = [ + ...new Set(this.material?.Basis?.elementsWithLabelsArray || []), + ]; + + this.firstElement = + this.uniqueElementsWithLabels?.length > 0 ? this.uniqueElementsWithLabels[0] : ""; + + this.isTotalMagnetization = this.data?.isTotalMagnetization || false; + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + "properties.startingMagnetization": { + maxItems: this.uniqueElementsWithLabels.length, + }, + "properties.startingMagnetization.items.properties.atomicSpecies": { + enum: this.uniqueElementsWithLabels, + default: this.firstElement, + }, + "properties.startingMagnetization.items.properties.value": { + default: 0.0, + }, + "properties.isTotalMagnetization": { + default: false, + }, + "properties.totalMagnetization": { + default: 0.0, + }, + }); + } + + getDefaultData(): Data { + return { + startingMagnetization: [ + { + index: 1, + atomicSpecies: this.firstElement, + value: 0.0, + }, + ], + isTotalMagnetization: false, + totalMagnetization: 0.0, + }; + } + + setData(data: Data) { + const startingMagnetization = data.startingMagnetization.map((row) => ({ + ...row, + index: this.uniqueElementsWithLabels.indexOf(row.atomicSpecies) + 1, + })); + + super.setData({ + ...data, + startingMagnetization, + }); + } + + get uiSchemaStyled() { + return { + startingMagnetization: { + items: { + atomicSpecies: { + "ui:classNames": "col-xs-3", + }, + value: { + "ui:classNames": "col-xs-6", + }, + }, + "ui:readonly": this.isTotalMagnetization, + }, + isTotalMagnetization: {}, + totalMagnetization: { + "ui:classNames": "col-xs-6", + "ui:readonly": !this.isTotalMagnetization, + }, + }; + } +} + +materialContextMixin(CollinearMagnetizationContextProvider.prototype); diff --git a/src/js/context/providers/Hubbard/HubbardContextProvider.ts b/src/js/context/providers/Hubbard/HubbardContextProvider.ts new file mode 100644 index 00000000..39648163 --- /dev/null +++ b/src/js/context/providers/Hubbard/HubbardContextProvider.ts @@ -0,0 +1,73 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; + +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "../base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "../base/JSONSchemaDataProvider"; + +type HubbardName = "hubbard_u" | "hubbard_j" | "hubbard_v" | "hubbard_legacy"; + +export type HubbardExternalContext = JinjaExternalContext & MaterialExternalContext; + +type Base = typeof JSONSchemaDataProvider & + Constructor; + +export default abstract class HubbardContextProvider< + N extends HubbardName, + D extends object, + EC extends HubbardExternalContext = HubbardExternalContext, +> extends (JSONSchemaDataProvider as Base) { + abstract readonly name: N; + + abstract getDefaultData(): D; + + readonly domain: Domain = "important"; + + protected readonly uniqueElementsWithLabels: string[]; + + protected readonly firstElement: string; + + protected readonly secondSpecies: string; + + protected readonly orbitalList = [ + "2p", + "3s", + "3p", + "3d", + "4s", + "4p", + "4d", + "4f", + "5s", + "5p", + "5d", + "5f", + "6s", + "6p", + "6d", + "7s", + "7p", + "7d", + ]; + + constructor(contextItem: ContextItem, externalContext: EC) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + + this.uniqueElementsWithLabels = [ + ...new Set(this.material.Basis?.elementsWithLabelsArray || []), + ]; + + this.firstElement = + this.uniqueElementsWithLabels?.length > 0 ? this.uniqueElementsWithLabels[0] : ""; + + this.secondSpecies = + this.uniqueElementsWithLabels?.length > 1 + ? this.uniqueElementsWithLabels[1] + : this.firstElement; + } +} + +materialContextMixin(HubbardContextProvider.prototype); diff --git a/src/js/context/providers/Hubbard/HubbardContextProviderLegacy.ts b/src/js/context/providers/Hubbard/HubbardContextProviderLegacy.ts new file mode 100644 index 00000000..0b60691a --- /dev/null +++ b/src/js/context/providers/Hubbard/HubbardContextProviderLegacy.ts @@ -0,0 +1,73 @@ +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { HubbardLegacyContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import type { ContextItem, Domain } from "../base/ContextProvider"; +import HubbardContextProvider, { type HubbardExternalContext } from "./HubbardContextProvider"; + +type Name = "hubbard_legacy"; +type Data = HubbardLegacyContextProviderSchema; + +const defaultHubbardConfig = { + hubbardUValue: 1.0, +}; + +const jsonSchemaId = "context-providers-directory/hubbard-legacy-context-provider"; + +export default class HubbardContextProviderLegacy extends HubbardContextProvider { + readonly name: Name = "hubbard_legacy"; + + readonly domain: Domain = "important"; + + readonly jsonSchema: JSONSchema7 | undefined; + + readonly uiSchemaStyled = { + "ui:options": { + addable: true, + orderable: false, + removable: true, + }, + items: { + atomicSpeciesIndex: { "ui:readonly": true }, + }, + }; + + constructor(contextItem: ContextItem, externalContext: HubbardExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + "items.properties.atomicSpecies": { + enum: this.uniqueElementsWithLabels, + }, + "items.properties.hubbardUValue": { + default: defaultHubbardConfig.hubbardUValue, + }, + }); + } + + getDefaultData(): Data { + return [ + { + ...defaultHubbardConfig, + atomicSpecies: this.firstElement, + atomicSpeciesIndex: this.uniqueElementsWithLabels?.length > 0 ? 1 : undefined, + }, + ]; + } + + setData(data: Data) { + const hubbardUValues = data.map((row) => { + const atomicSpeciesIndex = + this.uniqueElementsWithLabels?.length > 0 + ? this.uniqueElementsWithLabels.indexOf(row.atomicSpecies || "") + 1 + : undefined; + + return { + ...row, + atomicSpeciesIndex, + }; + }) as Data; + + super.setData(hubbardUValues); + } +} diff --git a/src/js/context/providers/Hubbard/HubbardJContextProvider.ts b/src/js/context/providers/Hubbard/HubbardJContextProvider.ts new file mode 100644 index 00000000..9eaa9a4e --- /dev/null +++ b/src/js/context/providers/Hubbard/HubbardJContextProvider.ts @@ -0,0 +1,62 @@ +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { HubbardJContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import type { ContextItem } from "../base/ContextProvider"; +import HubbardContextProvider, { type HubbardExternalContext } from "./HubbardContextProvider"; + +type Name = "hubbard_j"; +type Data = HubbardJContextProviderSchema; + +const defaultHubbardConfig = { + paramType: "J" as const, + atomicSpecies: "", + atomicOrbital: "2p", + value: 1.0, +}; + +const jsonSchemaId = "context-providers-directory/hubbard-j-context-provider"; + +export default class HubbardJContextProvider extends HubbardContextProvider { + readonly name: Name = "hubbard_j"; + + readonly uiSchemaStyled = { + "ui:options": { + addable: true, + orderable: true, + removable: true, + }, + }; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(contextItem: ContextItem, externalContext: HubbardExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + "items.properties.paramType": { + default: defaultHubbardConfig.paramType, + }, + "items.properties.atomicSpecies": { + enum: this.uniqueElementsWithLabels, + default: this.firstElement, + }, + "items.properties.atomicOrbital": { + enum: this.orbitalList, + default: defaultHubbardConfig.atomicOrbital, + }, + "items.properties.value": { + default: defaultHubbardConfig.value, + }, + }); + } + + getDefaultData(): Data { + return [ + { + ...defaultHubbardConfig, + atomicSpecies: this.firstElement, + }, + ]; + } +} diff --git a/src/js/context/providers/Hubbard/HubbardUContextProvider.ts b/src/js/context/providers/Hubbard/HubbardUContextProvider.ts new file mode 100644 index 00000000..259d16dc --- /dev/null +++ b/src/js/context/providers/Hubbard/HubbardUContextProvider.ts @@ -0,0 +1,61 @@ +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { HubbardUContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import materialContextMixin from "../../mixins/MaterialContextMixin"; +import type { ContextItem } from "../base/ContextProvider"; +import HubbardContextProvider, { type HubbardExternalContext } from "./HubbardContextProvider"; + +type Name = "hubbard_u"; +type Data = HubbardUContextProviderSchema; + +const defaultHubbardConfig = { + atomicSpecies: "", + atomicOrbital: "2p", + hubbardUValue: 1.0, +}; + +const jsonSchemaId = "context-providers-directory/hubbard-u-context-provider"; + +export default class HubbardUContextProvider extends HubbardContextProvider { + readonly name: Name = "hubbard_u"; + + readonly uiSchemaStyled = { + "ui:options": { + addable: true, + orderable: false, + removable: true, + }, + }; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(contextItem: ContextItem, externalContext: HubbardExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + "items.properties.atomicSpecies": { + enum: this.uniqueElementsWithLabels, + default: this.firstElement, + }, + "items.properties.atomicOrbital": { + enum: this.orbitalList, + default: defaultHubbardConfig.atomicOrbital, + }, + "items.properties.hubbardUValue": { + default: defaultHubbardConfig.hubbardUValue, + }, + }); + } + + getDefaultData(): Data { + return [ + { + ...defaultHubbardConfig, + atomicSpecies: this.firstElement, + }, + ]; + } +} + +materialContextMixin(HubbardUContextProvider.prototype); diff --git a/src/js/context/providers/HubbardVContextProvider.js b/src/js/context/providers/Hubbard/HubbardVContextProvider.ts similarity index 53% rename from src/js/context/providers/HubbardVContextProvider.js rename to src/js/context/providers/Hubbard/HubbardVContextProvider.ts index 6f922344..6403d2f2 100644 --- a/src/js/context/providers/HubbardVContextProvider.js +++ b/src/js/context/providers/Hubbard/HubbardVContextProvider.ts @@ -1,6 +1,12 @@ import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { HubbardVContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; -import { HubbardUContextProvider } from "./HubbardUContextProvider"; +import type { ContextItem } from "../base/ContextProvider"; +import HubbardContextProvider, { type HubbardExternalContext } from "./HubbardContextProvider"; + +type Name = "hubbard_v"; +type Data = HubbardVContextProviderSchema; const defaultHubbardConfig = { atomicSpecies: "", @@ -12,36 +18,28 @@ const defaultHubbardConfig = { hubbardVValue: 1.0, }; -export class HubbardVContextProvider extends HubbardUContextProvider { - jsonSchemaId = "context-providers-directory/hubbard-v-context-provider"; +const jsonSchemaId = "context-providers-directory/hubbard-v-context-provider"; - get defaultData() { - return [ - { - ...defaultHubbardConfig, - atomicSpecies: this.firstSpecies, - atomicSpecies2: this.secondSpecies, - siteIndex2: - this.uniqueElementsWithLabels?.length > 1 ? 2 : defaultHubbardConfig.siteIndex2, - }, - ]; - } +export default class HubbardVContextProvider extends HubbardContextProvider { + readonly name: Name = "hubbard_v"; - get firstSpecies() { - return this.firstElement; - } + readonly uiSchemaStyled = { + "ui:options": { + addable: true, + orderable: true, + removable: true, + }, + }; - get secondSpecies() { - return this.uniqueElementsWithLabels?.length > 1 - ? this.uniqueElementsWithLabels[1] - : this.firstSpecies; - } + readonly jsonSchema: JSONSchema7 | undefined; - get jsonSchemaPatchConfig() { - return { + constructor(contextItem: ContextItem, externalContext: HubbardExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { "items.properties.atomicSpecies": { enum: this.uniqueElementsWithLabels, - default: this.firstSpecies, + default: this.firstElement, }, "items.properties.siteIndex": { default: defaultHubbardConfig.siteIndex, @@ -65,32 +63,18 @@ export class HubbardVContextProvider extends HubbardUContextProvider { "items.properties.hubbardVValue": { default: defaultHubbardConfig.hubbardVValue, }, - }; + }); } - get uiSchemaStyled() { - return { - "ui:options": { - addable: true, - orderable: true, - removable: true, - }, - items: { - atomicSpecies: this.defaultFieldStyles, - atomicOrbital: this.defaultFieldStyles, - atomicSpecies2: this.defaultFieldStyles, - atomicOrbital2: this.defaultFieldStyles, - siteIndex: this.defaultFieldStyles, - siteIndex2: this.defaultFieldStyles, - hubbardVValue: this.defaultFieldStyles, + getDefaultData(): Data { + return [ + { + ...defaultHubbardConfig, + atomicSpecies: this.firstElement, + atomicSpecies2: this.secondSpecies, + siteIndex2: + this.uniqueElementsWithLabels?.length > 1 ? 2 : defaultHubbardConfig.siteIndex2, }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); + ]; } } diff --git a/src/js/context/providers/HubbardContextProviderLegacy.js b/src/js/context/providers/HubbardContextProviderLegacy.js deleted file mode 100644 index cda86636..00000000 --- a/src/js/context/providers/HubbardContextProviderLegacy.js +++ /dev/null @@ -1,67 +0,0 @@ -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { HubbardUContextProvider } from "./HubbardUContextProvider"; - -const defaultHubbardConfig = { - hubbardUValue: 1.0, -}; - -export class HubbardContextProviderLegacy extends HubbardUContextProvider { - jsonSchemaId = "context-providers-directory/hubbard-legacy-context-provider"; - - get defaultData() { - return [ - { - ...defaultHubbardConfig, - atomicSpecies: this.firstElement, - atomicSpeciesIndex: this.uniqueElementsWithLabels?.length > 0 ? 1 : null, - }, - ]; - } - - get jsonSchemaPatchConfig() { - return { - "items.properties.atomicSpecies": { - enum: this.uniqueElementsWithLabels, - }, - "items.properties.hubbardUValue": { - default: defaultHubbardConfig.hubbardUValue, - }, - }; - } - - speciesIndexFromSpecies = (species) => { - return this.uniqueElementsWithLabels?.length > 0 - ? this.uniqueElementsWithLabels.indexOf(species) + 1 - : null; - }; - - transformData = (data) => { - return data.map((row) => ({ - ...row, - atomicSpeciesIndex: this.speciesIndexFromSpecies(row.atomicSpecies), - })); - }; - - get uiSchemaStyled() { - return { - "ui:options": { - addable: true, - orderable: false, - removable: true, - }, - items: { - atomicSpecies: this.defaultFieldStyles, - atomicSpeciesIndex: { ...this.defaultFieldStyles, "ui:readonly": true }, - hubbardUValue: this.defaultFieldStyles, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} diff --git a/src/js/context/providers/HubbardJContextProvider.js b/src/js/context/providers/HubbardJContextProvider.js deleted file mode 100644 index ea0b43a3..00000000 --- a/src/js/context/providers/HubbardJContextProvider.js +++ /dev/null @@ -1,65 +0,0 @@ -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { HubbardUContextProvider } from "./HubbardUContextProvider"; - -const defaultHubbardConfig = { - paramType: "U", - atomicSpecies: "", - atomicOrbital: "2p", - value: 1.0, -}; - -export class HubbardJContextProvider extends HubbardUContextProvider { - jsonSchemaId = "context-providers-directory/hubbard-j-context-provider"; - - get defaultData() { - return [ - { - ...defaultHubbardConfig, - atomicSpecies: this.firstElement, - }, - ]; - } - - get jsonSchemaPatchConfig() { - return { - "items.properties.paramType": { - default: defaultHubbardConfig.paramType, - }, - "items.properties.atomicSpecies": { - enum: this.uniqueElementsWithLabels, - default: this.firstElement, - }, - "items.properties.atomicOrbital": { - enum: this.orbitalList, - default: defaultHubbardConfig.atomicOrbital, - }, - "items.properties.value": { - default: defaultHubbardConfig.value, - }, - }; - } - - get uiSchemaStyled() { - return { - "ui:options": { - addable: true, - orderable: true, - removable: true, - }, - items: { - paramType: this.defaultFieldStyles, - atomicSpecies: this.defaultFieldStyles, - atomicOrbital: this.defaultFieldStyles, - value: this.defaultFieldStyles, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} diff --git a/src/js/context/providers/HubbardUContextProvider.js b/src/js/context/providers/HubbardUContextProvider.js deleted file mode 100644 index 73d57598..00000000 --- a/src/js/context/providers/HubbardUContextProvider.js +++ /dev/null @@ -1,95 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { materialContextMixin } from "../mixins/MaterialContextMixin"; - -const defaultHubbardConfig = { - atomicSpecies: "", - atomicOrbital: "2p", - hubbardUValue: 1.0, -}; - -export class HubbardUContextProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/hubbard-u-context-provider"; - - constructor(config) { - super(config); - - this.initMaterialContextMixin(); - - this.uniqueElements = this.material?.Basis?.uniqueElements || []; - this.orbitalList = [ - "2p", - "3s", - "3p", - "3d", - "4s", - "4p", - "4d", - "4f", - "5s", - "5p", - "5d", - "5f", - "6s", - "6p", - "6d", - "7s", - "7p", - "7d", - ]; - const _elementsWithLabels = this.material?.Basis?.elementsWithLabelsArray || []; - this.uniqueElementsWithLabels = [...new Set(_elementsWithLabels)]; - this.firstElement = - this.uniqueElementsWithLabels?.length > 0 ? this.uniqueElementsWithLabels[0] : ""; - } - - get defaultData() { - return [ - { - ...defaultHubbardConfig, - atomicSpecies: this.firstElement, - }, - ]; - } - - get jsonSchemaPatchConfig() { - return { - "items.properties.atomicSpecies": { - enum: this.uniqueElementsWithLabels, - default: this.firstElement, - }, - "items.properties.atomicOrbital": { - enum: this.orbitalList, - default: defaultHubbardConfig.atomicOrbital, - }, - "items.properties.hubbardUValue": { - default: defaultHubbardConfig.hubbardUValue, - }, - }; - } - - get uiSchemaStyled() { - return { - "ui:options": { - addable: true, - orderable: false, - removable: true, - }, - items: { - atomicSpecies: this.defaultFieldStyles, - atomicOrbital: this.defaultFieldStyles, - hubbardUValue: this.defaultFieldStyles, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -materialContextMixin(HubbardUContextProvider.prototype); diff --git a/src/js/context/providers/IonDynamicsContextProvider.js b/src/js/context/providers/IonDynamicsContextProvider.js deleted file mode 100644 index f6c13a03..00000000 --- a/src/js/context/providers/IonDynamicsContextProvider.js +++ /dev/null @@ -1,44 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -const defaultMDConfig = { - numberOfSteps: 100, - timeStep: 5.0, - electronMass: 100.0, - temperature: 300.0, -}; - -export class IonDynamicsContextProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/ion-dynamics-context-provider"; - - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return defaultMDConfig; - } - - get jsonSchemaPatchConfig() { - return { - numberOfSteps: { default: this.defaultData.numberOfSteps }, - timeStep: { default: this.defaultData.timeStep }, - electronMass: { default: this.defaultData.electronMass }, - temperature: { default: this.defaultData.temperature }, - }; - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - numberOfSteps: {}, - timeStep: {}, - electronMass: {}, - temperature: {}, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} diff --git a/src/js/context/providers/IonDynamicsContextProvider.ts b/src/js/context/providers/IonDynamicsContextProvider.ts new file mode 100644 index 00000000..5b767ebc --- /dev/null +++ b/src/js/context/providers/IonDynamicsContextProvider.ts @@ -0,0 +1,49 @@ +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { IonDynamicsContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import type { ContextItem, Domain, ExternalContext } from "./base/ContextProvider"; +import JSONSchemaFormDataProvider from "./base/JSONSchemaFormDataProvider"; + +type Data = IonDynamicsContextProviderSchema; +type Name = "dynamics"; + +const jsonSchemaId = "context-providers-directory/ion-dynamics-context-provider"; + +const defaultData = { + numberOfSteps: 100, + timeStep: 5.0, + electronMass: 100.0, + temperature: 300.0, +}; + +export default class IonDynamicsContextProvider extends JSONSchemaFormDataProvider { + readonly name: Name = "dynamics"; + + readonly domain: Domain = "important"; + + readonly uiSchema = { + numberOfSteps: {}, + timeStep: {}, + electronMass: {}, + temperature: {}, + }; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + numberOfSteps: { default: defaultData.numberOfSteps }, + timeStep: { default: defaultData.timeStep }, + electronMass: { default: defaultData.electronMass }, + temperature: { default: defaultData.temperature }, + }); + } + + // eslint-disable-next-line class-methods-use-this + getDefaultData() { + return defaultData; + } +} diff --git a/src/js/context/providers/MLSettingsContextProvider.js b/src/js/context/providers/MLSettingsContextProvider.js deleted file mode 100644 index d74d2094..00000000 --- a/src/js/context/providers/MLSettingsContextProvider.js +++ /dev/null @@ -1,45 +0,0 @@ -import { ContextProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { applicationContextMixin } from "../mixins/ApplicationContextMixin"; - -export class MLSettingsContextProvider extends ContextProvider { - jsonSchemaId = "context-providers-directory/ml-settings-context-provider"; - - constructor(config) { - super(config); - this.initApplicationContextMixin(); - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - target_column_name: {}, - problem_category: {}, - }; - } - - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { - target_column_name: "target", - problem_category: "regression", - }; - } - - get jsonSchemaPatchConfig() { - return { - target_column_name: { default: this.defaultData.target_column_name }, - problem_category: { default: this.defaultData.problem_category }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -applicationContextMixin(MLSettingsContextProvider.prototype); diff --git a/src/js/context/providers/MLSettingsContextProvider.ts b/src/js/context/providers/MLSettingsContextProvider.ts new file mode 100644 index 00000000..06c81a9e --- /dev/null +++ b/src/js/context/providers/MLSettingsContextProvider.ts @@ -0,0 +1,54 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { MLSettingsContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import { + type ApplicationContextMixin, + applicationContextMixin, +} from "../mixins/ApplicationContextMixin"; +import { type ContextItem, type Domain } from "./base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./base/JSONSchemaDataProvider"; + +type Name = "mlSettings"; +type Data = MLSettingsContextProviderSchema; +type ExternalContext = JinjaExternalContext & ApplicationContextMixin; +type Base = typeof JSONSchemaDataProvider & + Constructor; + +const jsonSchemaId = "context-providers-directory/ml-settings-context-provider"; + +const defaultData = { + target_column_name: "target", + problem_category: "regression" as const, +}; + +export default class MLSettingsContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "mlSettings"; + + readonly domain: Domain = "important"; + + readonly jsonSchema: JSONSchema7 | undefined; + + readonly uiSchema = { + target_column_name: {}, + problem_category: {}, + }; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initApplicationContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + target_column_name: { default: defaultData.target_column_name }, + problem_category: { default: defaultData.problem_category }, + }); + } + + // eslint-disable-next-line class-methods-use-this + getDefaultData() { + return defaultData; + } +} + +applicationContextMixin(MLSettingsContextProvider.prototype); diff --git a/src/js/context/providers/MLTrainTestSplitContextProvider.js b/src/js/context/providers/MLTrainTestSplitContextProvider.js deleted file mode 100644 index 9f739e49..00000000 --- a/src/js/context/providers/MLTrainTestSplitContextProvider.js +++ /dev/null @@ -1,43 +0,0 @@ -import { ContextProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { applicationContextMixin } from "../mixins/ApplicationContextMixin"; - -export class MLTrainTestSplitContextProvider extends ContextProvider { - jsonSchemaId = "context-providers-directory/ml-train-test-split-context-provider"; - - constructor(config) { - super(config); - this.initApplicationContextMixin(); - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - target_column_name: {}, - problem_category: {}, - }; - } - - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { - fraction_held_as_test_set: 0.2, - }; - } - - get jsonSchemaPatchConfig() { - return { - fraction_held_as_test_set: { default: this.defaultData.fraction_held_as_test_set }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -applicationContextMixin(MLTrainTestSplitContextProvider.prototype); diff --git a/src/js/context/providers/MLTrainTestSplitContextProvider.ts b/src/js/context/providers/MLTrainTestSplitContextProvider.ts new file mode 100644 index 00000000..34a374c6 --- /dev/null +++ b/src/js/context/providers/MLTrainTestSplitContextProvider.ts @@ -0,0 +1,51 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { MLTrainTestSplitContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import { + type ApplicationContextMixin, + applicationContextMixin, +} from "../mixins/ApplicationContextMixin"; +import { type ContextItem, type Domain } from "./base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./base/JSONSchemaDataProvider"; + +type Name = "mlTrainTestSplit"; +type Data = MLTrainTestSplitContextProviderSchema; +type ExternalContext = JinjaExternalContext & ApplicationContextMixin; +type Base = typeof JSONSchemaDataProvider & Constructor; + +const jsonSchemaId = "context-providers-directory/ml-train-test-split-context-provider"; + +const defaultData = { + fraction_held_as_test_set: 0.2, +}; + +export default class MLTrainTestSplitContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "mlTrainTestSplit"; + + readonly domain: Domain = "important"; + + readonly jsonSchema: JSONSchema7 | undefined; + + readonly uiSchema = { + target_column_name: {}, + problem_category: {}, + }; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initApplicationContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + fraction_held_as_test_set: { default: defaultData.fraction_held_as_test_set }, + }); + } + + // eslint-disable-next-line class-methods-use-this + getDefaultData() { + return defaultData; + } +} + +applicationContextMixin(MLTrainTestSplitContextProvider.prototype); diff --git a/src/js/context/providers/NEBFormDataProvider.js b/src/js/context/providers/NEBFormDataProvider.js deleted file mode 100644 index 2cc422d0..00000000 --- a/src/js/context/providers/NEBFormDataProvider.js +++ /dev/null @@ -1,33 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -export class NEBFormDataProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/neb-data-provider"; - - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { - nImages: 1, - }; - } - - get jsonSchemaPatchConfig() { - return { - nImages: { default: this.defaultData.nImages }, - }; - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - nImages: {}, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} diff --git a/src/js/context/providers/NEBFormDataProvider.ts b/src/js/context/providers/NEBFormDataProvider.ts new file mode 100644 index 00000000..df67cc78 --- /dev/null +++ b/src/js/context/providers/NEBFormDataProvider.ts @@ -0,0 +1,42 @@ +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { NEBDataProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import type { ContextItem, Domain } from "./base/ContextProvider"; +import type { JinjaExternalContext } from "./base/JSONSchemaDataProvider"; +import JSONSchemaFormDataProvider from "./base/JSONSchemaFormDataProvider"; + +type Name = "neb"; +type Data = NEBDataProviderSchema; +type ExternalContext = JinjaExternalContext; + +const jsonSchemaId = "context-providers-directory/neb-data-provider"; + +const defaultData = { + nImages: 1, +}; + +export default class NEBFormDataProvider extends JSONSchemaFormDataProvider { + readonly name: Name = "neb"; + + readonly domain: Domain = "important"; + + readonly uiSchema = { + nImages: {}, + }; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + nImages: { default: defaultData.nImages }, + }); + } + + // eslint-disable-next-line class-methods-use-this + getDefaultData() { + return defaultData; + } +} diff --git a/src/js/context/providers/NonCollinearMagnetizationContextProvider.js b/src/js/context/providers/NonCollinearMagnetizationContextProvider.ts similarity index 64% rename from src/js/context/providers/NonCollinearMagnetizationContextProvider.js rename to src/js/context/providers/NonCollinearMagnetizationContextProvider.ts index 7f698108..299e2637 100644 --- a/src/js/context/providers/NonCollinearMagnetizationContextProvider.js +++ b/src/js/context/providers/NonCollinearMagnetizationContextProvider.ts @@ -1,33 +1,92 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import lodash from "lodash"; - -import { materialContextMixin } from "../mixins/MaterialContextMixin"; - -export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/non-collinear-magnetization-context-provider"; - - constructor(config) { - super(config); - this.initMaterialContextMixin(); - this.isStartingMagnetization = lodash.get(this.data, "isStartingMagnetization", true); - this.isConstrainedMagnetization = lodash.get( - this.data, - "isConstrainedMagnetization", - false, - ); - this.isExistingChargeDensity = lodash.get(this.data, "isExistingChargeDensity", false); - this.isArbitrarySpinDirection = lodash.get(this.data, "isArbitrarySpinDirection", false); - this.isFixedMagnetization = lodash.get(this.data, "isFixedMagnetization", false); - this.constrainedMagnetization = lodash.get(this.data, "constrainedMagnetization", {}); - } +import type { NonCollinearMagnetizationContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "./base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./base/JSONSchemaDataProvider"; + +type Name = "nonCollinearMagnetization"; +type Data = NonCollinearMagnetizationContextProviderSchema; +type ExternalContext = JinjaExternalContext & MaterialExternalContext; +type Base = typeof JSONSchemaDataProvider & Constructor; + +const jsonSchemaId = "context-providers-directory/non-collinear-magnetization-context-provider"; + +export default class NonCollinearMagnetizationContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "nonCollinearMagnetization"; + + readonly domain: Domain = "important"; + + readonly isStartingMagnetization: boolean; + + readonly isConstrainedMagnetization: boolean; + + readonly isExistingChargeDensity: boolean; + + readonly isArbitrarySpinDirection: boolean; - get uniqueElementsWithLabels() { - const elementsWithLabelsArray = this.material?.Basis?.elementsWithLabelsArray || []; - return [...new Set(elementsWithLabelsArray)]; + readonly isFixedMagnetization: boolean; + + readonly constrainedMagnetization: Data["constrainedMagnetization"]; + + readonly jsonSchema: JSONSchema7 | undefined; + + private readonly uniqueElementsWithLabels: string[]; + + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + + this.isStartingMagnetization = this.data?.isStartingMagnetization ?? true; + this.isConstrainedMagnetization = this.data?.isConstrainedMagnetization ?? false; + this.isExistingChargeDensity = this.data?.isExistingChargeDensity ?? false; + this.isArbitrarySpinDirection = this.data?.isArbitrarySpinDirection ?? false; + this.isFixedMagnetization = this.data?.isFixedMagnetization ?? false; + this.constrainedMagnetization = this.data?.constrainedMagnetization ?? { + lambda: 0.0, + constrainType: "atomic direction" as const, + }; + this.uniqueElementsWithLabels = [ + ...new Set(this.material?.Basis?.elementsWithLabelsArray || []), + ]; + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + isExistingChargeDensity: { default: false }, + isStartingMagnetization: { default: true }, + isArbitrarySpinAngle: { default: false }, + isConstrainedMagnetization: { default: false }, + isFixedMagnetization: { default: true }, + startingMagnetization: { + minItems: this.uniqueElementsWithLabels.length, + maxItems: this.uniqueElementsWithLabels.length, + }, + "startingMagnetization.items.properties.value": { + default: 0.0, + minimum: -1.0, + maximum: 1.0, + }, + spinAngles: { + minItems: this.uniqueElementsWithLabels.length, + maxItems: this.uniqueElementsWithLabels.length, + }, + "spinAngles.items.properties.angle1": { default: 0.0 }, + "spinAngles.items.properties.angle2": { default: 0.0 }, + "constrainedMagnetization.properties.constrainType": { + default: "atomic direction", + }, + "constrainedMagnetization.properties.lambda": { default: 0.0 }, + "fixedMagnetization.properties.x": { default: 0.0 }, + "fixedMagnetization.properties.y": { default: 0.0 }, + "fixedMagnetization.properties.z": { default: 0.0 }, + }); } - get defaultData() { + getDefaultData(): Data { const startingMagnetization = this.uniqueElementsWithLabels.map((element, index) => { return { index: index + 1, @@ -50,6 +109,7 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData isStartingMagnetization: true, isConstrainedMagnetization: false, isArbitrarySpinAngle: false, + isArbitrarySpinDirection: false, isFixedMagnetization: false, lforcet: true, spinAngles, @@ -80,11 +140,8 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData spinAngles: { items: { atomicSpecies: { - ...this.defaultFieldStyles, "ui:readonly": true, }, - angle1: this.defaultFieldStyles, - angle2: this.defaultFieldStyles, }, "ui:readonly": !this.isArbitrarySpinDirection, "ui:options": { @@ -97,7 +154,6 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData startingMagnetization: { items: { atomicSpecies: { - ...this.defaultFieldStyles, "ui:readonly": true, }, value: { @@ -113,8 +169,6 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData }, isConstrainedMagnetization: {}, constrainedMagnetization: { - constrainType: this.defaultFieldStyles, - lambda: this.defaultFieldStyles, "ui:readonly": !this.isConstrainedMagnetization, }, isFixedMagnetization: { @@ -124,9 +178,6 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData ), }, fixedMagnetization: { - x: this.defaultFieldStyles, - y: this.defaultFieldStyles, - z: this.defaultFieldStyles, "ui:readonly": !( this.isFixedMagnetization && this.isConstrainedMagnetization && @@ -135,45 +186,6 @@ export class NonCollinearMagnetizationContextProvider extends JSONSchemaFormData }, }; } - - get jsonSchemaPatchConfig() { - return { - isExistingChargeDensity: { default: false }, - isStartingMagnetization: { default: true }, - isArbitrarySpinAngle: { default: false }, - isConstrainedMagnetization: { default: false }, - isFixedMagnetization: { default: true }, - startingMagnetization: { - minItems: this.uniqueElementsWithLabels.length, - maxItems: this.uniqueElementsWithLabels.length, - }, - "startingMagnetization.items.properties.value": { - default: 0.0, - minimum: -1.0, - maximum: 1.0, - }, - spinAngles: { - minItems: this.uniqueElementsWithLabels.length, - maxItems: this.uniqueElementsWithLabels.length, - }, - "spinAngles.items.properties.angle1": { default: 0.0 }, - "spinAngles.items.properties.angle2": { default: 0.0 }, - "constrainedMagnetization.properties.constrainType": { - default: "atomic direction", - }, - "constrainedMagnetization.properties.lambda": { default: 0.0 }, - "fixedMagnetization.properties.x": { default: 0.0 }, - "fixedMagnetization.properties.y": { default: 0.0 }, - "fixedMagnetization.properties.z": { default: 0.0 }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } } materialContextMixin(NonCollinearMagnetizationContextProvider.prototype); diff --git a/src/js/context/providers/PlanewaveCutoffsContextProvider.js b/src/js/context/providers/PlanewaveCutoffsContextProvider.js deleted file mode 100644 index 1d78e354..00000000 --- a/src/js/context/providers/PlanewaveCutoffsContextProvider.js +++ /dev/null @@ -1,65 +0,0 @@ -import { ContextProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -import { applicationContextMixin } from "../mixins/ApplicationContextMixin"; - -const cutoffConfig = { - vasp: {}, // assuming default cutoffs for VASP - espresso: { - // assuming the default GBRV set of pseudopotentials is used - wavefunction: 40, - density: 200, - }, -}; - -export class PlanewaveCutoffsContextProvider extends ContextProvider { - jsonSchemaId = "context-providers-directory/planewave-cutoffs-context-provider"; - - constructor(config) { - super(config); - this.initApplicationContextMixin(); - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - wavefunction: {}, - density: {}, - }; - } - - get defaultData() { - return { - wavefunction: this.defaultECUTWFC, - density: this.defaultECUTRHO, - }; - } - - get jsonSchemaPatchConfig() { - return { - wavefunction: { default: this.defaultData.wavefunction }, - density: { default: this.defaultData.density }, - }; - } - - get _cutoffConfigPerApplication() { - return cutoffConfig[this.application.name]; - } - - get defaultECUTWFC() { - return this._cutoffConfigPerApplication.wavefunction || null; - } - - get defaultECUTRHO() { - return this._cutoffConfigPerApplication.density || null; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } -} - -applicationContextMixin(PlanewaveCutoffsContextProvider.prototype); diff --git a/src/js/context/providers/PlanewaveCutoffsContextProvider.ts b/src/js/context/providers/PlanewaveCutoffsContextProvider.ts new file mode 100644 index 00000000..d48875c1 --- /dev/null +++ b/src/js/context/providers/PlanewaveCutoffsContextProvider.ts @@ -0,0 +1,69 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { PlanewaveCutoffsContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import { + type ApplicationContextMixin, + applicationContextMixin, +} from "../mixins/ApplicationContextMixin"; +import ContextProvider, { + type ContextItem, + type Domain, + type EntityName, + type ExternalContext, +} from "./base/ContextProvider"; + +type ApplicationName = "vasp" | "espresso"; + +type Name = "cutoffs"; +type Data = PlanewaveCutoffsContextProviderSchema; +type PlanewaveExternalContext = ExternalContext & ApplicationContextMixin; +type Base = typeof ContextProvider & Constructor; + +const cutoffConfig: Record = { + vasp: { wavefunction: undefined, density: undefined }, + espresso: { wavefunction: 40, density: 200 }, +}; + +const jsonSchemaId = "context-providers-directory/planewave-cutoffs-context-provider"; + +export default class PlanewaveCutoffsContextProvider extends (ContextProvider as Base) { + readonly name: Name = "cutoffs"; + + readonly domain: Domain = "important"; + + readonly entityName: EntityName = "subworkflow"; + + readonly jsonSchema: JSONSchema7 | undefined; + + readonly uiSchema = { + wavefunction: {}, + density: {}, + }; + + constructor(contextItem: ContextItem, externalContext: PlanewaveExternalContext) { + super(contextItem, externalContext); + this.initApplicationContextMixin(externalContext); + + const { wavefunction, density } = this.getDefaultData(); + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + wavefunction: { default: wavefunction }, + density: { default: density }, + }); + } + + getDefaultData() { + // TODO-QUESTION: what if the application is not in the cutoffConfig? + const { wavefunction, density } = + cutoffConfig[this.application.name as ApplicationName] || {}; + + return { + wavefunction, + density, + }; + } +} + +applicationContextMixin(PlanewaveCutoffsContextProvider.prototype); diff --git a/src/js/context/providers/PointsGrid/IGridFormDataManager.ts b/src/js/context/providers/PointsGrid/IGridFormDataManager.ts new file mode 100644 index 00000000..3591d4f6 --- /dev/null +++ b/src/js/context/providers/PointsGrid/IGridFormDataManager.ts @@ -0,0 +1,9 @@ +import PointsGridFormDataProvider from "./PointsGridFormDataProvider"; + +type Name = "igrid"; + +export default class IGridFormDataManager extends PointsGridFormDataProvider { + readonly name: Name = "igrid"; + + readonly divisor: number = 0.2; +} diff --git a/src/js/context/providers/PointsGrid/KGridFormDataManager.ts b/src/js/context/providers/PointsGrid/KGridFormDataManager.ts new file mode 100644 index 00000000..a41059ca --- /dev/null +++ b/src/js/context/providers/PointsGrid/KGridFormDataManager.ts @@ -0,0 +1,7 @@ +import PointsGridFormDataProvider from "./PointsGridFormDataProvider"; + +type Name = "kgrid"; + +export default class KGridFormDataManager extends PointsGridFormDataProvider { + readonly name: Name = "kgrid"; +} diff --git a/src/js/context/providers/PointsGrid/PointsGridFormDataProvider.ts b/src/js/context/providers/PointsGrid/PointsGridFormDataProvider.ts new file mode 100644 index 00000000..30fce02d --- /dev/null +++ b/src/js/context/providers/PointsGrid/PointsGridFormDataProvider.ts @@ -0,0 +1,328 @@ +import { Units } from "@mat3ra/code/dist/js/constants"; +import { math as codeJSMath } from "@mat3ra/code/dist/js/math"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { PointsGridDataProviderSchema, Vector3DSchema } from "@mat3ra/esse/dist/js/types"; +import { type ReciprocalLattice, Made } from "@mat3ra/made"; +import type { JSONSchema7 } from "json-schema"; +import lodash from "lodash"; + +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "../base/ContextProvider"; +import type { JinjaExternalContext } from "../base/JSONSchemaDataProvider"; +import JSONSchemaFormDataProvider from "../base/JSONSchemaFormDataProvider"; +import { globalSettings } from "../settings"; + +type Name = string; +type Data = PointsGridDataProviderSchema; +type EContext = JinjaExternalContext & + MaterialExternalContext & { + divisor: number; + }; +type Base = typeof JSONSchemaFormDataProvider & + Constructor; + +type GridMetricType = Required["gridMetricType"]; + +// Helper function to create vector schema with defaults +const vector = ( + defaultValue: string | number | readonly number[] | readonly string[], + isStringType = false, +) => { + const isArray = Array.isArray(defaultValue); + + return { + type: "array", + items: { + type: isStringType ? "string" : "number", + ...(isArray ? {} : { default: defaultValue }), + }, + minItems: 3, + maxItems: 3, + ...(isArray ? { default: defaultValue } : {}), + }; +}; + +const jsonSchemaId = "context-providers-directory/points-grid-data-provider"; +const defaultShift = 0; +const defaultShifts: Vector3DSchema = [defaultShift, defaultShift, defaultShift]; + +export default abstract class PointsGridFormDataProvider< + N extends string = string, +> extends (JSONSchemaFormDataProvider as Base) { + abstract readonly name: N; + + readonly domain: Domain = "important"; + + public dimensions!: Vector3DSchema; + + public shifts!: Vector3DSchema; + + private reciprocalLattice!: ReciprocalLattice; + + private gridMetricType!: GridMetricType; + + private gridMetricValue!: number; + + private preferGridMetric!: boolean; + + private defaultDimensions!: Vector3DSchema; + + private reciprocalVectorRatios!: Vector3DSchema; + + private defaultMetric!: { + type: GridMetricType; + value: number; + }; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(contextItem: ContextItem, externalContext: EContext) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + this.initInstanceFields(); + + const { jsonSchemaPatchConfig } = this; + + this.jsonSchema = JSONSchemasInterface.getPatchedSchemaById( + jsonSchemaId, + jsonSchemaPatchConfig, + ); + } + + private initInstanceFields() { + this.defaultMetric = { + type: "KPPRA" as const, + value: this.getDefaultGridMetricValue("KPPRA"), + }; + + this.shifts = this.data?.shifts || [...defaultShifts]; + this.gridMetricType = this.data?.gridMetricType || this.defaultMetric.type; + this.gridMetricValue = this.data?.gridMetricValue || this.defaultMetric.value; + this.preferGridMetric = this.data?.preferGridMetric || false; + + this.reciprocalLattice = new Made.ReciprocalLattice(this.material?.lattice); + this.defaultDimensions = this.calculateDimensions({ + gridMetricType: this.defaultMetric.type, + gridMetricValue: this.defaultMetric.value, + }); + this.dimensions = this.data?.dimensions || this.defaultDimensions; + this.reciprocalVectorRatios = this.reciprocalLattice.reciprocalVectorRatios.map((r) => + Number(codeJSMath.numberToPrecision(r, 3)), + ) as Vector3DSchema; + } + + private getDefaultGridMetricValue(metric: GridMetricType) { + switch (metric) { + case "KPPRA": { + const divisor = this.externalContext?.divisor || 1; + const { defaultKPPRA } = globalSettings; + return Math.floor(defaultKPPRA / divisor); + } + case "spacing": + return 0.3; + default: + console.error("Metric type not recognized!"); + return 1; + } + } + + getDefaultData() { + const defaultData: Data = { + dimensions: this.defaultDimensions, + shifts: defaultShifts, + gridMetricType: this.defaultMetric.type, + gridMetricValue: this.defaultMetric.value, + preferGridMetric: false, + reciprocalVectorRatios: this.reciprocalVectorRatios, + }; + + if (this.material) { + const { gridMetricType, gridMetricValue } = this; + // if `data` is present and material is updated, prioritize `data` when `preferGridMetric` is not set + return this.preferGridMetric + ? { + dimensions: this.calculateDimensions({ gridMetricType, gridMetricValue }), + shifts: defaultShifts, + gridMetricType, + gridMetricValue, + } + : this.data || defaultData; + } + + return defaultData; + } + + private get jsonSchemaPatchConfig() { + const metricDescription = { + KPPRA: `${this.name.toUpperCase()}PPRA (${this.name}pt per reciprocal atom)`, // KPPRA or QPPRA + spacing: "grid spacing", + }; + + const gridMetricType = this.data?.gridMetricType || this.defaultMetric.type; + + return { + dimensions: vector(this.defaultDimensions, this.isUsingJinjaVariables), + shifts: vector(defaultShifts), + reciprocalVectorRatios: vector(this.reciprocalVectorRatios), + gridMetricType: { default: this.defaultMetric.type }, + description: `3D grid with shifts. Default min value for ${ + metricDescription[gridMetricType] + } is ${this.getDefaultGridMetricValue(gridMetricType)}.`, + required: ["dimensions", "shifts"], + dependencies: { + gridMetricType: { + oneOf: [ + { + properties: { + gridMetricType: { enum: ["KPPRA"] }, + gridMetricValue: { + type: "integer", + minimum: 1, + title: "Value", + default: this.gridMetricValue, + }, + preferGridMetric: { + type: "boolean", + title: "prefer KPPRA", + default: this.preferGridMetric, + }, + }, + }, + { + properties: { + gridMetricType: { enum: ["spacing"] }, + gridMetricValue: { + type: "number", + minimum: 0, + title: "Value [1/Å]", + default: this.gridMetricValue, + }, + preferGridMetric: { + type: "boolean", + title: "prefer spacing", + default: this.preferGridMetric, + }, + }, + }, + ], + }, + }, + }; + } + + get uiSchema() { + const arraySubStyle = (emptyValue = 0) => { + return { + "ui:options": { + addable: false, + orderable: false, + removable: false, + }, + items: { + "ui:disabled": this.preferGridMetric, + // TODO: extract the actual current values from context + "ui:placeholder": "1", + "ui:emptyValue": emptyValue, + "ui:label": false, + }, + }; + }; + + return { + dimensions: arraySubStyle(1), + shifts: arraySubStyle(0), + gridMetricType: { + "ui:title": "Grid Metric", + }, + gridMetricValue: { + "ui:disabled": !this.preferGridMetric, + "ui:emptyValue": this.gridMetricValue, + "ui:placeholder": this.gridMetricValue.toString(), // make string to prevent prop type error + }, + preferGridMetric: { + "ui:emptyValue": true, + "ui:disabled": this.isUsingJinjaVariables, + }, + reciprocalVectorRatios: { + "ui:title": "reciprocal vector ratios", + "ui:orderable": false, + "ui:removable": false, + "ui:readonly": true, + items: { + "ui:label": false, + }, + }, + }; + } + + private calculateDimensions({ + gridMetricType, + gridMetricValue, + }: // units = Units.angstrom, + Pick): Vector3DSchema { + switch (gridMetricType) { + case "KPPRA": { + const nAtoms = this.material ? this.material.Basis.nAtoms : 1; + return this.reciprocalLattice.getDimensionsFromPointsCount( + gridMetricValue / nAtoms, + ); + } + case "spacing": + return this.reciprocalLattice.getDimensionsFromSpacing( + gridMetricValue, + Units.angstrom, + ); + default: + return [1, 1, 1]; + } + } + + private calculateGridMetric({ + gridMetricType, + dimensions, + }: // units = Units.angstrom, + Pick) { + switch (gridMetricType) { + case "KPPRA": { + const nAtoms = this.material ? this.material.Basis.nAtoms : 1; + return dimensions.reduce((a, b) => a * b) * nAtoms; + } + case "spacing": + return lodash.round( + this.reciprocalLattice.getSpacingFromDimensions(dimensions, Units.angstrom), + 3, + ); + default: + return 1; + } + } + + setData(data?: Data) { + const canTransform = + (data?.preferGridMetric && data?.gridMetricType && data?.gridMetricValue) || + (!data?.preferGridMetric && data?.dimensions?.every((d) => typeof d === "number")); + + if (!data || !canTransform) { + return super.setData(data); + } + + // dimensions are calculated from grid metric or vice versa + if (data.preferGridMetric) { + return super.setData({ + ...data, + dimensions: this.calculateDimensions(data), + }); + } + + super.setData({ + ...data, + gridMetricValue: this.calculateGridMetric(data), + }); + } +} + +materialContextMixin(PointsGridFormDataProvider.prototype); diff --git a/src/js/context/providers/PointsGrid/QGridFormDataManager.ts b/src/js/context/providers/PointsGrid/QGridFormDataManager.ts new file mode 100644 index 00000000..4ce4c14a --- /dev/null +++ b/src/js/context/providers/PointsGrid/QGridFormDataManager.ts @@ -0,0 +1,9 @@ +import PointsGridFormDataProvider from "./PointsGridFormDataProvider"; + +type Name = "qgrid"; + +export default class QGridFormDataManager extends PointsGridFormDataProvider { + readonly name: Name = "qgrid"; + + readonly divisor: number = 5; +} diff --git a/src/js/context/providers/PointsGridFormDataProvider.js b/src/js/context/providers/PointsGridFormDataProvider.js deleted file mode 100644 index 2afe55d9..00000000 --- a/src/js/context/providers/PointsGridFormDataProvider.js +++ /dev/null @@ -1,271 +0,0 @@ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import { units as UNITS } from "@mat3ra/code/dist/js/constants"; -import { math as codeJSMath } from "@mat3ra/code/dist/js/math"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import { Made } from "@mat3ra/made"; -import lodash from "lodash"; - -import { materialContextMixin } from "../mixins/MaterialContextMixin"; -import { globalSettings } from "./settings"; - -export class PointsGridFormDataProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/points-grid-data-provider"; - - constructor(config) { - super(config); - this.initMaterialContextMixin(); - - this._divisor = config.divisor || 1; // KPPRA will be divided by this number - this.reciprocalLattice = new Made.ReciprocalLattice(this.material.lattice); - - this.dimensions = lodash.get(this.data, "dimensions") || this._defaultDimensions; - this.shifts = lodash.get(this.data, "shifts") || this._defaultShifts; - - // init class fields from data (as constructed from context in parent) - this.gridMetricType = lodash.get(this.data, "gridMetricType") || "KPPRA"; - this.gridMetricValue = - lodash.get(this.data, "gridMetricValue") || this._getDefaultGridMetricValue("KPPRA"); - this.preferGridMetric = lodash.get(this.data, "preferGridMetric", false); - - this._metricDescription = { - KPPRA: `${this.name[0].toUpperCase()}PPRA (${this.name[0]}pt per reciprocal atom)`, // KPPRA or QPPRA - spacing: "grid spacing", - }; - this.defaultClassNames = "col-xs-12 col-sm-6 col-md-3 col-lg-2"; - } - - // eslint-disable-next-line class-methods-use-this - getDefaultShift() { - return 0; - } - - get _defaultDimensions() { - return this.calculateDimensions({ - gridMetricType: "KPPRA", - gridMetricValue: this._getDefaultGridMetricValue("KPPRA"), - }); - } - - get _defaultShifts() { - return Array(3).fill(this.getDefaultShift()); - } - - _getDefaultGridMetricValue(metric) { - switch (metric) { - case "KPPRA": - return Math.floor(globalSettings.defaultKPPRA / this._divisor); - case "spacing": - return 0.3; - default: - console.error("Metric type not recognized!"); - return 1; - } - } - - get _defaultData() { - return { - dimensions: this._defaultDimensions, - shifts: this._defaultShifts, - gridMetricType: "KPPRA", - gridMetricValue: this._getDefaultGridMetricValue("KPPRA"), - preferGridMetric: false, - reciprocalVectorRatios: this.reciprocalVectorRatios, - }; - } - - get _defaultDataWithMaterial() { - const { gridMetricType, gridMetricValue } = this; - // if `data` is present and material is updated, prioritize `data` when `preferGridMetric` is not set - return this.preferGridMetric - ? { - dimensions: this.calculateDimensions({ gridMetricType, gridMetricValue }), - shifts: this._defaultShifts, - } - : this.data || this._defaultData; - } - - get defaultData() { - return this.material ? this._defaultDataWithMaterial : this._defaultData; - } - - get reciprocalVectorRatios() { - return this.reciprocalLattice.reciprocalVectorRatios.map((r) => - Number(codeJSMath.numberToPrecision(r, 3)), - ); - } - - get jsonSchemaPatchConfig() { - // Helper function to create vector schema with defaults - const vector_ = (defaultValue, isStringType = false) => { - const isArray = Array.isArray(defaultValue); - return { - type: "array", - items: { - type: isStringType ? "string" : "number", - ...(isArray ? {} : { default: defaultValue }), - }, - minItems: 3, - maxItems: 3, - ...(isArray ? { default: defaultValue } : {}), - }; - }; - - return { - dimensions: vector_(this._defaultDimensions, this.isUsingJinjaVariables), - shifts: vector_(this.getDefaultShift()), - reciprocalVectorRatios: vector_(this.reciprocalVectorRatios), - gridMetricType: { default: "KPPRA" }, - description: `3D grid with shifts. Default min value for ${ - this._metricDescription[this.gridMetricType] - } is ${this._getDefaultGridMetricValue(this.gridMetricType)}.`, - required: ["dimensions", "shifts"], - dependencies: { - gridMetricType: { - oneOf: [ - { - properties: { - gridMetricType: { enum: ["KPPRA"] }, - gridMetricValue: { - type: "integer", - minimum: 1, - title: "Value", - default: this.gridMetricValue, - }, - preferGridMetric: { - type: "boolean", - title: "prefer KPPRA", - default: this.preferGridMetric, - }, - }, - }, - { - properties: { - gridMetricType: { enum: ["spacing"] }, - gridMetricValue: { - type: "number", - minimum: 0, - title: "Value [1/Å]", - default: this.gridMetricValue, - }, - preferGridMetric: { - type: "boolean", - title: "prefer spacing", - default: this.preferGridMetric, - }, - }, - }, - ], - }, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } - - get uiSchema() { - const _arraySubStyle = (emptyValue = 0) => { - return { - "ui:options": { - addable: false, - orderable: false, - removable: false, - }, - items: { - "ui:disabled": this.preferGridMetric, - // TODO: extract the actual current values from context - "ui:placeholder": "1", - "ui:emptyValue": emptyValue, - "ui:label": false, - }, - }; - }; - - return { - dimensions: _arraySubStyle(1), - shifts: _arraySubStyle(0), - gridMetricType: { - "ui:title": "Grid Metric", - }, - gridMetricValue: { - "ui:disabled": !this.preferGridMetric, - "ui:emptyValue": this.gridMetricValue, - "ui:placeholder": this.gridMetricValue.toString(), // make string to prevent prop type error - }, - preferGridMetric: { - "ui:emptyValue": true, - "ui:disabled": this.isUsingJinjaVariables, - }, - reciprocalVectorRatios: { - "ui:title": "reciprocal vector ratios", - "ui:orderable": false, - "ui:removable": false, - "ui:readonly": true, - items: { - "ui:label": false, - }, - }, - }; - } - - _getDimensionsFromKPPRA(KPPRA) { - const nAtoms = this.material ? this.material.Basis.nAtoms : 1; - return this.reciprocalLattice.getDimensionsFromPointsCount(KPPRA / nAtoms); - } - - _getKPPRAFromDimensions(dimensions) { - const nAtoms = this.material ? this.material.Basis.nAtoms : 1; - return dimensions.reduce((a, b) => a * b) * nAtoms; - } - - static _canTransform(data) { - return ( - (data.preferGridMetric && data.gridMetricType && data.gridMetricValue) || - (!data.preferGridMetric && data.dimensions.every((d) => typeof d === "number")) - ); - } - - calculateDimensions({ gridMetricType, gridMetricValue, units = UNITS.angstrom }) { - switch (gridMetricType) { - case "KPPRA": - return this._getDimensionsFromKPPRA(gridMetricValue); - case "spacing": - return this.reciprocalLattice.getDimensionsFromSpacing(gridMetricValue, units); - default: - return [1, 1, 1]; - } - } - - calculateGridMetric({ gridMetricType, dimensions, units = UNITS.angstrom }) { - switch (gridMetricType) { - case "KPPRA": - return this._getKPPRAFromDimensions(dimensions); - case "spacing": - return lodash.round( - this.reciprocalLattice.getSpacingFromDimensions(dimensions, units), - 3, - ); - default: - return 1; - } - } - - transformData(data) { - if (!this.constructor._canTransform(data)) { - return data; - } - // dimensions are calculated from grid metric or vice versa - if (data.preferGridMetric) { - data.dimensions = this.calculateDimensions(data); - } else { - data.gridMetricValue = this.calculateGridMetric(data); - } - return data; - } -} - -materialContextMixin(PointsGridFormDataProvider.prototype); diff --git a/src/js/context/providers/PointsPath/ExplicitKPath2PIBAFormDataManager.ts b/src/js/context/providers/PointsPath/ExplicitKPath2PIBAFormDataManager.ts new file mode 100644 index 00000000..dde317b6 --- /dev/null +++ b/src/js/context/providers/PointsPath/ExplicitKPath2PIBAFormDataManager.ts @@ -0,0 +1,11 @@ +import PointsPathFormDataProvider from "./PointsPathFormDataProvider"; + +type Name = "explicitKPath2PIBA"; + +export default class ExplicitKPath2PIBAFormDataManager extends PointsPathFormDataProvider { + readonly name: Name = "explicitKPath2PIBA"; + + readonly is2PIBA = true; + + readonly useExplicitPath = true; +} diff --git a/src/js/context/providers/PointsPath/ExplicitKPathFormDataManager.ts b/src/js/context/providers/PointsPath/ExplicitKPathFormDataManager.ts new file mode 100644 index 00000000..5cffa4bc --- /dev/null +++ b/src/js/context/providers/PointsPath/ExplicitKPathFormDataManager.ts @@ -0,0 +1,9 @@ +import PointsPathFormDataProvider from "./PointsPathFormDataProvider"; + +type Name = "explicitKPath"; + +export default class ExplicitKPathFormDataManager extends PointsPathFormDataProvider { + readonly name: Name = "explicitKPath"; + + readonly useExplicitPath = true; +} diff --git a/src/js/context/providers/PointsPath/IPathFormDataManager.ts b/src/js/context/providers/PointsPath/IPathFormDataManager.ts new file mode 100644 index 00000000..9d29fabb --- /dev/null +++ b/src/js/context/providers/PointsPath/IPathFormDataManager.ts @@ -0,0 +1,7 @@ +import PointsPathFormDataProvider from "./PointsPathFormDataProvider"; + +type Name = "ipath"; + +export default class IPathFormDataManager extends PointsPathFormDataProvider { + readonly name: Name = "ipath"; +} diff --git a/src/js/context/providers/PointsPath/KPathFormDataManager.ts b/src/js/context/providers/PointsPath/KPathFormDataManager.ts new file mode 100644 index 00000000..5e4e8461 --- /dev/null +++ b/src/js/context/providers/PointsPath/KPathFormDataManager.ts @@ -0,0 +1,7 @@ +import PointsPathFormDataProvider from "./PointsPathFormDataProvider"; + +type Name = "kpath"; + +export default class KPathFormDataManager extends PointsPathFormDataProvider { + readonly name: Name = "kpath"; +} diff --git a/src/js/context/providers/PointsPath/PointsPathFormDataProvider.ts b/src/js/context/providers/PointsPath/PointsPathFormDataProvider.ts new file mode 100644 index 00000000..2929e21e --- /dev/null +++ b/src/js/context/providers/PointsPath/PointsPathFormDataProvider.ts @@ -0,0 +1,163 @@ +import { math as codeJSMath } from "@mat3ra/code/dist/js/math"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { PointsPathDataProviderSchema } from "@mat3ra/esse/dist/js/types"; +import { type ReciprocalLattice, Made } from "@mat3ra/made"; +import s from "underscore.string"; + +import { + type ApplicationContextMixin, + applicationContextMixin, +} from "../../mixins/ApplicationContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../mixins/MaterialContextMixin"; +import type { ContextItem, Domain } from "../base/ContextProvider"; +import JSONSchemaDataProvider, { type JinjaExternalContext } from "../base/JSONSchemaDataProvider"; + +const defaultPoint = "Г" as const; +const defaultSteps = 10 as const; + +type Data = PointsPathDataProviderSchema; // same as KPointCoordinates +type DataItem = Data[0]; +type ExternalContext = JinjaExternalContext & MaterialExternalContext & ApplicationContextMixin; +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor; + +const jsonSchemaId = "context-providers-directory/points-path-data-provider"; + +abstract class MixinsContextProvider extends (JSONSchemaDataProvider as Base) { + constructor(contextItem: ContextItem, externalContext: ExternalContext) { + super(contextItem, externalContext); + this.initMaterialContextMixin(externalContext); + this.initApplicationContextMixin(externalContext); + } +} + +materialContextMixin(MixinsContextProvider.prototype); +applicationContextMixin(MixinsContextProvider.prototype); + +abstract class PointsPathFormDataProvider extends MixinsContextProvider { + abstract name: N; + + readonly domain: Domain = "important"; + + private reciprocalLattice: ReciprocalLattice; + + readonly useExplicitPath: boolean; + + readonly is2PIBA: boolean = false; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.reciprocalLattice = new Made.ReciprocalLattice(this.material.lattice); + this.useExplicitPath = this.application.name === "vasp"; + } + + getDefaultData() { + return this.reciprocalLattice.defaultKpointPath as Data; + } + + updateMaterialHash() { + super.updateMaterialHash(); + + // Workaround: Material.createDefault() used to initiate workflow reducer and hence here too + // does not have an id. Here we catch when such material is used and avoid resetting isEdited + const isMaterialCreatedDefault = !this.material.id; + const isMaterialUpdated = this.extraData?.materialHash !== this.material.hash; + + if (isMaterialUpdated || isMaterialCreatedDefault) { + this.isEdited = false; + } + } + + get jsonSchema() { + return JSONSchemasInterface.getPatchedSchemaById(jsonSchemaId, { + "items.properties.point": { + default: defaultPoint, + enum: this.reciprocalLattice.symmetryPoints.map((x) => x.point), + }, + "items.properties.steps": { + default: defaultSteps, + }, + }); + } + + setData(path: Data) { + const rawData: DataItem[] = path.map((pathItem) => { + const point = this.reciprocalLattice.symmetryPoints.find((sp) => { + return sp.point === pathItem.point; + }); + if (!point) { + throw new Error(`Point ${pathItem.point} not found in reciprocal lattice`); + } + return { ...pathItem, coordinates: point.coordinates }; + }); + + const processedData = this.useExplicitPath ? this.convertToExplicitPath(rawData) : rawData; + + const newData = processedData.map((p) => { + const coordinates = this.is2PIBA + ? this.reciprocalLattice.getCartesianCoordinates(p.coordinates) + : p.coordinates; + + return { + ...p, + coordinates: coordinates.map((c) => +s.sprintf("%14.9f", c)), + }; + }) as Data; + + super.setData(newData); + } + + // Initially, path contains symmetry points with steps counts. + // This function explicitly calculates each point between symmetry points by step counts. + // eslint-disable-next-line class-methods-use-this + private convertToExplicitPath(path: DataItem[]): DataItem[] { + return path.reduce((acc, startPoint, index) => { + const nextPoint = path[index + 1]; + + if (!nextPoint) { + return acc; + } + + const middlePoints = codeJSMath.calculateSegmentsBetweenPoints3D( + startPoint.coordinates, + nextPoint.coordinates, + startPoint.steps, + ); + + const steps = 1; + + // TODO-QUESTION: confirm that "point" property should be present after transformation; point was missing in original implementation + acc.push( + { + steps, + coordinates: startPoint.coordinates, + point: startPoint.point, + }, + ...middlePoints.map((coordinates) => ({ + steps, + coordinates, + // TODO-QUESTION: is this correct? + point: startPoint.point, + })), + ); + + // nextPoint is the last point in the path + if (path.length - 2 === index) { + acc.push({ + steps, + coordinates: nextPoint.coordinates, + point: nextPoint.point, + }); + } + + return acc; + }, []); + } +} + +export default PointsPathFormDataProvider; diff --git a/src/js/context/providers/PointsPath/QPathFormDataManager.ts b/src/js/context/providers/PointsPath/QPathFormDataManager.ts new file mode 100644 index 00000000..e16a5d03 --- /dev/null +++ b/src/js/context/providers/PointsPath/QPathFormDataManager.ts @@ -0,0 +1,7 @@ +import PointsPathFormDataProvider from "./PointsPathFormDataProvider"; + +type Name = "qpath"; + +export default class QPathFormDataManager extends PointsPathFormDataProvider { + readonly name: Name = "qpath"; +} diff --git a/src/js/context/providers/PointsPathFormDataProvider.js b/src/js/context/providers/PointsPathFormDataProvider.js deleted file mode 100644 index dc7c1604..00000000 --- a/src/js/context/providers/PointsPathFormDataProvider.js +++ /dev/null @@ -1,163 +0,0 @@ -/* eslint-disable max-classes-per-file */ -/* eslint react/prop-types: 0 */ -import { JSONSchemaFormDataProvider } from "@mat3ra/ade"; -import { math as codeJSMath } from "@mat3ra/code/dist/js/math"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import { Made } from "@mat3ra/made"; -import s from "underscore.string"; - -import { applicationContextMixin } from "../mixins/ApplicationContextMixin"; -import { materialContextMixin } from "../mixins/MaterialContextMixin"; - -const defaultPoint = "Г"; -const defaultSteps = 10; - -export class PointsPathFormDataProvider extends JSONSchemaFormDataProvider { - jsonSchemaId = "context-providers-directory/points-path-data-provider"; - - constructor(config) { - super(config); - this.initMaterialContextMixin(); - this.initApplicationContextMixin(); - this.reciprocalLattice = new Made.ReciprocalLattice(this.material.lattice); - this.symmetryPoints = this.symmetryPointsFromMaterial; - } - - get isEditedIsSetToFalseOnMaterialUpdate() { - return this.isMaterialUpdated || this.isMaterialCreatedDefault; - } - - get defaultData() { - return this.reciprocalLattice.defaultKpointPath; - } - - get symmetryPointsFromMaterial() { - return this.reciprocalLattice.symmetryPoints; - } - - get jsonSchemaPatchConfig() { - const points = [].concat(this.symmetryPoints).map((x) => x.point); - - return { - "items.properties.point": { - default: defaultPoint, - enum: points, - }, - "items.properties.steps": { - default: defaultSteps, - }, - }; - } - - get jsonSchema() { - return JSONSchemasInterface.getPatchedSchemaById( - this.jsonSchemaId, - this.jsonSchemaPatchConfig, - ); - } - - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { - items: {}, - }; - } - - get uiSchemaStyled() { - return { - items: { - point: this.defaultFieldStyles, - steps: this.defaultFieldStyles, - }, - }; - } - - // eslint-disable-next-line class-methods-use-this - get templates() { - return {}; - } - - getBrillouinZoneImageComponent(title) { - const hasRequiredFn = typeof this.material.getBrillouinZoneImageComponent === "function"; - if (!hasRequiredFn) { - console.log( - "PointsPathFormDataProvider: Material class has no function" + - " 'getBrillouinZoneImageComponent'! Returning empty Object instead.", - ); - return null; - } - return this.material.getBrillouinZoneImageComponent(title); - } - - get useExplicitPath() { - return this.application.name === "vasp"; - } - - // override yieldData to avoid storing explicit path in saved context - yieldDataForRendering() { - return this.yieldData(this.useExplicitPath); - } - - transformData(path = [], useExplicitPath = false) { - const rawData = path.map((p) => { - const point = this.symmetryPoints.find((sp) => sp.point === p.point); - return { ...p, coordinates: point.coordinates }; - }); - const processedData = useExplicitPath ? this._convertToExplicitPath(rawData) : rawData; - // make coordinates into string and add formatting - return processedData.map((p) => { - const coordinates = this.is2PIBA - ? this.get2PIBACoordinates(p.coordinates) - : p.coordinates; - p.coordinates = coordinates.map((c) => s.sprintf("%14.9f", c)); - return p; - }); - } - - get2PIBACoordinates(point) { - return this.reciprocalLattice.getCartesianCoordinates(point); - } - - // Initially, path contains symmetry points with steps counts. - // This function explicitly calculates each point between symmetry points by step counts. - // eslint-disable-next-line class-methods-use-this - _convertToExplicitPath(path) { - const points = []; - for (let i = 0; i < path.length - 1; i++) { - const startPoint = path[i]; - const endPoint = path[i + 1]; - const middlePoints = codeJSMath.calculateSegmentsBetweenPoints3D( - startPoint.coordinates, - endPoint.coordinates, - startPoint.steps, - ); - points.push(startPoint.coordinates); - points.push(...middlePoints); - // Include endPoint into path for the last section, otherwise it will be included by next loop iteration - if (path.length - 2 === i) points.push(endPoint.coordinates); - } - return points.map((x) => { - return { - coordinates: x, - steps: 1, - }; - }); - } -} - -export class ExplicitPointsPathFormDataProvider extends PointsPathFormDataProvider { - // eslint-disable-next-line class-methods-use-this - get useExplicitPath() { - return true; - } -} - -export class ExplicitPointsPath2PIBAFormDataProvider extends ExplicitPointsPathFormDataProvider { - // eslint-disable-next-line class-methods-use-this - get is2PIBA() { - return true; - } -} - -materialContextMixin(PointsPathFormDataProvider.prototype); -applicationContextMixin(PointsPathFormDataProvider.prototype); diff --git a/src/js/context/providers/base/ContextProvider.ts b/src/js/context/providers/base/ContextProvider.ts new file mode 100644 index 00000000..dfb22bd8 --- /dev/null +++ b/src/js/context/providers/base/ContextProvider.ts @@ -0,0 +1,107 @@ +/* + * @summary This is a standalone class that contains "data" for a property with "name". Helps facilitate UI logic. + * Can be initialized from context when user edits are present: + * - user edits the corresponding property, eg. "kpath" + * - isKpathEdited is set to `true` + * - context property is updated for the parent entity (eg. Unit) in a way that persists in Redux state + * - new entity inherits the "data" through "context" field in config + * - `extraData` field is used to store any other data that should be passed from one instance of provider + * to next one, for example data about material to track when it is changed. + * @notes Should hold static data only (see `setData` method), no classes or functions + */ +import { ContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import { Utils } from "@mat3ra/utils"; + +export interface ContextProviderInstance { + constructor: typeof ContextProvider; + config: ContextProviderSchema; +} + +export type ContextProviderConfig< + N extends string = string, + D extends object = object, + ED extends object = object, +> = { + name: N; + data?: D; + extraData?: ED; + domain?: string; + entityName?: EntityName; + isEdited?: boolean; +}; + +export type ContextItem = { + data?: D; + extraData?: ED; + isEdited?: boolean; +}; + +export type ExtendedContextItem< + N extends string = string, + D extends object = object, + ED extends object = object, +> = ContextItem & { + name: N; + isEdited: boolean; +}; + +export type Domain = "executable" | "important"; + +export type EntityName = "unit" | "subworkflow"; + +export type ExternalContext = object; + +abstract class ContextProvider< + N extends string = string, + D extends object = object, + ED extends object = object, + EC extends ExternalContext = ExternalContext, + // eslint-disable-next-line prettier/prettier +> implements ContextProviderConfig { + abstract name: N; + + abstract readonly domain: Domain; + + abstract readonly entityName: EntityName; + + protected abstract getDefaultData(): D; + + data?: D; + + readonly extraData?: ED; + + readonly externalContext: EC; + + isEdited: boolean; + + constructor(contextItem: ContextItem, externalContext: EC) { + this.externalContext = externalContext; + this.extraData = contextItem.extraData; + this.isEdited = contextItem.isEdited || false; + + this.setData(contextItem.data); + } + + setIsEdited(isEdited: boolean) { + this.isEdited = isEdited; + } + + getData() { + return this.isEdited && this.data ? this.data : this.getDefaultData(); + } + + setData(data?: D) { + this.data = data ? Utils.clone.deepClone(data) : undefined; + } + + getContextItem(): ExtendedContextItem { + return { + name: this.name, + isEdited: this.isEdited, + data: this.getData(), + extraData: this.extraData, + }; + } +} + +export default ContextProvider; diff --git a/src/js/context/providers/base/JSONSchemaDataProvider.ts b/src/js/context/providers/base/JSONSchemaDataProvider.ts new file mode 100644 index 00000000..dddf64b5 --- /dev/null +++ b/src/js/context/providers/base/JSONSchemaDataProvider.ts @@ -0,0 +1,33 @@ +/* eslint-disable class-methods-use-this */ +import type { JSONSchema } from "@mat3ra/esse/dist/js/esse/utils"; + +import type { ContextItem, EntityName, ExternalContext } from "./ContextProvider"; +import ContextProvider from "./ContextProvider"; + +export interface JinjaExternalContext extends ExternalContext { + isUsingJinjaVariables?: boolean; +} + +/** + * @summary Provides jsonSchema only. + */ +abstract class JSONSchemaDataProvider< + N extends string = string, + D extends object = object, + ED extends object = object, + EC extends JinjaExternalContext = JinjaExternalContext, + // eslint-disable-next-line prettier/prettier +> extends ContextProvider { + abstract readonly jsonSchema: JSONSchema | undefined; + + readonly entityName: EntityName = "unit"; + + isUsingJinjaVariables: boolean; + + constructor(contextItem: ContextItem, externalContext: EC) { + super(contextItem, externalContext); + this.isUsingJinjaVariables = Boolean(externalContext?.isUsingJinjaVariables); + } +} + +export default JSONSchemaDataProvider; diff --git a/src/js/context/providers/base/JSONSchemaFormDataProvider.ts b/src/js/context/providers/base/JSONSchemaFormDataProvider.ts new file mode 100644 index 00000000..8661ac51 --- /dev/null +++ b/src/js/context/providers/base/JSONSchemaFormDataProvider.ts @@ -0,0 +1,40 @@ +/* eslint-disable class-methods-use-this */ +// import { JSONSchemaDataProvider } from "@mat3ra/ade"; +import type { UiSchema } from "react-jsonschema-form"; + +import JSONSchemaDataProvider, { type JinjaExternalContext } from "./JSONSchemaDataProvider"; + +/** + * @summary Provides jsonSchema and uiSchema for generating react-jsonschema-form + * See https://github.com/mozilla-services/react-jsonschema-form for Form UI. + * Form generation example: + * ``` + *
+ * ``` + */ +abstract class JSONSchemaFormDataProvider< + N extends string = string, + D extends object = object, + ED extends object = object, + EC extends JinjaExternalContext = JinjaExternalContext, +> extends JSONSchemaDataProvider { + fields: object = {}; + + protected abstract uiSchema: UiSchema; + + get uiSchemaStyled(): UiSchema { + return Object.fromEntries( + Object.entries(this.uiSchema).map(([key, value]) => [ + key, + { + ...value, + classNames: `${value.classNames || ""}`, + }, + ]), + ); + } +} + +export default JSONSchemaFormDataProvider; diff --git a/src/js/context/providers/by_application/ExecutableContextProvider.js b/src/js/context/providers/by_application/ExecutableContextProvider.js deleted file mode 100644 index 07b8e610..00000000 --- a/src/js/context/providers/by_application/ExecutableContextProvider.js +++ /dev/null @@ -1,17 +0,0 @@ -import { ContextProvider } from "@mat3ra/ade"; -import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; - -export default class ExecutableContextProvider extends ContextProvider { - jsonSchemaId = "context-provider"; - - constructor(config) { - super({ - ...config, - domain: "executable", - }); - } - - get jsonSchema() { - return JSONSchemasInterface.getSchemaById(this.jsonSchemaId); - } -} diff --git a/src/js/context/providers/by_application/espresso/QENEBContextProvider.js b/src/js/context/providers/by_application/espresso/QENEBContextProvider.js deleted file mode 100644 index f4e067d8..00000000 --- a/src/js/context/providers/by_application/espresso/QENEBContextProvider.js +++ /dev/null @@ -1,58 +0,0 @@ -import lodash from "lodash"; - -import { jobContextMixin } from "../../../mixins/JobContextMixin"; -import { materialContextMixin } from "../../../mixins/MaterialContextMixin"; -import { materialsContextMixin } from "../../../mixins/MaterialsContextMixin"; -import { materialsSetContextMixin } from "../../../mixins/MaterialsSetContextMixin"; -import { methodDataContextMixin } from "../../../mixins/MethodDataContextMixin"; -import { workflowContextMixin } from "../../../mixins/WorkflowContextMixin"; -import ExecutableContextProvider from "../ExecutableContextProvider"; -import QEPWXContextProvider from "./QEPWXContextProvider"; - -export default class QENEBContextProvider extends ExecutableContextProvider { - jsonSchemaId = "context-providers-directory/by-application/qe-neb-context-provider"; - - _material = undefined; - - _materials = []; - - _materialsSet = undefined; - - constructor(config) { - super(config); - this.initJobContextMixin(); - this.initMaterialsContextMixin(); - this.initMethodDataContextMixin(); - this.initWorkflowContextMixin(); - this.initMaterialContextMixin(); - this.initMaterialsSetContextMixin(); - } - - getData() { - const sortedMaterials = this.sortMaterialsByIndexInSet(this.materials); - const PWXContexts = sortedMaterials.map((material) => { - const context = { ...this.config.context, material }; - const config = { ...this.config, context }; - return new QEPWXContextProvider(config).getData(); - }); - - return { - ...lodash.omit(PWXContexts[0], [ - "ATOMIC_POSITIONS", - "ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS", - ]), - FIRST_IMAGE: PWXContexts[0].ATOMIC_POSITIONS, - LAST_IMAGE: PWXContexts[PWXContexts.length - 1].ATOMIC_POSITIONS, - INTERMEDIATE_IMAGES: PWXContexts.slice(1, PWXContexts.length - 1).map( - (data) => data.ATOMIC_POSITIONS, - ), - }; - } -} - -materialContextMixin(QENEBContextProvider.prototype); -materialsContextMixin(QENEBContextProvider.prototype); -methodDataContextMixin(QENEBContextProvider.prototype); -workflowContextMixin(QENEBContextProvider.prototype); -jobContextMixin(QENEBContextProvider.prototype); -materialsSetContextMixin(QENEBContextProvider.prototype); diff --git a/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts b/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts new file mode 100644 index 00000000..46526cfb --- /dev/null +++ b/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts @@ -0,0 +1,111 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { + QENEBContextProviderSchema, + QEPwxContextProviderSchema, +} from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import jobContextMixin, { + type JobContextMixin, + type JobExternalContext, +} from "../../../mixins/JobContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../../mixins/MaterialContextMixin"; +import materialsContextMixin, { + type MaterialsContextMixin, + type MaterialsExternalContext, +} from "../../../mixins/MaterialsContextMixin"; +import materialsSetContextMixin, { + type MaterialsSetContextMixin, +} from "../../../mixins/MaterialsSetContextMixin"; +import methodDataContextMixin, { + type MethodDataContextMixin, + type MethodDataExternalContext, +} from "../../../mixins/MethodDataContextMixin"; +import workflowContextMixin, { + type WorkflowContextMixin, + type WorkflowExternalContext, +} from "../../../mixins/WorkflowContextMixin"; +import type { ContextItem, Domain } from "../../base/ContextProvider"; +import JSONSchemaDataProvider, { + type JinjaExternalContext, +} from "../../base/JSONSchemaDataProvider"; +import QEPWXContextProvider from "./QEPWXContextProvider"; + +const jsonSchemaId = "context-providers-directory/by-application/qe-neb-context-provider"; + +type Name = "input"; +type Data = QENEBContextProviderSchema; +type ExternalContext = JinjaExternalContext & + WorkflowExternalContext & + JobExternalContext & + MaterialsExternalContext & + MethodDataExternalContext & + MaterialsSetContextMixin & + MaterialExternalContext; + +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor; + +function atomicPositionsToString(atomicPositions: QEPwxContextProviderSchema["ATOMIC_POSITIONS"]) { + return atomicPositions.map(({ X, x, y, z }) => `${X} ${x} ${y} ${z}`).join("\n"); +} + +export default class QENEBContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "input"; + + readonly domain: Domain = "executable"; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.initJobContextMixin(externalContext); + this.initMaterialsContextMixin(externalContext); + this.initMethodDataContextMixin(externalContext); + this.initWorkflowContextMixin(externalContext); + this.initMaterialContextMixin(externalContext); + this.initMaterialsSetContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getSchemaById(jsonSchemaId); + } + + getDefaultData(): Data { + const PWXContexts = this.sortMaterialsByIndexInSet(this.materials).map((material) => { + return new QEPWXContextProvider({}, { ...this.externalContext, material }).getData(); + }); + + const { + ATOMIC_POSITIONS, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: _, + ...rest + } = PWXContexts[0]; + + return { + ...rest, + FIRST_IMAGE: atomicPositionsToString(ATOMIC_POSITIONS), + LAST_IMAGE: atomicPositionsToString( + PWXContexts[PWXContexts.length - 1].ATOMIC_POSITIONS, + ), + INTERMEDIATE_IMAGES: PWXContexts.slice(1, PWXContexts.length - 1).map((data) => + atomicPositionsToString(data.ATOMIC_POSITIONS), + ), + }; + } +} + +materialContextMixin(QENEBContextProvider.prototype); +materialsContextMixin(QENEBContextProvider.prototype); +methodDataContextMixin(QENEBContextProvider.prototype); +workflowContextMixin(QENEBContextProvider.prototype); +jobContextMixin(QENEBContextProvider.prototype); +materialsSetContextMixin(QENEBContextProvider.prototype); diff --git a/src/js/context/providers/by_application/espresso/QEPWXContextProvider.js b/src/js/context/providers/by_application/espresso/QEPWXContextProvider.js deleted file mode 100644 index b1208588..00000000 --- a/src/js/context/providers/by_application/espresso/QEPWXContextProvider.js +++ /dev/null @@ -1,168 +0,0 @@ -import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js"; -import path from "path"; -import s from "underscore.string"; - -import { jobContextMixin } from "../../../mixins/JobContextMixin"; -import { materialContextMixin } from "../../../mixins/MaterialContextMixin"; -import { materialsContextMixin } from "../../../mixins/MaterialsContextMixin"; -import { methodDataContextMixin } from "../../../mixins/MethodDataContextMixin"; -import { workflowContextMixin } from "../../../mixins/WorkflowContextMixin"; -import ExecutableContextProvider from "../ExecutableContextProvider"; - -export default class QEPWXContextProvider extends ExecutableContextProvider { - jsonSchemaId = "context-providers-directory/by-application/qe-pwx-context-provider"; - - _material = undefined; - - _materials = []; - - constructor(config) { - super(config); - this.initMaterialsContextMixin(); - this.initMethodDataContextMixin(); - this.initWorkflowContextMixin(); - this.initJobContextMixin(); - this.initMaterialContextMixin(); - } - - static atomSymbols(material) { - return material.Basis.uniqueElements; - } - - static uniqueElementsWithLabels(material) { - // return unique items - return [...new Set(material.Basis.elementsWithLabelsArray)]; - } - - /** Returns the input text block for atomic positions WITH constraints. - */ - static atomicPositionsWithConstraints(material) { - return material.Basis.getAtomicPositionsWithConstraintsAsStrings().join("\n"); - } - - /** Returns the input text block for atomic positions - * Note: does NOT include constraints - */ - static atomicPositions(material) { - return material.Basis.atomicPositions.join("\n"); - } - - static NAT(material) { - return material.Basis.atomicPositions.length; - } - - static NTYP(material) { - return material.Basis.uniqueElements.length; - } - - static NTYP_WITH_LABELS(material) { - return this.uniqueElementsWithLabels(material).length; - } - - buildQEPWXContext(material) { - const IBRAV = 0; // use CELL_PARAMETERS to define Bravais lattice - - return { - IBRAV, - RESTART_MODE: this.RESTART_MODE, - ATOMIC_SPECIES: this.ATOMIC_SPECIES(material), - ATOMIC_SPECIES_WITH_LABELS: this.ATOMIC_SPECIES_WITH_LABELS(material), - NAT: QEPWXContextProvider.NAT(material), - NTYP: QEPWXContextProvider.NTYP(material), - NTYP_WITH_LABELS: QEPWXContextProvider.NTYP_WITH_LABELS(material), - ATOMIC_POSITIONS: QEPWXContextProvider.atomicPositionsWithConstraints(material), - ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: QEPWXContextProvider.atomicPositions(material), - CELL_PARAMETERS: QEPWXContextProvider.CELL_PARAMETERS(material), - }; - } - - getDataPerMaterial() { - if (!this.materials || this.materials.length <= 1) return {}; - return { perMaterial: this.materials.map((material) => this.buildQEPWXContext(material)) }; - } - - /* - * @NOTE: Overriding getData makes this provider "stateless", ie. delivering data from scratch each time and not - * considering the content of `this.data`, and `this.isEdited` field(s). - */ - getData() { - // the below values are read from PlanewaveDataManager instead - // ECUTWFC = 40; - // ECUTRHO = 200; - - return { - ...this.buildQEPWXContext(this.material), - ...this.getDataPerMaterial(), - }; - } - - get RESTART_MODE() { - return this.job.parentJob || this.workflow.hasRelaxation ? "restart" : "from_scratch"; - } - - getPseudoBySymbol(symbol) { - return (this.methodData.pseudo || []).find((p) => p.element === symbol); - } - - /** Builds ATOMIC SPECIES block of pw.x input in the format - * X Mass_X PseudoPot_X - * where X is the atom label - * Mass_X is the mass of element X [amu] - * PseudoPot_X is the pseudopotential filename associated with element X - * - * Note: assumes this.methodData is defined - */ - ATOMIC_SPECIES(material) { - return QEPWXContextProvider.atomSymbols(material) - .map((symbol) => { - const pseudo = this.getPseudoBySymbol(symbol); - return QEPWXContextProvider.symbolToAtomicSpecie(symbol, pseudo); - }) - .join("\n"); - } - - ATOMIC_SPECIES_WITH_LABELS(material) { - return QEPWXContextProvider.uniqueElementsWithLabels(material) - .map((symbol) => { - const symbolWithoutLabel = symbol.replace(/\d$/, ""); - const label = symbol.match(/\d$/g) ? symbol.match(/\d$/g)?.[0] : ""; - const pseudo = this.getPseudoBySymbol(symbolWithoutLabel); - return QEPWXContextProvider.elementAndPseudoToAtomicSpecieWithLabels( - symbolWithoutLabel, - pseudo, - label, - ); - }) - .join("\n"); - } - - static CELL_PARAMETERS(material) { - return material.Lattice.vectorArrays - .map((x) => { - return x - .map((y) => { - return s.sprintf("%14.9f", y).trim(); - }) - .join(" "); - }) - .join("\n"); - } - - static symbolToAtomicSpecie(symbol, pseudo) { - const el = PERIODIC_TABLE[symbol]; - const filename = pseudo?.filename || path.basename(pseudo?.path || ""); - return s.sprintf("%s %f %s", symbol, el.atomic_mass, filename) || ""; - } - - static elementAndPseudoToAtomicSpecieWithLabels(symbol, pseudo, label = "") { - const el = PERIODIC_TABLE[symbol]; - const filename = pseudo?.filename || path.basename(pseudo?.path || ""); - return s.sprintf("%s%s %f %s", symbol, label, el.atomic_mass, filename) || ""; - } -} - -materialContextMixin(QEPWXContextProvider.prototype); -materialsContextMixin(QEPWXContextProvider.prototype); -methodDataContextMixin(QEPWXContextProvider.prototype); -workflowContextMixin(QEPWXContextProvider.prototype); -jobContextMixin(QEPWXContextProvider.prototype); diff --git a/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts b/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts new file mode 100644 index 00000000..8887983f --- /dev/null +++ b/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts @@ -0,0 +1,159 @@ +import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { QEPwxContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { Material } from "@mat3ra/made"; +import type { AtomicElementValue } from "@mat3ra/made/dist/js/basis/elements"; +import type { JSONSchema7 } from "json-schema"; +import path from "path"; + +import jobContextMixin, { + type JobContextMixin, + type JobExternalContext, +} from "../../../mixins/JobContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../../mixins/MaterialContextMixin"; +import materialsContextMixin, { + type MaterialsContextMixin, + type MaterialsExternalContext, +} from "../../../mixins/MaterialsContextMixin"; +import methodDataContextMixin, { + type MethodDataContextMixin, + type MethodDataExternalContext, +} from "../../../mixins/MethodDataContextMixin"; +import workflowContextMixin, { + type WorkflowContextMixin, + type WorkflowExternalContext, +} from "../../../mixins/WorkflowContextMixin"; +import type { ContextItem, Domain } from "../../base/ContextProvider"; +import JSONSchemaDataProvider, { + type JinjaExternalContext, +} from "../../base/JSONSchemaDataProvider"; + +type Name = "input"; +type Data = QEPwxContextProviderSchema; +type ExternalContext = JinjaExternalContext & + WorkflowExternalContext & + MaterialExternalContext & + JobExternalContext & + MethodDataExternalContext & + MaterialsExternalContext; + +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor; + +const jsonSchemaId = "context-providers-directory/by-application/qe-pwx-context-provider"; + +export default class QEPWXContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "input"; + + readonly domain: Domain = "executable"; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.initMaterialsContextMixin(externalContext); + this.initMethodDataContextMixin(externalContext); + this.initWorkflowContextMixin(externalContext); + this.initJobContextMixin(externalContext); + this.initMaterialContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getSchemaById(jsonSchemaId); + } + + private buildQEPWXContext(material: Material): Data { + const { Basis: basis, Lattice: lattice } = material; + const { job, workflow } = this; + + const ATOMIC_SPECIES = basis.uniqueElements.map((symbol) => { + const pseudo = (this.methodData?.pseudo || []).find((p) => p.element === symbol); + return { + X: symbol, + Mass_X: PERIODIC_TABLE[symbol].atomic_mass, + PseudoPot_X: pseudo?.filename || path.basename(pseudo?.path || ""), + }; + // return s.sprintf("%s %f %s", symbol, el.atomic_mass, filename) || ""; + }); // .join("\n"); + + const uniqueElementsWithLabels = [...new Set(basis.elementsWithLabelsArray)]; + + const ATOMIC_SPECIES_WITH_LABELS = uniqueElementsWithLabels.map((symbol) => { + const symbolWithoutLabel = symbol.replace(/\d$/, "") as AtomicElementValue; + const label = symbol.match(/\d$/g) ? symbol.match(/\d$/g)?.[0] : ""; + const pseudo = (this.methodData?.pseudo || []).find( + (p) => p.element === symbolWithoutLabel, + ); + return { + X: `${symbolWithoutLabel}${label}`, + Mass_X: PERIODIC_TABLE[symbol].atomic_mass, + PseudoPot_X: pseudo?.filename || path.basename(pseudo?.path || ""), + }; + // return s.sprintf("%s%s %f %s", symbol, label, el.atomic_mass, filename) || ""; + }); // .join("\n"); + + // Format numbers with 14 total width, 9 decimal places (equivalent to %14.9f) + // const formatNumber = (num: number) => { + // return Number(num.toFixed(9).padStart(14).trim()); + // }; + + const CELL_PARAMETERS = { + v1: lattice.vectorArrays[0], + v2: lattice.vectorArrays[1], + v3: lattice.vectorArrays[2], + }; + + // const ATOMIC_POSITIONS = basis.getAtomicPositionsWithConstraintsAsStrings().join("\n"); + const ATOMIC_POSITIONS = basis.elementsAndCoordinatesAndLabelsArray.map( + ([element, coordinate, label]) => { + return { + X: `${element}${label}`, + x: coordinate[0], + y: coordinate[1], + z: coordinate[2], + }; + }, + ); + + return { + IBRAV: 0, // use CELL_PARAMETERS to define Bravais lattice + RESTART_MODE: job.parent || workflow.hasRelaxation ? "restart" : "from_scratch", + ATOMIC_SPECIES, + ATOMIC_SPECIES_WITH_LABELS, + NAT: basis.atomicPositions.length, + NTYP: basis.uniqueElements.length, + NTYP_WITH_LABELS: uniqueElementsWithLabels.length, + ATOMIC_POSITIONS, + ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: basis.atomicPositions.join("\n"), + CELL_PARAMETERS, + }; + } + + private getDataPerMaterial() { + if (!this.materials || this.materials.length <= 1) return {}; + return { perMaterial: this.materials.map((material) => this.buildQEPWXContext(material)) }; + } + + getDefaultData() { + // the below values are read from PlanewaveDataManager instead + // ECUTWFC = 40; + // ECUTRHO = 200; + + return { + ...this.buildQEPWXContext(this.material), + ...this.getDataPerMaterial(), + }; + } +} + +materialContextMixin(QEPWXContextProvider.prototype); +materialsContextMixin(QEPWXContextProvider.prototype); +methodDataContextMixin(QEPWXContextProvider.prototype); +workflowContextMixin(QEPWXContextProvider.prototype); +jobContextMixin(QEPWXContextProvider.prototype); diff --git a/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.js b/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.js deleted file mode 100644 index 148db5c5..00000000 --- a/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.js +++ /dev/null @@ -1,89 +0,0 @@ -import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js"; -import lodash from "lodash"; -import _ from "underscore"; -import s from "underscore.string"; - -import { jobContextMixin } from "../../../mixins/JobContextMixin"; -import { materialContextMixin } from "../../../mixins/MaterialContextMixin"; -import { methodDataContextMixin } from "../../../mixins/MethodDataContextMixin"; -import { workflowContextMixin } from "../../../mixins/WorkflowContextMixin"; -import ExecutableContextProvider from "../ExecutableContextProvider"; - -export default class NWChemTotalEnergyContextProvider extends ExecutableContextProvider { - jsonSchemaId = - "context-providers-directory/by-application/nwchem-total-energy-context-provider"; - - _material = undefined; - - constructor(config) { - super(config); - this.initMethodDataContextMixin(); - this.initWorkflowContextMixin(); - this.initJobContextMixin(); - this.initMaterialContextMixin(); - } - - get atomicPositionsWithoutConstraints() { - return this.material.Basis.atomicPositions; - } - - get atomicPositions() { - const basis = this.material.Basis; - basis.toCartesian(); - return basis.getAtomicPositionsWithConstraintsAsStrings(); - } - - get atomSymbols() { - return this.material.Basis.uniqueElements; - } - - get cartesianAtomicPositions() { - return this.material.Basis.toCartesian !== undefined; - } - - get ATOMIC_SPECIES() { - return _.map(this.atomSymbols, (symbol) => { - return NWChemTotalEnergyContextProvider.symbolToAtomicSpecies(symbol); - }).join("\n"); - } - - /* - * @NOTE: Overriding getData makes this provider "stateless", ie. delivering data from scratch each time and not - * considering the content of `this.data`, and `this.isEdited` field(s). - */ - getData() { - /* - TODO: Create ability for user to define CHARGE, MULT, BASIS and FUNCTIONAL parameters. - */ - const CHARGE = 0; - const MULT = 1; - const BASIS = "6-31G"; - const FUNCTIONAL = "B3LYP"; - - return { - CHARGE, - MULT, - BASIS, - NAT: this.atomicPositions.length, - NTYP: this.atomSymbols.length, - ATOMIC_POSITIONS: this.atomicPositions.join("\n"), - ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS: this.atomicPositionsWithoutConstraints.join("\n"), - ATOMIC_SPECIES: this.ATOMIC_SPECIES, - FUNCTIONAL, - CARTESIAN: this.cartesianAtomicPositions, - }; - } - - static symbolToAtomicSpecies(symbol, pseudo) { - const el = PERIODIC_TABLE[symbol]; - const filename = pseudo - ? lodash.get(pseudo, "filename", s.strRightBack(pseudo.path || "", "/")) - : ""; - return el ? s.sprintf("%s %f %s", symbol, el.atomic_mass, filename) : undefined; - } -} - -materialContextMixin(NWChemTotalEnergyContextProvider.prototype); -methodDataContextMixin(NWChemTotalEnergyContextProvider.prototype); -workflowContextMixin(NWChemTotalEnergyContextProvider.prototype); -jobContextMixin(NWChemTotalEnergyContextProvider.prototype); diff --git a/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.ts b/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.ts new file mode 100644 index 00000000..e8c3c8bf --- /dev/null +++ b/src/js/context/providers/by_application/nwchem/NWChemTotalEnergyContextProvider.ts @@ -0,0 +1,95 @@ +import { PERIODIC_TABLE } from "@exabyte-io/periodic-table.js"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { NWChemTotalEnergyContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import jobContextMixin, { + type JobContextMixin, + type JobExternalContext, +} from "../../../mixins/JobContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../../mixins/MaterialContextMixin"; +import methodDataContextMixin, { + type MethodDataContextMixin, + type MethodDataExternalContext, +} from "../../../mixins/MethodDataContextMixin"; +import workflowContextMixin, { + type WorkflowContextMixin, + type WorkflowExternalContext, +} from "../../../mixins/WorkflowContextMixin"; +import type { ContextItem, Domain } from "../../base/ContextProvider"; +import JSONSchemaDataProvider, { + type JinjaExternalContext, +} from "../../base/JSONSchemaDataProvider"; + +type Name = "input"; +type Data = NWChemTotalEnergyContextProviderSchema; +type ExternalContext = JinjaExternalContext & + WorkflowExternalContext & + JobExternalContext & + MethodDataExternalContext & + MaterialExternalContext; + +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor & + Constructor & + Constructor; + +const jsonSchemaId = + "context-providers-directory/by-application/nwchem-total-energy-context-provider"; + +export default class NWChemTotalEnergyContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "input"; + + readonly domain: Domain = "executable"; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.initMethodDataContextMixin(externalContext); + this.initWorkflowContextMixin(externalContext); + this.initJobContextMixin(externalContext); + this.initMaterialContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getSchemaById(jsonSchemaId); + } + + /* + * TODO: Create ability for user to define CHARGE, MULT, BASIS and FUNCTIONAL parameters. + */ + getDefaultData() { + const basis = this.material.Basis; + + const NTYP = basis.uniqueElements.length; + const ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS = basis.atomicPositions.join("\n") || ""; + const ATOMIC_SPECIES = basis.uniqueElements + .map((symbol) => `${symbol} ${PERIODIC_TABLE[symbol].atomic_mass} `) + .join("\n"); + + basis.toCartesian(); + const atomicPositions = basis.getAtomicPositionsWithConstraintsAsStrings(); + + return { + CHARGE: 0, + MULT: 1, + BASIS: "6-31G", + NAT: atomicPositions.length, + NTYP, + ATOMIC_POSITIONS: atomicPositions.join("\n"), + ATOMIC_POSITIONS_WITHOUT_CONSTRAINTS, + ATOMIC_SPECIES, + FUNCTIONAL: "B3LYP", + CARTESIAN: basis.toCartesian !== undefined, + }; + } +} + +materialContextMixin(NWChemTotalEnergyContextProvider.prototype); +methodDataContextMixin(NWChemTotalEnergyContextProvider.prototype); +workflowContextMixin(NWChemTotalEnergyContextProvider.prototype); +jobContextMixin(NWChemTotalEnergyContextProvider.prototype); diff --git a/src/js/context/providers/by_application/vasp/VASPContextProvider.js b/src/js/context/providers/by_application/vasp/VASPContextProvider.js deleted file mode 100644 index b359a583..00000000 --- a/src/js/context/providers/by_application/vasp/VASPContextProvider.js +++ /dev/null @@ -1,58 +0,0 @@ -import { jobContextMixin } from "../../../mixins/JobContextMixin"; -import { materialContextMixin } from "../../../mixins/MaterialContextMixin"; -import { materialsContextMixin } from "../../../mixins/MaterialsContextMixin"; -import { methodDataContextMixin } from "../../../mixins/MethodDataContextMixin"; -import { workflowContextMixin } from "../../../mixins/WorkflowContextMixin"; -import ExecutableContextProvider from "../ExecutableContextProvider"; - -export default class VASPContextProvider extends ExecutableContextProvider { - jsonSchemaId = "context-providers-directory/by-application/vasp-context-provider"; - - _material = undefined; - - _materials = []; - - constructor(config) { - super(config); - this.initJobContextMixin(); - this.initMaterialsContextMixin(); - this.initMethodDataContextMixin(); - this.initWorkflowContextMixin(); - this.initMaterialContextMixin(); - } - - // eslint-disable-next-line class-methods-use-this - buildVASPContext(material) { - return { - // TODO: figure out whether we need two separate POSCARS, maybe one is enough - POSCAR: material.getAsPOSCAR(true, true), - POSCAR_WITH_CONSTRAINTS: material.getAsPOSCAR(true), - }; - } - - getDataPerMaterial() { - if (!this.materials || this.materials.length <= 1) return {}; - return { perMaterial: this.materials.map((material) => this.buildVASPContext(material)) }; - } - - /* - * @NOTE: Overriding getData makes this provider "stateless", ie. delivering data from scratch each time and not - * considering the content of `this.data`, and `this.isEdited` field(s). - */ - getData() { - // consider adjusting so that below values are read from PlanewaveDataManager - // ECUTWFC; - // ECUTRHO; - - return { - ...this.buildVASPContext(this.material), - ...this.getDataPerMaterial(), - }; - } -} - -materialContextMixin(VASPContextProvider.prototype); -materialsContextMixin(VASPContextProvider.prototype); -methodDataContextMixin(VASPContextProvider.prototype); -workflowContextMixin(VASPContextProvider.prototype); -jobContextMixin(VASPContextProvider.prototype); diff --git a/src/js/context/providers/by_application/vasp/VASPContextProvider.ts b/src/js/context/providers/by_application/vasp/VASPContextProvider.ts new file mode 100644 index 00000000..59369245 --- /dev/null +++ b/src/js/context/providers/by_application/vasp/VASPContextProvider.ts @@ -0,0 +1,99 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { VASPContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { Material } from "@mat3ra/made"; +import type { JSONSchema7 } from "json-schema"; + +import jobContextMixin, { + type JobContextMixin, + type JobExternalContext, +} from "../../../mixins/JobContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../../mixins/MaterialContextMixin"; +import materialsContextMixin, { + type MaterialsContextMixin, +} from "../../../mixins/MaterialsContextMixin"; +import methodDataContextMixin, { + type MethodDataContextMixin, + type MethodDataExternalContext, +} from "../../../mixins/MethodDataContextMixin"; +import workflowContextMixin, { + type WorkflowContextMixin, + type WorkflowExternalContext, +} from "../../../mixins/WorkflowContextMixin"; +import type { ContextItem, Domain } from "../../base/ContextProvider"; +import JSONSchemaDataProvider, { + type JinjaExternalContext, +} from "../../base/JSONSchemaDataProvider"; + +type Name = "input"; +type Data = VASPContextProviderSchema; +type ExternalContext = JinjaExternalContext & + WorkflowExternalContext & + JobExternalContext & + MaterialExternalContext & + MethodDataExternalContext & + MaterialsContextMixin; + +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor; + +const jsonSchemaId = "context-providers-directory/by-application/vasp-context-provider"; + +export default class VASPContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "input"; + + readonly domain: Domain = "executable"; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.initJobContextMixin(externalContext); + this.initMaterialsContextMixin(externalContext); + this.initMethodDataContextMixin(externalContext); + this.initWorkflowContextMixin(externalContext); + this.initMaterialContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getSchemaById(jsonSchemaId); + } + + // eslint-disable-next-line class-methods-use-this + private buildVASPContext(material: Material): Data { + return { + // TODO: figure out whether we need two separate POSCARS, maybe one is enough + POSCAR: material.getAsPOSCAR(true, true), + POSCAR_WITH_CONSTRAINTS: material.getAsPOSCAR(true), + }; + } + + private getDataPerMaterial() { + if (!this.materials || this.materials.length <= 1) return {}; + + // TODO-QUESTION: perMaterial is not defined in the schema + return { perMaterial: this.materials.map((material) => this.buildVASPContext(material)) }; + } + + getDefaultData() { + // consider adjusting so that below values are read from PlanewaveDataManager + // ECUTWFC; + // ECUTRHO; + + return { + ...this.buildVASPContext(this.material), + ...this.getDataPerMaterial(), + }; + } +} + +materialContextMixin(VASPContextProvider.prototype); +materialsContextMixin(VASPContextProvider.prototype); +methodDataContextMixin(VASPContextProvider.prototype); +workflowContextMixin(VASPContextProvider.prototype); +jobContextMixin(VASPContextProvider.prototype); diff --git a/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.js b/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.js deleted file mode 100644 index 760a1cff..00000000 --- a/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.js +++ /dev/null @@ -1,48 +0,0 @@ -import { jobContextMixin } from "../../../mixins/JobContextMixin"; -import { materialContextMixin } from "../../../mixins/MaterialContextMixin"; -import { materialsContextMixin } from "../../../mixins/MaterialsContextMixin"; -import { materialsSetContextMixin } from "../../../mixins/MaterialsSetContextMixin"; -import { methodDataContextMixin } from "../../../mixins/MethodDataContextMixin"; -import { workflowContextMixin } from "../../../mixins/WorkflowContextMixin"; -import ExecutableContextProvider from "../ExecutableContextProvider"; -import VASPContextProvider from "./VASPContextProvider"; - -export default class VASPNEBContextProvider extends ExecutableContextProvider { - jsonSchemaId = "context-providers-directory/by-application/vasp-neb-context-provider"; - - _materials = []; - - constructor(config) { - super(config); - this.initMaterialContextMixin(); - this.initMaterialsContextMixin(); - this.initMaterialsSetContextMixin(); - this.initMethodDataContextMixin(); - this.initWorkflowContextMixin(); - this.initJobContextMixin(); - } - - getData() { - const sortedMaterials = this.sortMaterialsByIndexInSet(this.materials); - const VASPContexts = sortedMaterials.map((material) => { - const context = { ...this.config.context, material }; - const config = { ...this.config, context }; - return new VASPContextProvider(config).getData(); - }); - - return { - FIRST_IMAGE: VASPContexts[0].POSCAR_WITH_CONSTRAINTS, - LAST_IMAGE: VASPContexts[VASPContexts.length - 1].POSCAR_WITH_CONSTRAINTS, - INTERMEDIATE_IMAGES: VASPContexts.slice(1, VASPContexts.length - 1).map( - (data) => data.POSCAR_WITH_CONSTRAINTS, - ), - }; - } -} - -materialContextMixin(VASPNEBContextProvider.prototype); -materialsContextMixin(VASPNEBContextProvider.prototype); -materialsSetContextMixin(VASPNEBContextProvider.prototype); -methodDataContextMixin(VASPNEBContextProvider.prototype); -workflowContextMixin(VASPNEBContextProvider.prototype); -jobContextMixin(VASPNEBContextProvider.prototype); diff --git a/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.ts b/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.ts new file mode 100644 index 00000000..45a88060 --- /dev/null +++ b/src/js/context/providers/by_application/vasp/VASPNEBContextProvider.ts @@ -0,0 +1,93 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import type { VASPNEBContextProviderSchema } from "@mat3ra/esse/dist/js/types"; +import type { JSONSchema7 } from "json-schema"; + +import jobContextMixin, { + type JobContextMixin, + type JobExternalContext, +} from "../../../mixins/JobContextMixin"; +import materialContextMixin, { + type MaterialContextMixin, + type MaterialExternalContext, +} from "../../../mixins/MaterialContextMixin"; +import materialsContextMixin, { + type MaterialsContextMixin, +} from "../../../mixins/MaterialsContextMixin"; +import materialsSetContextMixin, { + type MaterialsSetContextMixin, +} from "../../../mixins/MaterialsSetContextMixin"; +import methodDataContextMixin, { + type MethodDataContextMixin, + type MethodDataExternalContext, +} from "../../../mixins/MethodDataContextMixin"; +import workflowContextMixin, { + type WorkflowContextMixin, + type WorkflowExternalContext, +} from "../../../mixins/WorkflowContextMixin"; +import type { ContextItem, Domain } from "../../base/ContextProvider"; +import JSONSchemaDataProvider, { + type JinjaExternalContext, +} from "../../base/JSONSchemaDataProvider"; +import VASPContextProvider from "./VASPContextProvider"; + +type Name = "input"; +type Data = VASPNEBContextProviderSchema; +type ExternalContext = JinjaExternalContext & + WorkflowExternalContext & + JobExternalContext & + MaterialExternalContext & + MethodDataExternalContext & + MaterialsContextMixin & + MaterialsSetContextMixin; + +type Base = typeof JSONSchemaDataProvider & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor; + +const jsonSchemaId = "context-providers-directory/by-application/vasp-neb-context-provider"; + +export default class VASPNEBContextProvider extends (JSONSchemaDataProvider as Base) { + readonly name: Name = "input"; + + readonly domain: Domain = "executable"; + + readonly jsonSchema: JSONSchema7 | undefined; + + constructor(config: ContextItem, externalContext: ExternalContext) { + super(config, externalContext); + this.initMaterialContextMixin(externalContext); + this.initMaterialsContextMixin(externalContext); + this.initMaterialsSetContextMixin(externalContext); + this.initMethodDataContextMixin(externalContext); + this.initWorkflowContextMixin(externalContext); + this.initJobContextMixin(externalContext); + + this.jsonSchema = JSONSchemasInterface.getSchemaById(jsonSchemaId); + } + + getDefaultData() { + const VASPContexts = this.sortMaterialsByIndexInSet(this.materials).map((material) => { + return new VASPContextProvider({}, { ...this.externalContext, material }).getData(); + }); + + return { + FIRST_IMAGE: VASPContexts[0].POSCAR_WITH_CONSTRAINTS, + LAST_IMAGE: VASPContexts[VASPContexts.length - 1].POSCAR_WITH_CONSTRAINTS, + INTERMEDIATE_IMAGES: VASPContexts.slice(1, VASPContexts.length - 1).map((data) => { + return data.POSCAR_WITH_CONSTRAINTS; + }), + }; + } +} + +materialContextMixin(VASPNEBContextProvider.prototype); +materialsContextMixin(VASPNEBContextProvider.prototype); +materialsSetContextMixin(VASPNEBContextProvider.prototype); +methodDataContextMixin(VASPNEBContextProvider.prototype); +workflowContextMixin(VASPNEBContextProvider.prototype); +jobContextMixin(VASPNEBContextProvider.prototype); diff --git a/src/js/context/providers/settings.js b/src/js/context/providers/settings.ts similarity index 84% rename from src/js/context/providers/settings.js rename to src/js/context/providers/settings.ts index 7ce2dfd0..ccb19e9f 100644 --- a/src/js/context/providers/settings.js +++ b/src/js/context/providers/settings.ts @@ -16,15 +16,15 @@ class GlobalSettings { return this["PointsGridFormDataProvider.defaultKPPRA"]; } - setApplication(application) { + setApplication(application: typeof Application) { this.Application = application; } - setMaterial(material) { + setMaterial(material: typeof Made.Material) { this.Material = material; } - setDefaultKPPRA(kppra) { + setDefaultKPPRA(kppra: number) { this["PointsGridFormDataProvider.defaultKPPRA"] = kppra; } diff --git a/src/js/enums.js b/src/js/enums.ts similarity index 81% rename from src/js/enums.js rename to src/js/enums.ts index ec766a4a..675ab294 100644 --- a/src/js/enums.js +++ b/src/js/enums.ts @@ -21,6 +21,20 @@ export const UNIT_TYPES = { assertion: "assertion", }; +export enum UnitType { + convergence = "convergence", + exit = "exit", + execution = "execution", + map = "map", + reduce = "reduce", + assignment = "assignment", + condition = "condition", + subworkflow = "subworkflow", + processing = "processing", + io = "io", + assertion = "assertion", +} + export const UNIT_STATUSES = { idle: "idle", active: "active", diff --git a/src/js/generated/AssertionUnitSchemaMixin.ts b/src/js/generated/AssertionUnitSchemaMixin.ts new file mode 100644 index 00000000..7df97859 --- /dev/null +++ b/src/js/generated/AssertionUnitSchemaMixin.ts @@ -0,0 +1,34 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { AssertionUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type AssertionUnitSchemaMixin = AssertionUnitMixinSchema; + +export type AssertionUnitInMemoryEntity = InMemoryEntity & AssertionUnitSchemaMixin; + +export function assertionUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & AssertionUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & AssertionUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: AssertionUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get statement() { + return this.requiredProp("statement"); + }, + set statement(value: AssertionUnitMixinSchema["statement"]) { + this.setProp("statement", value); + }, + get errorMessage() { + return this.prop("errorMessage"); + }, + set errorMessage(value: AssertionUnitMixinSchema["errorMessage"]) { + this.setProp("errorMessage", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/AssignmentUnitSchemaMixin.ts b/src/js/generated/AssignmentUnitSchemaMixin.ts new file mode 100644 index 00000000..2ffc3f76 --- /dev/null +++ b/src/js/generated/AssignmentUnitSchemaMixin.ts @@ -0,0 +1,40 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { AssignmentUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type AssignmentUnitSchemaMixin = AssignmentUnitMixinSchema; + +export type AssignmentUnitInMemoryEntity = InMemoryEntity & AssignmentUnitSchemaMixin; + +export function assignmentUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & AssignmentUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & AssignmentUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: AssignmentUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get input() { + return this.prop("input"); + }, + set input(value: AssignmentUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + get operand() { + return this.requiredProp("operand"); + }, + set operand(value: AssignmentUnitMixinSchema["operand"]) { + this.setProp("operand", value); + }, + get value() { + return this.requiredProp("value"); + }, + set value(value: AssignmentUnitMixinSchema["value"]) { + this.setProp("value", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/BaseUnitSchemaMixin.ts b/src/js/generated/BaseUnitSchemaMixin.ts new file mode 100644 index 00000000..e03cabb0 --- /dev/null +++ b/src/js/generated/BaseUnitSchemaMixin.ts @@ -0,0 +1,64 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { WorkflowBaseUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type BaseUnitSchemaMixin = WorkflowBaseUnitMixinSchema; + +export type BaseUnitInMemoryEntity = InMemoryEntity & BaseUnitSchemaMixin; + +export function baseUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & BaseUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & BaseUnitSchemaMixin = { + get isDraft() { + return this.prop("isDraft"); + }, + set isDraft(value: WorkflowBaseUnitMixinSchema["isDraft"]) { + this.setProp("isDraft", value); + }, + get type() { + return this.requiredProp("type"); + }, + set type(value: WorkflowBaseUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get name() { + return this.prop("name"); + }, + set name(value: WorkflowBaseUnitMixinSchema["name"]) { + this.setProp("name", value); + }, + get status() { + return this.prop("status"); + }, + set status(value: WorkflowBaseUnitMixinSchema["status"]) { + this.setProp("status", value); + }, + get head() { + return this.prop("head"); + }, + set head(value: WorkflowBaseUnitMixinSchema["head"]) { + this.setProp("head", value); + }, + get flowchartId() { + return this.requiredProp("flowchartId"); + }, + set flowchartId(value: WorkflowBaseUnitMixinSchema["flowchartId"]) { + this.setProp("flowchartId", value); + }, + get next() { + return this.prop("next"); + }, + set next(value: WorkflowBaseUnitMixinSchema["next"]) { + this.setProp("next", value); + }, + get enableRender() { + return this.prop("enableRender"); + }, + set enableRender(value: WorkflowBaseUnitMixinSchema["enableRender"]) { + this.setProp("enableRender", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ConditionUnitSchemaMixin.ts b/src/js/generated/ConditionUnitSchemaMixin.ts new file mode 100644 index 00000000..bef36595 --- /dev/null +++ b/src/js/generated/ConditionUnitSchemaMixin.ts @@ -0,0 +1,58 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ConditionUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type ConditionUnitSchemaMixin = ConditionUnitMixinSchema; + +export type ConditionUnitInMemoryEntity = InMemoryEntity & ConditionUnitSchemaMixin; + +export function conditionUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ConditionUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ConditionUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: ConditionUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: ConditionUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + get statement() { + return this.requiredProp("statement"); + }, + set statement(value: ConditionUnitMixinSchema["statement"]) { + this.setProp("statement", value); + }, + get then() { + return this.requiredProp("then"); + }, + set then(value: ConditionUnitMixinSchema["then"]) { + this.setProp("then", value); + }, + get else() { + return this.requiredProp("else"); + }, + set else(value: ConditionUnitMixinSchema["else"]) { + this.setProp("else", value); + }, + get maxOccurrences() { + return this.requiredProp("maxOccurrences"); + }, + set maxOccurrences(value: ConditionUnitMixinSchema["maxOccurrences"]) { + this.setProp("maxOccurrences", value); + }, + get throwException() { + return this.prop("throwException"); + }, + set throwException(value: ConditionUnitMixinSchema["throwException"]) { + this.setProp("throwException", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ExecutionUnitInputSchemaMixin.ts b/src/js/generated/ExecutionUnitInputSchemaMixin.ts new file mode 100644 index 00000000..b3c6a520 --- /dev/null +++ b/src/js/generated/ExecutionUnitInputSchemaMixin.ts @@ -0,0 +1,36 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ExecutionUnitInputItemSchema } from "@mat3ra/esse/dist/js/types"; + +export type ExecutionUnitInputSchemaMixin = ExecutionUnitInputItemSchema; + +export type ExecutionUnitInputInMemoryEntity = InMemoryEntity & ExecutionUnitInputSchemaMixin; + +export function executionUnitInputSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ExecutionUnitInputSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ExecutionUnitInputSchemaMixin = { + get template() { + return this.requiredProp("template"); + }, + set template(value: ExecutionUnitInputItemSchema["template"]) { + this.setProp("template", value); + }, + get rendered() { + return this.requiredProp("rendered"); + }, + set rendered(value: ExecutionUnitInputItemSchema["rendered"]) { + this.setProp("rendered", value); + }, + get isManuallyChanged() { + return this.requiredProp( + "isManuallyChanged", + ); + }, + set isManuallyChanged(value: ExecutionUnitInputItemSchema["isManuallyChanged"]) { + this.setProp("isManuallyChanged", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ExecutionUnitSchemaMixin.ts b/src/js/generated/ExecutionUnitSchemaMixin.ts new file mode 100644 index 00000000..e2d77e43 --- /dev/null +++ b/src/js/generated/ExecutionUnitSchemaMixin.ts @@ -0,0 +1,52 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ExecutionUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type ExecutionUnitSchemaMixin = ExecutionUnitMixinSchema; + +export type ExecutionUnitInMemoryEntity = InMemoryEntity & ExecutionUnitSchemaMixin; + +export function executionUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ExecutionUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ExecutionUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: ExecutionUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get application() { + return this.requiredProp("application"); + }, + set application(value: ExecutionUnitMixinSchema["application"]) { + this.setProp("application", value); + }, + get executable() { + return this.prop("executable"); + }, + set executable(value: ExecutionUnitMixinSchema["executable"]) { + this.setProp("executable", value); + }, + get flavor() { + return this.prop("flavor"); + }, + set flavor(value: ExecutionUnitMixinSchema["flavor"]) { + this.setProp("flavor", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: ExecutionUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + get context() { + return this.prop("context"); + }, + set context(value: ExecutionUnitMixinSchema["context"]) { + this.setProp("context", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/IOUnitSchemaMixin.ts b/src/js/generated/IOUnitSchemaMixin.ts new file mode 100644 index 00000000..5d9228da --- /dev/null +++ b/src/js/generated/IOUnitSchemaMixin.ts @@ -0,0 +1,40 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { DataIOUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type IOUnitSchemaMixin = DataIOUnitMixinSchema; + +export type IOUnitInMemoryEntity = InMemoryEntity & IOUnitSchemaMixin; + +export function iOUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & IOUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & IOUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: DataIOUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get subtype() { + return this.requiredProp("subtype"); + }, + set subtype(value: DataIOUnitMixinSchema["subtype"]) { + this.setProp("subtype", value); + }, + get source() { + return this.requiredProp("source"); + }, + set source(value: DataIOUnitMixinSchema["source"]) { + this.setProp("source", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: DataIOUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/MapUnitSchemaMixin.ts b/src/js/generated/MapUnitSchemaMixin.ts new file mode 100644 index 00000000..56c2b44a --- /dev/null +++ b/src/js/generated/MapUnitSchemaMixin.ts @@ -0,0 +1,34 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { MapUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type MapUnitSchemaMixin = MapUnitMixinSchema; + +export type MapUnitInMemoryEntity = InMemoryEntity & MapUnitSchemaMixin; + +export function mapUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & MapUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & MapUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: MapUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get workflowId() { + return this.requiredProp("workflowId"); + }, + set workflowId(value: MapUnitMixinSchema["workflowId"]) { + this.setProp("workflowId", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: MapUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ProcessingUnitSchemaMixin.ts b/src/js/generated/ProcessingUnitSchemaMixin.ts new file mode 100644 index 00000000..963c2c82 --- /dev/null +++ b/src/js/generated/ProcessingUnitSchemaMixin.ts @@ -0,0 +1,40 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ProcessingUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type ProcessingUnitSchemaMixin = ProcessingUnitMixinSchema; + +export type ProcessingUnitInMemoryEntity = InMemoryEntity & ProcessingUnitSchemaMixin; + +export function processingUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ProcessingUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ProcessingUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: ProcessingUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get operation() { + return this.requiredProp("operation"); + }, + set operation(value: ProcessingUnitMixinSchema["operation"]) { + this.setProp("operation", value); + }, + get operationType() { + return this.requiredProp("operationType"); + }, + set operationType(value: ProcessingUnitMixinSchema["operationType"]) { + this.setProp("operationType", value); + }, + get inputData() { + return this.requiredProp("inputData"); + }, + set inputData(value: ProcessingUnitMixinSchema["inputData"]) { + this.setProp("inputData", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ReduceUnitSchemaMixin.ts b/src/js/generated/ReduceUnitSchemaMixin.ts new file mode 100644 index 00000000..bd9d7250 --- /dev/null +++ b/src/js/generated/ReduceUnitSchemaMixin.ts @@ -0,0 +1,34 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ReduceUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type ReduceUnitSchemaMixin = ReduceUnitMixinSchema; + +export type ReduceUnitInMemoryEntity = InMemoryEntity & ReduceUnitSchemaMixin; + +export function reduceUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ReduceUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ReduceUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: ReduceUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + get mapFlowchartId() { + return this.requiredProp("mapFlowchartId"); + }, + set mapFlowchartId(value: ReduceUnitMixinSchema["mapFlowchartId"]) { + this.setProp("mapFlowchartId", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: ReduceUnitMixinSchema["input"]) { + this.setProp("input", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/StatusSchemaMixin.ts b/src/js/generated/StatusSchemaMixin.ts new file mode 100644 index 00000000..0501182f --- /dev/null +++ b/src/js/generated/StatusSchemaMixin.ts @@ -0,0 +1,28 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { StatusSchema } from "@mat3ra/esse/dist/js/types"; + +export type StatusSchemaMixin = StatusSchema; + +export type StatusInMemoryEntity = InMemoryEntity & StatusSchemaMixin; + +export function statusSchemaMixin( + item: InMemoryEntity, +): asserts item is T & StatusSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & StatusSchemaMixin = { + get status() { + return this.prop("status"); + }, + set status(value: StatusSchema["status"]) { + this.setProp("status", value); + }, + get statusTrack() { + return this.prop("statusTrack"); + }, + set statusTrack(value: StatusSchema["statusTrack"]) { + this.setProp("statusTrack", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/SubworkflowSchemaMixin.ts b/src/js/generated/SubworkflowSchemaMixin.ts new file mode 100644 index 00000000..b32fbac5 --- /dev/null +++ b/src/js/generated/SubworkflowSchemaMixin.ts @@ -0,0 +1,52 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { SubworkflowMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type SubworkflowSchemaMixin = SubworkflowMixinSchema; + +export type SubworkflowInMemoryEntity = InMemoryEntity & SubworkflowSchemaMixin; + +export function subworkflowSchemaMixin( + item: InMemoryEntity, +): asserts item is T & SubworkflowSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & SubworkflowSchemaMixin = { + get properties() { + return this.prop("properties"); + }, + set properties(value: SubworkflowMixinSchema["properties"]) { + this.setProp("properties", value); + }, + get compute() { + return this.prop("compute"); + }, + set compute(value: SubworkflowMixinSchema["compute"]) { + this.setProp("compute", value); + }, + get units() { + return this.requiredProp("units"); + }, + set units(value: SubworkflowMixinSchema["units"]) { + this.setProp("units", value); + }, + get model() { + return this.requiredProp("model"); + }, + set model(value: SubworkflowMixinSchema["model"]) { + this.setProp("model", value); + }, + get application() { + return this.requiredProp("application"); + }, + set application(value: SubworkflowMixinSchema["application"]) { + this.setProp("application", value); + }, + get isDraft() { + return this.prop("isDraft"); + }, + set isDraft(value: SubworkflowMixinSchema["isDraft"]) { + this.setProp("isDraft", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/SubworkflowUnitSchemaMixin.ts b/src/js/generated/SubworkflowUnitSchemaMixin.ts new file mode 100644 index 00000000..60c1b73c --- /dev/null +++ b/src/js/generated/SubworkflowUnitSchemaMixin.ts @@ -0,0 +1,22 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { SubworkflowUnitMixinSchema } from "@mat3ra/esse/dist/js/types"; + +export type SubworkflowUnitSchemaMixin = SubworkflowUnitMixinSchema; + +export type SubworkflowUnitInMemoryEntity = InMemoryEntity & SubworkflowUnitSchemaMixin; + +export function subworkflowUnitSchemaMixin( + item: InMemoryEntity, +): asserts item is T & SubworkflowUnitSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & SubworkflowUnitSchemaMixin = { + get type() { + return this.prop("type"); + }, + set type(value: SubworkflowUnitMixinSchema["type"]) { + this.setProp("type", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/index.js b/src/js/index.js index a72cb308..e9b535c5 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -1,5 +1,5 @@ import { wodeProviders } from "./context/providers"; -import { PointsPathFormDataProvider } from "./context/providers/PointsPathFormDataProvider"; +import { PointsPathFormDataProvider } from "./context/providers/PointsPath/PointsPathFormDataProvider"; import { globalSettings } from "./context/providers/settings"; import { TAB_NAVIGATION_CONFIG, @@ -23,7 +23,7 @@ import { } from "./units"; import { builders } from "./units/builders"; import { UnitFactory } from "./units/factory"; -import { defaultMapConfig } from "./units/map"; +import { defaultMapConfig } from "./units/MapUnit"; import { createWorkflow, createWorkflowConfigs, createWorkflows, Workflow } from "./workflows"; export { diff --git a/src/js/patch.js b/src/js/patch.js deleted file mode 100644 index 309734f0..00000000 --- a/src/js/patch.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Template } from "@mat3ra/ade"; - -import { wodeProviders } from "./context/providers"; - -// We patch the static providerRegistry here so that -// Template has all context providers available -// to it when creating workflows. It is then re-exported -// from WoDe for use downstream. - -Template.setContextProvidersConfig(wodeProviders); - -export { Template }; diff --git a/src/js/subworkflows/subworkflow.js b/src/js/subworkflows/subworkflow.ts similarity index 68% rename from src/js/subworkflows/subworkflow.js rename to src/js/subworkflows/subworkflow.ts index a2b07cc7..f462d688 100644 --- a/src/js/subworkflows/subworkflow.js +++ b/src/js/subworkflows/subworkflow.ts @@ -1,68 +1,89 @@ import { Application } from "@mat3ra/ade"; +import { ContextAndRenderFieldsMixin, InMemoryEntity } from "@mat3ra/code/dist/js/entity"; import { - ContextAndRenderFieldsMixin, - NamedDefaultableRepetitionImportantSettingsInMemoryEntity, -} from "@mat3ra/code/dist/js/entity"; -import { Model, ModelFactory } from "@mat3ra/mode"; + type DefaultableInMemoryEntityConstructor, + defaultableEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { + type NamedInMemoryEntityConstructor, + namedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ApplicationSchema, BaseMethod, BaseModel } from "@mat3ra/esse/dist/js/types"; +import { type Method, Model, ModelFactory } from "@mat3ra/mode"; import { Utils } from "@mat3ra/utils"; import lodash from "lodash"; -import { mix } from "mixwith"; import _ from "underscore"; -import { UNIT_TYPES } from "../enums"; -import { UnitFactory } from "../units"; +import { UNIT_TYPES, UnitType } from "../enums"; +import { + type SubworkflowSchemaMixin, + subworkflowSchemaMixin, +} from "../generated/SubworkflowSchemaMixin"; +import { type BaseUnit, UnitFactory } from "../units"; import { setNextLinks, setUnitsHead } from "../utils"; import { ConvergenceMixin } from "./convergence"; /* eslint max-classes-per-file:0 */ -class BaseSubworkflow extends mix(NamedDefaultableRepetitionImportantSettingsInMemoryEntity).with( - ConvergenceMixin, - ContextAndRenderFieldsMixin, -) {} +// class BaseSubworkflow extends mix(NamedDefaultableRepetitionImportantSettingsInMemoryEntity).with( +// ConvergenceMixin, +// ContextAndRenderFieldsMixin, +// ) {} + +type Base = typeof InMemoryEntity & + DefaultableInMemoryEntityConstructor & + NamedInMemoryEntityConstructor & + Constructor; -export class Subworkflow extends BaseSubworkflow { +export class Subworkflow extends (InMemoryEntity as Base) { static usePredefinedIds = false; + private ModelFactory: typeof ModelFactory; + + private UnitFactory: typeof UnitFactory; + + private applicationInstance: Application; + + private modelInstance: Model; + + private unitsInstances: BaseUnit[]; + constructor( - config, - _Application = Application, + config: SubworkflowSchemaMixin, _ModelFactory = ModelFactory, _UnitFactory = UnitFactory, ) { super(config); - this._Application = _Application; - this._ModelFactory = _ModelFactory; - this._UnitFactory = _UnitFactory; - this.initialize(); - } + this.ModelFactory = _ModelFactory; + this.UnitFactory = _UnitFactory; - initialize() { - this._application = new this._Application(this.prop("application")); - this._model = this._ModelFactory.create({ - ...this.prop("model"), - application: this.prop("application"), + this.applicationInstance = new Application(this.application); + this.modelInstance = this.ModelFactory.create({ + ...this.model, + application: this.application, }); - this._units = setNextLinks(setUnitsHead(this.prop("units", [])), this.id).map((cfg) => - this._UnitFactory.create( - Object.assign(cfg, { application: this.application.toJSON() }), - ), + this.unitsInstances = setNextLinks( + setUnitsHead(this.units || []).map((cfg) => { + return this.UnitFactory.create({ ...cfg, application: this.application }); + }), ); } - static generateSubworkflowId(name, application = null, model = null, method = null) { - const appName = application ? application.name || application : ""; - const modelInfo = model - ? `${(model.toJSON?.() || model).type}-${(model.toJSON?.() || model).subtype || ""}` - : ""; - const methodInfo = method - ? `${(method.toJSON?.() || method).type}-${(method.toJSON?.() || method).subtype || ""}` - : ""; + static generateSubworkflowId( + name: string, + application?: ApplicationSchema, + model?: BaseModel, + method?: BaseMethod, + ) { + const appName = application?.name || ""; + const modelInfo = model ? `${model.type}-${model.subtype || ""}` : ""; + const methodInfo = method ? `${method.type}-${method.subtype || ""}` : ""; const seed = [`subworkflow-${name}`, appName, modelInfo, methodInfo] .filter((p) => p) .join("-"); - if (this.usePredefinedIds) return Utils.uuid.getUUIDFromNamespace(seed); - return Utils.uuid.getUUID(); + + return this.usePredefinedIds ? Utils.uuid.getUUIDFromNamespace(seed) : Utils.uuid.getUUID(); } static get defaultConfig() { @@ -81,8 +102,8 @@ export class Subworkflow extends BaseSubworkflow { * @returns {SubworkflowUnit} */ getAsUnit() { - return this._UnitFactory.create({ - type: UNIT_TYPES.subworkflow, + return this.UnitFactory.create({ + type: UnitType.subworkflow, _id: this.id, name: this.name, }); @@ -92,11 +113,11 @@ export class Subworkflow extends BaseSubworkflow { * @summary Used to generate initial application tree, therefore omit setting application. */ static fromArguments( - application, - model, - method, - name, - units = [], + application: Application, + model: Model, + method: Method, + name: string, + units: BaseUnit[] = [], config = {}, Cls = Subworkflow, ) { @@ -122,15 +143,11 @@ export class Subworkflow extends BaseSubworkflow { }); } - get application() { - return this._application; - } - - setApplication(application) { + setApplication(application: Application) { // TODO: adjust the logic above to take into account whether units need re-rendering after version change etc. // reset units if application name changes const previousApplicationName = this.application.name; - this._application = application; + this.applicationInstance = application; if (previousApplicationName !== application.name) { // TODO: figure out how to set a default unit per new application instead of removing all @@ -139,39 +156,31 @@ export class Subworkflow extends BaseSubworkflow { // propagate new application version to all units this.units .filter((unit) => typeof unit.setApplication === "function") - .forEach((unit) => unit.setApplication(application, true)); + .forEach((unit) => unit.setApplication(this.applicationInstance, true)); } - this.setProp("application", application.toJSON()); + this.application = application.toJSON(); // set model to the default one for the application selected this.setModel( - this._ModelFactory.createFromApplication({ - application: this.prop("application"), + this.ModelFactory.createFromApplication({ + application: this.application, }), ); } - get model() { - return this._model; + setModel(model: Model) { + this.modelInstance = model; } - setModel(model) { - this._model = model; + setUnits(units: BaseUnit[]) { + this.unitsInstances = units; } - get units() { - return this._units; - } - - setUnits(units) { - this._units = units; - } - - toJSON(exclude = []) { + toJSON(exclude: string[] = []) { return { ...super.toJSON(exclude), - model: this.model.toJSON(), - units: this.units.map((x) => x.toJSON()), + model: this.modelInstance.toJSON(), + units: this.unitsInstances.map((x) => x.toJSON()), ...(this.compute ? { compute: this.compute } : {}), // {"compute": null } won't pass esse validation }; } @@ -184,7 +193,7 @@ export class Subworkflow extends BaseSubworkflow { unitsWithContextProviders.map((u) => u.allContextProviders), ); const subworkflowContextProviders = allContextProviders.filter( - (p) => p.isSubworkflowContextProvider, + (p) => p.entityName === "subworkflow", ); return _.uniq(subworkflowContextProviders, (p) => p.name); } @@ -238,11 +247,8 @@ export class Subworkflow extends BaseSubworkflow { /** * TODO: reuse workflow function instead - * @param unit {Unit} - * @param head {Boolean} - * @param index {Number} */ - addUnit(unit, index = -1) { + addUnit(unit: BaseUnit, index = -1) { const { units } = this; if (units.length === 0) { unit.head = true; @@ -254,7 +260,7 @@ export class Subworkflow extends BaseSubworkflow { } } - removeUnit(flowchartId) { + removeUnit(flowchartId: string) { const previousUnit = this.units.find((x) => x.next === flowchartId); if (previousUnit) previousUnit.unsetProp("next"); // TODO: remove the setNextLinks and setUnitsHead and handle the logic via flowchart designer @@ -267,17 +273,17 @@ export class Subworkflow extends BaseSubworkflow { return lodash.flatten(this.units.map((x) => x.resultNames)); } - getUnit(flowchartId) { + getUnit(flowchartId: string) { return this.units.find((x) => x.flowchartId === flowchartId); } - unitIndex(flowchartId) { + unitIndex(flowchartId: string) { return lodash.findIndex(this.units, (unit) => { return unit.flowchartId === flowchartId; }); } - replaceUnit(index, unit) { + replaceUnit(index: number, unit: BaseUnit) { this.units[index] = unit; this.setUnits(setNextLinks(setUnitsHead(this.units))); } @@ -300,7 +306,7 @@ export class Subworkflow extends BaseSubworkflow { return this.prop("isDraft", false); } - setIsDraft(bool) { + setIsDraft(bool: boolean) { return this.setProp("isDraft", bool); } @@ -329,17 +335,17 @@ export class Subworkflow extends BaseSubworkflow { return Utils.hash.calculateHashFromObject(model); } - findUnitById(id) { + findUnitById(id: string) { // TODO: come back and refactor after converting flowchartId to id return this.units.find((u) => u.flowchartId === id); } - findUnitKeyById(id) { + findUnitKeyById(id: string) { const index = this.units.findIndex((u) => u.flowchartId === id); return `units.${index}`; } - findUnitWithTag(tag) { + findUnitWithTag(tag: string) { return this.units.find((unit) => unit.tags.includes(tag)); } @@ -347,3 +353,7 @@ export class Subworkflow extends BaseSubworkflow { return !!this.convergenceParam && !!this.convergenceResult && !!this.convergenceSeries; } } + +namedEntityMixin(Subworkflow.prototype); +defaultableEntityMixin(Subworkflow); +subworkflowSchemaMixin(Subworkflow.prototype); diff --git a/src/js/units/AssertionUnit.ts b/src/js/units/AssertionUnit.ts new file mode 100644 index 00000000..df78e23e --- /dev/null +++ b/src/js/units/AssertionUnit.ts @@ -0,0 +1,30 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { AssertionUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type AssertionUnitSchemaMixin, + assertionUnitSchemaMixin, +} from "../generated/AssertionUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = AssertionUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class AssertionUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ + name: UnitType.assertion, + type: UnitType.assertion, + statement: "true", + errorMessage: "assertion failed", + ...config, + }); + } + + getHashObject() { + return { statement: this.statement, errorMessage: this.errorMessage }; + } +} + +assertionUnitSchemaMixin(AssertionUnit.prototype); diff --git a/src/js/units/AssignmentUnit.ts b/src/js/units/AssignmentUnit.ts new file mode 100644 index 00000000..5070c56b --- /dev/null +++ b/src/js/units/AssignmentUnit.ts @@ -0,0 +1,31 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { AssignmentUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type AssignmentUnitSchemaMixin, + assignmentUnitSchemaMixin, +} from "../generated/AssignmentUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = AssignmentUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class AssignmentUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ + name: UnitType.assignment, + type: UnitType.assignment, + operand: "X", + value: "1", + input: [], + ...config, + }); + } + + getHashObject(): object { + return { input: this.input, operand: this.operand, value: this.value }; + } +} + +assignmentUnitSchemaMixin(AssignmentUnit.prototype); diff --git a/src/js/units/BaseUnit.ts b/src/js/units/BaseUnit.ts new file mode 100644 index 00000000..6e1bb52d --- /dev/null +++ b/src/js/units/BaseUnit.ts @@ -0,0 +1,121 @@ +/* eslint-disable class-methods-use-this */ +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { + type Defaultable, + defaultableEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { + HashedEntity, + hashedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/HashedEntityMixin"; +import { + HasRepetition, + hasRepetitionMixin, +} from "@mat3ra/code/dist/js/entity/mixins/HasRepetitionMixin"; +import { + type NamedEntity, + namedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import { + type RuntimeItems, + runtimeItemsMixin, +} from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; +import { Taggable, taggableMixin } from "@mat3ra/code/dist/js/entity/mixins/TaggableMixin"; +import type { NameResultSchema } from "@mat3ra/code/dist/js/utils/object"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { StatusSchema, WorkflowBaseUnitSchema } from "@mat3ra/esse/dist/js/types"; +import { Utils } from "@mat3ra/utils"; + +import { UNIT_STATUSES } from "../enums"; +import { type BaseUnitSchemaMixin, baseUnitSchemaMixin } from "../generated/BaseUnitSchemaMixin"; +import { type StatusSchemaMixin, statusSchemaMixin } from "../generated/StatusSchemaMixin"; +import { type RuntimeItemsUILogic, runtimeItemsUILogicMixin } from "../RuntimeItemsUILogicMixin"; + +type Base = typeof InMemoryEntity & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor & + Constructor; + +type Schema = WorkflowBaseUnitSchema; + +// eslint-disable-next-line prettier/prettier +export class BaseUnit extends (InMemoryEntity as Base) implements Schema { + static usePredefinedIds = false; + + static generateFlowChartId(name: string) { + if (this.usePredefinedIds) { + return Utils.uuid.getUUIDFromNamespace(`flowchart-${name}`); + } + return Utils.uuid.getUUID(); + } + + defaultResults: NameResultSchema[] = []; + + defaultMonitors: NameResultSchema[] = []; + + defaultPostProcessors: NameResultSchema[] = []; + + defaultPreProcessors: NameResultSchema[] = []; + + allowedResults: NameResultSchema[] = []; + + allowedMonitors: NameResultSchema[] = []; + + allowedPostProcessors: NameResultSchema[] = []; + + constructor(config: Partial & Pick) { + super({ + results: [], + monitors: [], + preProcessors: [], + postProcessors: [], + ...config, + status: config.status || UNIT_STATUSES.idle, + statusTrack: config.statusTrack || [], + flowchartId: config.flowchartId || BaseUnit.generateFlowChartId(config.name), + tags: config.tags || [], + }); + + this._initRuntimeItems(config); + } + + get lastStatusUpdate() { + const statusTrack = (this.statusTrack || []).filter( + (s) => (s.repetition || 0) === this.repetition, + ); + const sortedStatusTrack = statusTrack.sort((a, b) => a.trackedAt - b.trackedAt); // lodash.sortBy(statusTrack, (x) => x.trackedAt); + return sortedStatusTrack[sortedStatusTrack.length - 1]; + } + + getHashObject(): object { + return { ...this.hashObjectFromRuntimeItems, type: this.type }; + } + + isInStatus(status: StatusSchema["status"]) { + return this.status === status; + } + + clone(extraContext: object) { + const flowchartIDOverrideConfigAsExtraContext = { + flowchartId: BaseUnit.generateFlowChartId(this.name), + ...extraContext, + }; + return super.clone(flowchartIDOverrideConfigAsExtraContext); + } +} + +taggableMixin(BaseUnit.prototype); +hashedEntityMixin(BaseUnit.prototype); +hasRepetitionMixin(BaseUnit.prototype); +runtimeItemsMixin(BaseUnit.prototype); +runtimeItemsUILogicMixin(BaseUnit.prototype); +baseUnitSchemaMixin(BaseUnit.prototype); +statusSchemaMixin(BaseUnit.prototype); +namedEntityMixin(BaseUnit.prototype); +defaultableEntityMixin(BaseUnit); diff --git a/src/js/units/ConditionUnit.ts b/src/js/units/ConditionUnit.ts new file mode 100644 index 00000000..9c8f066c --- /dev/null +++ b/src/js/units/ConditionUnit.ts @@ -0,0 +1,36 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ConditionUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type ConditionUnitSchemaMixin, + conditionUnitSchemaMixin, +} from "../generated/ConditionUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = ConditionUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class ConditionUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ + name: UnitType.condition, + type: UnitType.condition, + input: [], + results: [], + preProcessors: [], + postProcessors: [], + then: undefined, + else: undefined, + statement: "true", + maxOccurrences: 100, + ...config, + }); + } + + getHashObject(): object { + return { statement: this.statement, maxOccurrences: this.maxOccurrences }; + } +} + +conditionUnitSchemaMixin(ConditionUnit.prototype); diff --git a/src/js/units/ExecutionUnit.ts b/src/js/units/ExecutionUnit.ts new file mode 100644 index 00000000..ce691063 --- /dev/null +++ b/src/js/units/ExecutionUnit.ts @@ -0,0 +1,203 @@ +import { Application, ApplicationRegistry as AdeRegistry, Executable, Flavor } from "@mat3ra/ade"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; +import type { + ExecutableSchema, + ExecutionUnitInputItemSchema, + ExecutionUnitSchemaBase, + FlavorSchema, +} from "@mat3ra/esse/dist/js/types"; +import { Utils } from "@mat3ra/utils"; + +import { contextMixin } from "../context/mixins/ContextAndRenderFieldsMixin"; +import { + type ImportantSettingsProvider, + importantSettingsProviderMixin, +} from "../context/mixins/ImportantSettingsProviderMixin"; +import type { ContextItem } from "../context/providers/base/ContextProvider"; +import ExecutionUnitInput from "../ExecutionUnitInput"; +import { + type ExecutionUnitSchemaMixin, + executionUnitSchemaMixin, +} from "../generated/ExecutionUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = ExecutionUnitSchemaBase; +type Base = typeof BaseUnit & + Constructor & + Constructor; + +interface SetApplicationProps { + application: Application; + executable?: Executable | ExecutableSchema; + flavor?: Flavor | FlavorSchema; +} + +interface SetExecutableProps { + executable?: Executable | ExecutableSchema; + flavor?: Flavor | FlavorSchema; +} + +export type ExecutionUnitSchema = Schema; + +export class ExecutionUnit extends (BaseUnit as Base) implements Schema { + applicationInstance!: Application; + + executableInstance!: Executable; + + flavorInstance!: Flavor; + + inputInstances: ExecutionUnitInput[] = []; + + renderingContext: ContextItem[] = []; + + constructor(config: Schema) { + super(config); + + const { application, executable, flavor } = config; + const applicationInstance = AdeRegistry.createApplication(application); + const executableInstance = AdeRegistry.getExecutableByConfig(application.name, executable); + const flavorInstance = AdeRegistry.getFlavorByConfig(executableInstance, flavor); + + if (!flavorInstance) { + throw new Error("Flavor is not set"); + } + + this.setApplication({ + application: applicationInstance, + executable: executableInstance, + flavor: flavorInstance, + }); + + this.name = this.name || this.flavor?.name || ""; + } + + setApplication({ application, executable, flavor }: SetApplicationProps) { + this.applicationInstance = application; + this.setProp("application", application.toJSON()); + this.setExecutable({ executable, flavor }); + } + + setExecutable({ executable, flavor }: SetExecutableProps) { + const defaultExecutable = AdeRegistry.getExecutableByName(this.application.name); + const instance = + executable instanceof Executable + ? executable + : new Executable(executable ?? defaultExecutable.toJSON()); + + this.allowedResults = instance.results; + this.allowedMonitors = instance.monitors; + this.allowedPostProcessors = instance.postProcessors; + + this.setProp("executable", instance.toJSON()); + this.setFlavor(flavor); + } + + setFlavor(flavor?: Flavor | FlavorSchema) { + const defaultFlavor = AdeRegistry.getFlavorByConfig(this.executableInstance); + const instance = + flavor instanceof Flavor ? flavor : new Flavor(flavor ?? defaultFlavor?.toJSON()); + + if (!instance) { + throw new Error("Flavor is not found for executable"); + } + + this.flavorInstance = instance; + this.defaultMonitors = instance.monitors; + this.defaultResults = instance.results; + this.defaultPostProcessors = instance.postProcessors; + + this.setProp("flavor", instance.toJSON()); + this.setRuntimeItemsToDefaultValues(); + this.setDefaultInput(); + } + + setDefaultInput() { + const inputs = AdeRegistry.getInput(this.flavorInstance); + this.inputInstances = inputs.map(ExecutionUnitInput.createFromTemplate); + } + + get allContextProviders() { + return this.inputInstances.map((input) => input.contextProvidersInstances).flat(); + } + + get contextProviders() { + return this.allContextProviders.filter((p) => p.entityName === "unit"); + } + + /** Update rendering context and persistent context + * Note: this function is sometimes being called without passing a context! + */ + render(context: AnyObject = {}) { + this.renderingContext = { ...this.renderingContext, ...context }; + + const newInput: ExecutionUnitInputItemSchema[] = []; + const newPersistentContext: ContextItem[] = []; + const newRenderingContext: ContextItem[] = []; + + this.inputInstances.forEach((input) => { + input.setContext(this.renderingContext); + input.render(); + + const inputJSON = input.toJSON(); + const context = input.getFullContext(); + + newInput.push(inputJSON); + newRenderingContext.push(...context); + newPersistentContext.push(...context.filter((c) => c.isEdited)); + }); + + this.input = newInput; + this.renderingContext = newRenderingContext; + this.context = newPersistentContext; + } + + /** + * @summary Calculates hash on unit-specific fields. + * The meaningful fields of processing unit are operation, flavor and input at the moment. + */ + getHashObject() { + return { + ...super.getHashObject(), + application: Utils.specific.removeTimestampableKeysFromConfig( + this.applicationInstance.toJSON(), + ), + executable: Utils.specific.removeTimestampableKeysFromConfig( + this.executableInstance.toJSON(), + ), + flavor: this.flavorInstance + ? Utils.specific.removeTimestampableKeysFromConfig(this.flavorInstance.toJSON()) + : undefined, + input: Utils.hash.calculateHashFromObject( + this.input.map((i) => { + return Utils.str.removeEmptyLinesFromString( + Utils.str.removeCommentsFromSourceCode(i.template.content), + ); + }), + ), + }; + } + + // toJSON() { + // const json = super.toJSON() as ExecutionUnitSchemaBase & AnyObject; + + // // Remove results from executable; TODO: why do we need this? + // if (json.executable) { + // // eslint-disable-next-line @typescript-eslint/no-unused-vars + // const { results: _, ...executable } = json.executable; + + // return { + // ...json, + // executable: { + // ...executable, + // }, + // }; + // } + + // return json; + // } +} + +executionUnitSchemaMixin(ExecutionUnit.prototype); +contextMixin(ExecutionUnit.prototype); +importantSettingsProviderMixin(ExecutionUnit.prototype); diff --git a/src/js/units/IOUnit.ts b/src/js/units/IOUnit.ts new file mode 100644 index 00000000..02e62424 --- /dev/null +++ b/src/js/units/IOUnit.ts @@ -0,0 +1,17 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { DataIOUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { type IOUnitSchemaMixin, iOUnitSchemaMixin } from "../generated/IOUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = DataIOUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class IOUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ name: UnitType.io, subtype: "input", ...config, type: UnitType.io }); + } +} + +iOUnitSchemaMixin(IOUnit.prototype); diff --git a/src/js/units/MapUnit.ts b/src/js/units/MapUnit.ts new file mode 100644 index 00000000..5a96a781 --- /dev/null +++ b/src/js/units/MapUnit.ts @@ -0,0 +1,35 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { MapUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { type MapUnitSchemaMixin, mapUnitSchemaMixin } from "../generated/MapUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = MapUnitSchema; + +export const defaultMapConfig = { + name: UnitType.map as string, + type: UnitType.map as const, + workflowId: "", + input: { + target: "MAP_DATA", + scope: "global", + name: "", + values: [], + useValues: false, + }, +}; + +type Base = typeof BaseUnit & Constructor; + +export class MapUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ ...defaultMapConfig, ...config }); + } + + setWorkflowId(id: string) { + this.setProp("workflowId", id); + } +} + +mapUnitSchemaMixin(MapUnit.prototype); diff --git a/src/js/units/ProcessingUnit.ts b/src/js/units/ProcessingUnit.ts new file mode 100644 index 00000000..460003d3 --- /dev/null +++ b/src/js/units/ProcessingUnit.ts @@ -0,0 +1,36 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ProcessingUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type ProcessingUnitSchemaMixin, + processingUnitSchemaMixin, +} from "../generated/ProcessingUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = ProcessingUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class ProcessingUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ + name: UnitType.processing, + type: UnitType.processing, + ...config, + }); + } + + setOperation(op: ProcessingUnitSchema["operation"]) { + this.setProp("operation", op); + } + + setOperationType(type: ProcessingUnitSchema["operationType"]) { + this.setProp("operationType", type); + } + + setInput(input: ProcessingUnitSchema["inputData"]) { + this.setProp("inputData", input); + } +} + +processingUnitSchemaMixin(ProcessingUnit.prototype); diff --git a/src/js/units/ReduceUnit.ts b/src/js/units/ReduceUnit.ts new file mode 100644 index 00000000..2da9929d --- /dev/null +++ b/src/js/units/ReduceUnit.ts @@ -0,0 +1,20 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ReduceUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type ReduceUnitSchemaMixin, + reduceUnitSchemaMixin, +} from "../generated/ReduceUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = ReduceUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class ReduceUnit extends (BaseUnit as Base) implements Schema { + constructor(unitName: string, mapUnit: string, input: ReduceUnitSchema["input"]) { + super({ type: UnitType.reduce, name: unitName, mapFlowchartId: mapUnit, input }); + } +} + +reduceUnitSchemaMixin(ReduceUnit.prototype); diff --git a/src/js/units/SubworkflowUnit.ts b/src/js/units/SubworkflowUnit.ts new file mode 100644 index 00000000..78da842b --- /dev/null +++ b/src/js/units/SubworkflowUnit.ts @@ -0,0 +1,20 @@ +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { SubworkflowUnitSchema } from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { + type SubworkflowUnitSchemaMixin, + subworkflowUnitSchemaMixin, +} from "../generated/SubworkflowUnitSchemaMixin"; +import { BaseUnit } from "./BaseUnit"; + +type Schema = SubworkflowUnitSchema; +type Base = typeof BaseUnit & Constructor; + +export class SubworkflowUnit extends (BaseUnit as Base) implements Schema { + constructor(config: Partial) { + super({ name: "New Subworkflow", ...config, type: UnitType.subworkflow }); + } +} + +subworkflowUnitSchemaMixin(SubworkflowUnit.prototype); diff --git a/src/js/units/assertion.js b/src/js/units/assertion.js deleted file mode 100644 index 13dc7288..00000000 --- a/src/js/units/assertion.js +++ /dev/null @@ -1,29 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class AssertionUnit extends BaseUnit { - constructor(config) { - super({ ...AssertionUnit.getAssertionConfig(), ...config }); - } - - static getAssertionConfig() { - return { - name: UNIT_TYPES.assertion, - type: UNIT_TYPES.assertion, - statement: "true", - errorMessage: "assertion failed", - }; - } - - get statement() { - return this.prop("statement"); - } - - get errorMessage() { - return this.prop("errorMessage"); - } - - getHashObject() { - return { statement: this.statement, errorMessage: this.errorMessage }; - } -} diff --git a/src/js/units/assignment.js b/src/js/units/assignment.js deleted file mode 100644 index f16a5e14..00000000 --- a/src/js/units/assignment.js +++ /dev/null @@ -1,34 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class AssignmentUnit extends BaseUnit { - constructor(config) { - super({ ...AssignmentUnit.getAssignmentConfig(), ...config }); - } - - static getAssignmentConfig() { - return { - name: UNIT_TYPES.assignment, - type: UNIT_TYPES.assignment, - operand: "X", - value: "1", - input: [], - }; - } - - get operand() { - return this.prop("operand"); - } - - get value() { - return this.prop("value"); - } - - get input() { - return this.prop("input"); - } - - getHashObject() { - return { input: this.input, operand: this.operand, value: this.value }; - } -} diff --git a/src/js/units/base.js b/src/js/units/base.js deleted file mode 100644 index dc6aa2ba..00000000 --- a/src/js/units/base.js +++ /dev/null @@ -1,97 +0,0 @@ -import { NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import { taggableMixin } from "@mat3ra/code/dist/js/entity/mixins/TaggableMixin"; -import { Utils } from "@mat3ra/utils"; -import lodash from "lodash"; - -import { UNIT_STATUSES } from "../enums"; - -// eslint-disable-next-line max-len -export class BaseUnit extends NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity { - static usePredefinedIds = false; - - constructor(config) { - const flowchartId = - config.flowchartId || BaseUnit.generateFlowChartId.call(new.target, config.name); - super({ - ...config, - status: config.status || UNIT_STATUSES.idle, - statusTrack: config.statusTrack || [], - flowchartId, - tags: config.tags || [], - }); - } - - static generateFlowChartId(...args) { - args[0] = `flowchart-${args[0]}`; - if (this.usePredefinedIds) return Utils.uuid.getUUIDFromNamespace(...args); - return Utils.uuid.getUUID(); - } - - get flowchartId() { - return this.prop("flowchartId"); - } - - get head() { - return this.prop("head", false); - } - - set head(bool) { - this.setProp("head", bool); - } - - get next() { - return this.prop("next"); - } - - set next(flowchartId) { - this.setProp("next", flowchartId); - } - - get status() { - return lodash.get(this.lastStatusUpdate, "status") || UNIT_STATUSES.idle; - } - - set status(s) { - this.setProp("status", s); - } - - get lastStatusUpdate() { - const statusTrack = this.prop("statusTrack", []).filter( - (s) => (s.repetition || 0) === this.repetition, - ); - const sortedStatusTrack = lodash.sortBy(statusTrack || [], (x) => x.trackedAt); - return sortedStatusTrack[sortedStatusTrack.length - 1]; - } - - get type() { - return this.prop("type"); - } - - get isDraft() { - return this.prop("isDraft", false); - } - - getHashObject() { - return { ...this.hashObjectFromRuntimeItems, type: this.type }; - } - - /** - * Checks whether a unit is currently in a given status (e.g. idle, active, etc). The full list can be found - * in the UNIT_STATUSES variable in enums.js. - * @param status (String) name of the status to check - * @returns Boolean - */ - isInStatus(status) { - return this.status === status; - } - - clone(extraContext) { - const flowchartIDOverrideConfigAsExtraContext = { - flowchartId: this.constructor.generateFlowChartId(), - ...extraContext, - }; - return super.clone(flowchartIDOverrideConfigAsExtraContext); - } -} - -taggableMixin(BaseUnit.prototype); diff --git a/src/js/units/condition.js b/src/js/units/condition.js deleted file mode 100644 index c4254add..00000000 --- a/src/js/units/condition.js +++ /dev/null @@ -1,47 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class ConditionUnit extends BaseUnit { - constructor(config) { - super({ ...ConditionUnit.getConditionConfig(), ...config }); - } - - static getConditionConfig() { - return { - name: UNIT_TYPES.condition, - type: UNIT_TYPES.condition, - input: [], - results: [], - preProcessors: [], - postProcessors: [], - then: undefined, - else: undefined, - statement: "true", - maxOccurrences: 100, - }; - } - - get input() { - return this.prop("input"); - } - - get then() { - return this.prop("then"); - } - - get else() { - return this.prop("else"); - } - - get statement() { - return this.prop("statement"); - } - - get maxOccurrences() { - return this.prop("maxOccurrences"); - } - - getHashObject() { - return { statement: this.statement, maxOccurrences: this.maxOccurrences }; - } -} diff --git a/src/js/units/execution.js b/src/js/units/execution.js deleted file mode 100644 index d9ecfd61..00000000 --- a/src/js/units/execution.js +++ /dev/null @@ -1,267 +0,0 @@ -import { ApplicationRegistry, Template } from "@mat3ra/ade"; -import { Utils } from "@mat3ra/utils"; -import _ from "underscore"; - -import { BaseUnit } from "./base"; - -export class ExecutionUnit extends BaseUnit { - // keys to be omitted during toJSON - static omitKeys = [ - "job", - "workflow", - "material", - "materials", - "model", - "methodData", - "hasRelaxation", - ]; - - /** - * @override this method to provide entities from other sources - */ - _initApplication(config) { - this._application = ApplicationRegistry.createApplication(config.application); - this._executable = ApplicationRegistry.getExecutableByConfig( - this._application.name, - config.executable, - ); - this._flavor = ApplicationRegistry.getFlavorByConfig(this._executable, config.flavor); - this._templates = this._flavor ? this._flavor.inputAsTemplates : []; - } - - /** - * @override this method to provide default executable from other source - */ - _getDefaultExecutable() { - return ApplicationRegistry.getExecutableByName(this.application.name); - } - - /** - * @override this method to provide default flavor from other source - */ - _getDefaultFlavor() { - return ApplicationRegistry.getFlavorByName(this.executable.name); - } - - /** - * @override this method to provide custom templates - */ - _getTemplatesFromInput() { - return this.getInput().map((i) => new Template(i)); - } - - /** - * @override this method to provide custom input from other sources - */ - _getInput() { - return ( - this.input || - ApplicationRegistry.getInputAsRenderedTemplates( - this.flavor, - this.getCombinedContext(), - ) || - [] - ); - } - - /** - * @override this method to provide custom input as templates - */ - _getInputAsTemplates() { - return ApplicationRegistry.getInputAsTemplates(this.flavor); - } - - _initRuntimeItems(keys, config) { - this._initApplication(config); - super._initRuntimeItems(keys); - } - - /* - * @summary expects an array with elements containing field [{content: "..."}] - */ - get hashFromArrayInputContent() { - const objectForHashing = this._getInput().map((i) => { - return Utils.str.removeEmptyLinesFromString( - Utils.str.removeCommentsFromSourceCode(i.content), - ); - }); - return Utils.hash.calculateHashFromObject(objectForHashing); - } - - get name() { - return this.prop("name", this.flavor.name); - } - - get application() { - return this._application; - } - - get executable() { - return this._executable; - } - - get flavor() { - return this._flavor; - } - - get templates() { - return this._templates; - } - - setApplication(application, omitSettingExecutable = false) { - this._application = application; - this.setProp("application", application.toJSON()); - if (!omitSettingExecutable) { - this.setExecutable(this._getDefaultExecutable()); - } - } - - setExecutable(executable) { - this._executable = executable; - this.setProp("executable", executable.toJSON()); - this.setFlavor(this._getDefaultFlavor()); - } - - setFlavor(flavor) { - this._flavor = flavor; - this.setRuntimeItemsToDefaultValues(); - this.setProp("flavor", flavor.toJSON()); - this.setTemplates(this._getInputAsTemplates()); - } - - setTemplates(templates) { - this._templates = templates; - this.render(this.context, true); - } - - setInput(input) { - this.setProp("input", input); - } - - get defaultResults() { - return this.flavor.results; - } - - get defaultMonitors() { - return this.flavor.monitors; - } - - get defaultPostProcessors() { - return this.flavor.postProcessors; - } - - get allowedResults() { - return this.executable.results; - } - - get allowedMonitors() { - return this.executable.monitors; - } - - get allowedPostProcessors() { - return this.executable.postProcessors; - } - - get allContextProviders() { - const list = []; - // pass context below to keep UI changes - this.templates.forEach((i) => - list.push(...i.getContextProvidersAsClassInstances(this.getCombinedContext())), - ); - return list; - } - - get contextProviders() { - return this.allContextProviders.filter((p) => p.isUnitContextProvider); - } - - get input() { - return this.prop("input"); - } - - get renderingContext() { - return this._renderingContext || {}; - } - - set renderingContext(ctx) { - this._renderingContext = ctx; - } - - // context to persist in toJSON - get storedContext() { - return _.omit(this.context, ...this.constructor.omitKeys); - } - - // context to show to users with some extra keys omitted - get visibleRenderingContext() { - return _.omit(this.renderingContext, ...this.constructor.omitKeys); - } - - static getSubworkflowContext(context) { - const { subworkflowContext } = context; - return subworkflowContext ? { subworkflowContext } : {}; - } - - /** Update rendering context and persistent context - * Note: this function is sometimes being called without passing a context! - * @param context - * @param fromTemplates - */ - render(context, fromTemplates = false) { - const newInput = []; - const newPersistentContext = {}; - const newRenderingContext = {}; - const renderingContext = { ...this.context, ...context }; - this.updateContext(renderingContext); // update in-memory context to properly render templates from input below - (fromTemplates ? this.templates : this._getTemplatesFromInput()).forEach((t) => { - newInput.push(t.getRenderedJSON(renderingContext)); - Object.assign( - newRenderingContext, - t.getDataFromProvidersForRenderingContext(renderingContext), - ExecutionUnit.getSubworkflowContext(renderingContext), - ); - Object.assign( - newPersistentContext, - t.getDataFromProvidersForPersistentContext(renderingContext), - ExecutionUnit.getSubworkflowContext(renderingContext), - ); - }); - this.setInput(newInput); - this.renderingContext = newRenderingContext; - this.updatePersistentContext(newPersistentContext); - } - - /** - * @summary Calculates hash on unit-specific fields. - * The meaningful fields of processing unit are operation, flavor and input at the moment. - */ - getHashObject() { - return { - ...super.getHashObject(), - application: Utils.specific.removeTimestampableKeysFromConfig( - this.application.toJSON(), - ), - executable: Utils.specific.removeTimestampableKeysFromConfig(this.executable.toJSON()), - flavor: Utils.specific.removeTimestampableKeysFromConfig(this.flavor.toJSON()), - input: this.hashFromArrayInputContent, - }; - } - - toJSON() { - const json = this.clean({ - ...super.toJSON(), - executable: this.executable.toJSON(), - flavor: this.flavor.toJSON(), - input: this._getInput(), - // keys below are not propagated to the parent class on initialization of a new unit unless explicitly given - name: this.name, - // TODO: figure out the problem with storing context below - // context: this.storedContext, - }); - - // Remove results from executable - if (json.executable?.results) delete json.executable.results; - - return json; - } -} diff --git a/src/js/units/factory.js b/src/js/units/factory.js deleted file mode 100644 index 765fd4aa..00000000 --- a/src/js/units/factory.js +++ /dev/null @@ -1,53 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { AssertionUnit } from "./assertion"; -import { AssignmentUnit } from "./assignment"; -import { BaseUnit } from "./base"; -import { ConditionUnit } from "./condition"; -import { ExecutionUnit } from "./execution"; -import { IOUnit } from "./io"; -import { MapUnit } from "./map"; -import { ProcessingUnit } from "./processing"; -import { SubworkflowUnit } from "./subworkflow"; - -export class UnitFactory { - static AssertionUnit = AssertionUnit; - - static AssignmentUnit = AssignmentUnit; - - static BaseUnit = BaseUnit; - - static ConditionUnit = ConditionUnit; - - static ExecutionUnit = ExecutionUnit; - - static IOUnit = IOUnit; - - static MapUnit = MapUnit; - - static ProcessingUnit = ProcessingUnit; - - static SubworkflowUnit = SubworkflowUnit; - - static create(config) { - switch (config.type) { - case UNIT_TYPES.execution: - return new this.ExecutionUnit(config); - case UNIT_TYPES.assignment: - return new this.AssignmentUnit(config); - case UNIT_TYPES.condition: - return new this.ConditionUnit(config); - case UNIT_TYPES.io: - return new this.IOUnit(config); - case UNIT_TYPES.processing: - return new this.ProcessingUnit(config); - case UNIT_TYPES.map: - return new this.MapUnit(config); - case UNIT_TYPES.subworkflow: - return new this.SubworkflowUnit(config); - case UNIT_TYPES.assertion: - return new this.AssertionUnit(config); - default: - return new this.BaseUnit(config); - } - } -} diff --git a/src/js/units/factory.ts b/src/js/units/factory.ts new file mode 100644 index 00000000..a5e038e1 --- /dev/null +++ b/src/js/units/factory.ts @@ -0,0 +1,55 @@ +import type { + AssertionUnitSchema, + AssignmentUnitSchema, + ConditionUnitSchema, + DataIOUnitSchema, + MapUnitSchema, + ProcessingUnitSchema, + SubworkflowUnitSchema, +} from "@mat3ra/esse/dist/js/types"; + +import { UnitType } from "../enums"; +import { AssertionUnit } from "./AssertionUnit"; +import { AssignmentUnit } from "./AssignmentUnit"; +import { BaseUnit } from "./BaseUnit"; +import { ConditionUnit } from "./ConditionUnit"; +import { type ExecutionUnitSchema, ExecutionUnit } from "./ExecutionUnit"; +import { IOUnit } from "./IOUnit"; +import { MapUnit } from "./MapUnit"; +import { ProcessingUnit } from "./ProcessingUnit"; +import { SubworkflowUnit } from "./SubworkflowUnit"; + +type UnitConfig = + | ExecutionUnitSchema + | AssignmentUnitSchema + | ConditionUnitSchema + | DataIOUnitSchema + | ProcessingUnitSchema + | MapUnitSchema + | SubworkflowUnitSchema + | AssertionUnitSchema; + +export class UnitFactory { + static create(config: UnitConfig): BaseUnit { + switch (config.type) { + case UnitType.execution: + return new ExecutionUnit(config); + case UnitType.assignment: + return new AssignmentUnit(config); + case UnitType.condition: + return new ConditionUnit(config); + case UnitType.io: + return new IOUnit(config); + case UnitType.processing: + return new ProcessingUnit(config); + case UnitType.map: + return new MapUnit(config); + case UnitType.subworkflow: + return new SubworkflowUnit(config); + case UnitType.assertion: + return new AssertionUnit(config); + default: + throw new Error(`Unknown unit type: ${config.type}`); + } + } +} diff --git a/src/js/units/index.js b/src/js/units/index.js deleted file mode 100644 index 072378ff..00000000 --- a/src/js/units/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import { AssertionUnit } from "./assertion"; -import { AssignmentUnit } from "./assignment"; -import { BaseUnit } from "./base"; -import { ConditionUnit } from "./condition"; -import { ExecutionUnit } from "./execution"; -import { UnitFactory } from "./factory"; -import { IOUnit } from "./io"; -import { MapUnit } from "./map"; -import { ProcessingUnit } from "./processing"; -import { ReduceUnit } from "./reduce"; -import { SubworkflowUnit } from "./subworkflow"; - -export { - BaseUnit, - AssertionUnit, - AssignmentUnit, - ConditionUnit, - ExecutionUnit, - IOUnit, - MapUnit, - ProcessingUnit, - ReduceUnit, - SubworkflowUnit, - UnitFactory, -}; diff --git a/src/js/units/index.ts b/src/js/units/index.ts new file mode 100644 index 00000000..8574c322 --- /dev/null +++ b/src/js/units/index.ts @@ -0,0 +1,25 @@ +import { AssertionUnit } from "./AssertionUnit"; +import { AssignmentUnit } from "./AssignmentUnit"; +import { BaseUnit } from "./BaseUnit"; +import { ConditionUnit } from "./ConditionUnit"; +import { ExecutionUnit } from "./ExecutionUnit"; +import { UnitFactory } from "./factory"; +import { IOUnit } from "./IOUnit"; +import { MapUnit } from "./MapUnit"; +import { ProcessingUnit } from "./ProcessingUnit"; +import { ReduceUnit } from "./ReduceUnit"; +import { SubworkflowUnit } from "./SubworkflowUnit"; + +export { + BaseUnit, + AssertionUnit, + AssignmentUnit, + ConditionUnit, + ExecutionUnit, + IOUnit, + MapUnit, + ProcessingUnit, + ReduceUnit, + SubworkflowUnit, + UnitFactory, +}; diff --git a/src/js/units/io.js b/src/js/units/io.js deleted file mode 100644 index e6de1eb9..00000000 --- a/src/js/units/io.js +++ /dev/null @@ -1,163 +0,0 @@ -import lodash from "lodash"; - -import { IO_ID_COLUMN, UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class IOUnit extends BaseUnit { - /** - * IO Unit Builder for Object Storage sources. - * - * @param {Object} config - config object with other parameters: - * @param {String} config.name - the name of the unit this builder is creating - * @param {String} config.subtype - "input", "output", or "dataframe" - * @param {Object} config.input - input containing information on the file to download - * @param {Boolean} config.enableRender - Whether to use Jinja templating at runtime - */ - constructor(config) { - super({ ...IOUnit.getIOConfig(), ...config }); - this.initialize(config); - } - - static getIOConfig() { - return { - name: UNIT_TYPES.io, - type: UNIT_TYPES.io, - subtype: "input", - }; - } - - initialize(config) { - this._materials = []; - this._defaultTargets = ["band_gaps:direct", "band_gaps:indirect"]; - this._features = lodash.get(config, "input.0.endpoint_options.data.features", []); - this._targets = lodash.get( - config, - "input.0.endpoint_options.data.targets", - this._defaultTargets, - ); - this._ids = lodash.get(config, "input.0.endpoint_options.data.ids", []); - this._jobId = null; - } - - get materials() { - return this._materials || []; - } - - get defaultTargets() { - return this._defaultTargets; - } - - get features() { - return this._features; - } - - get featuresWithoutId() { - return this.features.filter((x) => x !== IO_ID_COLUMN); - } - - get availableFeatures() { - const { materials } = this; - return lodash.uniq( - lodash - .flatten(materials.map((x) => lodash.keys(x.propertiesDict()))) - .concat(this.features), - ); - } - - get availableFeaturesWithoutId() { - return this.availableFeatures.filter((feature) => feature !== IO_ID_COLUMN); - } - - get targets() { - return this._targets; - } - - /** - * @summary Checks whether selected features contain only IO_ID_COLUMN ('exabyteId'). - * Used to identify that no features are selected yet (features set always contains ID_COLUMN) - */ - get onlyIdFeatureSelected() { - return lodash.isEmpty(lodash.without(this.features, IO_ID_COLUMN)); - } - - /** - * @summary Returns object with targets as key and arrays of appropriate values. - * E.g. {'band_gap:indirect': [0.1, 0.3], 'pressure': [100, undefined]} - */ - get valuesByTarget() { - const values = this.dataGridValues; - const result = {}; - this.targets.forEach((target) => { - result[target] = values.map((v) => v[target]); - }); - return result; - } - - get dataFrameConfig() { - return { - subtype: "dataFrame", - source: "api", - input: [ - { - endpoint: "dataframe", - endpoint_options: { - method: "POST", - data: { - targets: this._targets, - features: this._features, - ids: this._ids, - jobId: this._jobId, - }, - headers: {}, - params: {}, - }, - }, - ], - }; - } - - get isDataFrame() { - return this.prop("subtype") === "dataFrame"; - } - - setMaterials(materials) { - this._materials = materials; - this._ids = materials.map((m) => m.exabyteId); - } - - addFeature(feature) { - // only add if not already present - if (this._features.indexOf(feature) === -1) this._features.push(feature); - } - - removeFeature(feature) { - if (this.featuresWithoutId.length === 1) { - throw new Error("At least one feature is required"); - } - this._features = this._features.filter((x) => feature !== x && x !== IO_ID_COLUMN); - } - - addTarget(target) { - if (this._targets.indexOf(target) === -1) this._targets.push(target); - } - - removeTarget(target) { - if (this._targets.length === 1) { - throw new Error("At least one target is required"); - } - this._targets = this._targets.filter((x) => target !== x); - } - - hasFeature(feature) { - return this._features.indexOf(feature) > -1; - } - - hasTarget(target) { - return this._targets.indexOf(target) > -1; - } - - toJSON() { - const config = this.isDataFrame ? this.dataFrameConfig : {}; - return this.clean({ ...super.toJSON(), ...config }); - } -} diff --git a/src/js/units/map.js b/src/js/units/map.js deleted file mode 100644 index 29a6e215..00000000 --- a/src/js/units/map.js +++ /dev/null @@ -1,33 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export const defaultMapConfig = { - name: UNIT_TYPES.map, - type: UNIT_TYPES.map, - workflowId: "", - input: { - target: "MAP_DATA", - scope: "global", - name: "", - values: [], - useValues: false, - }, -}; - -export class MapUnit extends BaseUnit { - constructor(config) { - super({ ...defaultMapConfig, ...config }); - } - - get input() { - return this.prop("input"); - } - - get workflowId() { - return this.prop("workflowId"); - } - - setWorkflowId(id) { - this.setProp("workflowId", id); - } -} diff --git a/src/js/units/processing.js b/src/js/units/processing.js deleted file mode 100644 index 93f0c39f..00000000 --- a/src/js/units/processing.js +++ /dev/null @@ -1,39 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class ProcessingUnit extends BaseUnit { - constructor(config) { - super({ ...ProcessingUnit.getProcessingConfig(), ...config }); - } - - static getProcessingConfig() { - return { - name: UNIT_TYPES.processing, - type: UNIT_TYPES.processing, - }; - } - - setOperation(op) { - this.setProp("operation", op); - } - - setOperationType(type) { - this.setProp("operationType", type); - } - - setInput(input) { - this.setProp("input", input); - } - - get operation() { - return this.prop("operation"); - } - - get operationType() { - return this.prop("operationType"); - } - - get input() { - return this.prop("input"); - } -} diff --git a/src/js/units/reduce.js b/src/js/units/reduce.js deleted file mode 100644 index 152b2a05..00000000 --- a/src/js/units/reduce.js +++ /dev/null @@ -1,17 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class ReduceUnit extends BaseUnit { - constructor(unitName, mapUnit, input) { - super({ ...ReduceUnit.getReduceConfig(unitName, mapUnit, input) }); - } - - static getReduceConfig(unitName, mapUnit, input) { - return { - type: UNIT_TYPES.reduce, - name: unitName, - mapFlowchartId: mapUnit, - input, - }; - } -} diff --git a/src/js/units/subworkflow.js b/src/js/units/subworkflow.js deleted file mode 100644 index dea55ecc..00000000 --- a/src/js/units/subworkflow.js +++ /dev/null @@ -1,15 +0,0 @@ -import { UNIT_TYPES } from "../enums"; -import { BaseUnit } from "./base"; - -export class SubworkflowUnit extends BaseUnit { - constructor(config) { - super({ ...SubworkflowUnit.getSubworkflowConfig(), ...config }); - } - - static getSubworkflowConfig() { - return { - name: "New Subworkflow", - type: UNIT_TYPES.subworkflow, - }; - } -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..fc97d3ef --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@mat3ra/tsconfig/tsconfig-js-py-transpile.json", + "include": [ + "src/js/**/*", + "types/**/*" + ] +} diff --git a/types/periodic-table.d.ts b/types/periodic-table.d.ts new file mode 100644 index 00000000..08f4ed20 --- /dev/null +++ b/types/periodic-table.d.ts @@ -0,0 +1,46 @@ +/** + * Type definition for periodic table element data + */ +interface PeriodicTableElement { + name: string; + symbol: string; + atomic_number: number; + atomic_mass: number; + density_g_per_cm3: string | number; + melting_point_K: number; + boiling_point_K: number; + atomic_radius_pm: string | number; + covalent_radius_pm: number; + ionic_radius_pm: string; + van_der_Waals_radius_pm: string | number; + atomic_volume_cm3_per_mol: string | number; + specific_heat_J_g_mol: string | number; + fusion_heat_kJ_mol: string | number; + evaporation_heat_kJ_mol: string | number; + thermal_conductivity_25C_W_m_K: string | number; + pauling_negativity: string | number; + first_ionizing_kJ_mol: string | number; + oxidation_states: string | number; + electronic_configuration: string; + lattice_structure: string; + lattice_constant_ang: string | number; +} + +/** + * Periodic table mapping element symbols to element data + */ +type PeriodicTable = { + [Symbol in string]: PeriodicTableElement; +}; + +declare module "@exabyte-io/periodic-table.js" { + export const PERIODIC_TABLE: PeriodicTable; +} + +declare module "@exabyte-io/periodic-table.js/lib/js" { + export const PERIODIC_TABLE: PeriodicTable; +} + +declare module "@exabyte-io/periodic-table.js/lib/js/periodic_table" { + export const PERIODIC_TABLE: PeriodicTable; +} From af41e3965585aeae2fd81c22fca01902c3c27252 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Tue, 13 Jan 2026 21:30:50 +0200 Subject: [PATCH 2/3] fix: typescript config --- package-lock.json | 11 +++++++++++ package.json | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc1d53ab..55f7fcd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", "@mat3ra/mode": "2025.11.13-0", "@mat3ra/standata": "2026.1.12-0", + "@mat3ra/tsconfig": "^2024.6.3-0", "@mat3ra/utils": "2025.9.20-0", "chai": "^4.3.4", "eslint": "^7.32.0", @@ -4027,6 +4028,16 @@ "node": ">=4.2.0" } }, + "node_modules/@mat3ra/tsconfig": { + "version": "2024.6.3-0", + "resolved": "https://registry.npmjs.org/@mat3ra/tsconfig/-/tsconfig-2024.6.3-0.tgz", + "integrity": "sha512-dA3gKDSl9+vlZvot1DN+UXfZPgxPSyHkZrkfVCTOWvzwm/3NdJ4cTzrTxjBIWUrZukpVVtH5ao8FbXLB6RDQzQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@mat3ra/utils": { "version": "2025.9.20-0", "resolved": "https://registry.npmjs.org/@mat3ra/utils/-/utils-2025.9.20-0.tgz", diff --git a/package.json b/package.json index 1c5a8f51..fd1d98e3 100644 --- a/package.json +++ b/package.json @@ -48,13 +48,14 @@ "devDependencies": { "@exabyte-io/eslint-config": "2025.5.13-0", "@mat3ra/ade": "git+https://github.com/Exabyte-io/ade#6d494337d83e1b22fe272ff74cc1b6842a7c6561", - "@mat3ra/ide": "2025.11.19-0", - "@mat3ra/mode": "2025.11.13-0", - "@mat3ra/utils": "2025.9.20-0", "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#3a7eab6a28db4a85711795e84ace3c74f7681577", + "@mat3ra/ide": "2025.11.19-0", "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", + "@mat3ra/mode": "2025.11.13-0", "@mat3ra/standata": "2026.1.12-0", + "@mat3ra/tsconfig": "^2024.6.3-0", + "@mat3ra/utils": "2025.9.20-0", "chai": "^4.3.4", "eslint": "^7.32.0", "eslint-config-airbnb": "^19.0.2", From c05cd7c4a1dc7c236225638f55ba31f61aa10b6c Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Fri, 16 Jan 2026 17:07:20 +0200 Subject: [PATCH 3/3] update: QENEBContextProvider data --- package-lock.json | 6 +++--- package.json | 2 +- .../espresso/QENEBContextProvider.ts | 21 ++++++------------- .../espresso/QEPWXContextProvider.ts | 7 +++++-- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 55f7fcd8..3694f3a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@exabyte-io/eslint-config": "2025.5.13-0", "@mat3ra/ade": "git+https://github.com/Exabyte-io/ade#6d494337d83e1b22fe272ff74cc1b6842a7c6561", "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", - "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#3a7eab6a28db4a85711795e84ace3c74f7681577", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#b324747a87f4b3363936974f512e75fe255b52a9", "@mat3ra/ide": "2025.11.19-0", "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", "@mat3ra/mode": "2025.11.13-0", @@ -2861,8 +2861,8 @@ }, "node_modules/@mat3ra/esse": { "version": "0.0.0", - "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#3a7eab6a28db4a85711795e84ace3c74f7681577", - "integrity": "sha512-rxEVn6+BkRYQ4dRK6fLZj/5lxkwB6JepmF2XjYJ3VTg2hyFey4ZdxRsFQNMXjLIOWU4B4QtErQ+m+iHnGewu3Q==", + "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#b324747a87f4b3363936974f512e75fe255b52a9", + "integrity": "sha512-2oi8jV/427kyC8USMPJavMbi9qHas+9OeC70jOrhb4yFdVkeZ8U4dgDYuzKzZYXHnItETnQdFhP/3JXKMfcLBA==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index fd1d98e3..dd8b57d3 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@exabyte-io/eslint-config": "2025.5.13-0", "@mat3ra/ade": "git+https://github.com/Exabyte-io/ade#6d494337d83e1b22fe272ff74cc1b6842a7c6561", "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cb3fa59e2cc143d744f9019322208d928ff8de88", - "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#3a7eab6a28db4a85711795e84ace3c74f7681577", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#b324747a87f4b3363936974f512e75fe255b52a9", "@mat3ra/ide": "2025.11.19-0", "@mat3ra/made": "git+https://github.com/Exabyte-io/made.git#47b3e12a859c45fa72079ed4ddd1675a6a32b4fe", "@mat3ra/mode": "2025.11.13-0", diff --git a/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts b/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts index 46526cfb..66192f1b 100644 --- a/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts +++ b/src/js/context/providers/by_application/espresso/QENEBContextProvider.ts @@ -1,9 +1,6 @@ import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import type { - QENEBContextProviderSchema, - QEPwxContextProviderSchema, -} from "@mat3ra/esse/dist/js/types"; +import type { QENEBContextProviderSchema } from "@mat3ra/esse/dist/js/types"; import type { JSONSchema7 } from "json-schema"; import jobContextMixin, { @@ -55,10 +52,6 @@ type Base = typeof JSONSchemaDataProvider & Constructor & Constructor; -function atomicPositionsToString(atomicPositions: QEPwxContextProviderSchema["ATOMIC_POSITIONS"]) { - return atomicPositions.map(({ X, x, y, z }) => `${X} ${x} ${y} ${z}`).join("\n"); -} - export default class QENEBContextProvider extends (JSONSchemaDataProvider as Base) { readonly name: Name = "input"; @@ -92,13 +85,11 @@ export default class QENEBContextProvider extends (JSONSchemaDataProvider as Bas return { ...rest, - FIRST_IMAGE: atomicPositionsToString(ATOMIC_POSITIONS), - LAST_IMAGE: atomicPositionsToString( - PWXContexts[PWXContexts.length - 1].ATOMIC_POSITIONS, - ), - INTERMEDIATE_IMAGES: PWXContexts.slice(1, PWXContexts.length - 1).map((data) => - atomicPositionsToString(data.ATOMIC_POSITIONS), - ), + FIRST_IMAGE: ATOMIC_POSITIONS, + LAST_IMAGE: PWXContexts[PWXContexts.length - 1].ATOMIC_POSITIONS, + INTERMEDIATE_IMAGES: PWXContexts.slice(1, PWXContexts.length - 1).map((data) => { + return data.ATOMIC_POSITIONS; + }), }; } } diff --git a/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts b/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts index 8887983f..78735264 100644 --- a/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts +++ b/src/js/context/providers/by_application/espresso/QEPWXContextProvider.ts @@ -110,13 +110,16 @@ export default class QEPWXContextProvider extends (JSONSchemaDataProvider as Bas }; // const ATOMIC_POSITIONS = basis.getAtomicPositionsWithConstraintsAsStrings().join("\n"); - const ATOMIC_POSITIONS = basis.elementsAndCoordinatesAndLabelsArray.map( - ([element, coordinate, label]) => { + const ATOMIC_POSITIONS = basis.elementsCoordinatesConstraintsArray.map( + ([element, label, coordinate, constraint]) => { return { X: `${element}${label}`, x: coordinate[0], y: coordinate[1], z: coordinate[2], + "if_pos(1)": constraint[0] ? 1 : 0, + "if_pos(2)": constraint[1] ? 1 : 0, + "if_pos(3)": constraint[2] ? 1 : 0, }; }, );