diff --git a/.github/workflows/dry-release.yml b/.github/workflows/dry-release.yml index 9ca748b7..bbb0bfbd 100644 --- a/.github/workflows/dry-release.yml +++ b/.github/workflows/dry-release.yml @@ -50,6 +50,10 @@ jobs: run: | cd apps/miranum-extension-pack vsce package --out miranum-extension-pack.vsix + - name: Build vsix miranum-config-editor + run: | + cd apps/miranum-config-editor + vsce package --no-dependencies --out miranum-config-editor.vsix - name: Build vsix miranum-console run: | cd apps/miranum-console diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9fcb4eec..ec0cd607 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,6 +27,11 @@ on: type: boolean required: true default: true + miranum-config-editor: + description: 'Release miranum-config-editor app?' + type: boolean + required: true + default: true miranum-console: description: 'Release miranum-console app?' type: boolean @@ -96,6 +101,11 @@ jobs: with: name: miranum-extension-pack path: dist/apps/miranum-extension-pack + # miranum-config-editor + - uses: actions/upload-artifact@v3 + with: + name: miranum-config-editor + path: dist/apps/miranum-config-editor # miranum-console - uses: actions/upload-artifact@v3 with: @@ -231,6 +241,31 @@ jobs: env: VSCE_PAT: ${{ secrets.VSCE_PUBLISH }} + # miranum-config-editor + publish-miranum-config-editor: + if: github.event.inputs.miranum-config-editor == 'true' + runs-on: ubuntu-latest + needs: + - build + - create-release + steps: + - name: Setup NodeJS 16 + uses: actions/setup-node@v3 + with: + node-version: '16' + registry-url: 'https://registry.npmjs.org' + - uses: actions/download-artifact@v3 + with: + name: miranum-config-editor + - name: Prepare + run: npm install && npm install -g @vscode/vsce@latest + - name: Build vsix + run: vsce package --out miranum-config-editor.vsix + - name: Publish extension + run: vsce publish + env: + VSCE_PAT: ${{ secrets.VSCE_PUBLISH }} + # miranum-console publish-miranum-console: if: github.event.inputs.miranum-console == 'true' diff --git a/.vscode/launch.json b/.vscode/launch.json index 8e9fadb0..a72d4277 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,65 +1,85 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "Run miranum-console", - "type": "extensionHost", - "request": "launch", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-console" - ], - "outFiles": [ - "${workspaceFolder}/dist/apps/miranum-console/**/*.js" - ], - "resolveSourceMapLocations": [ - "${workspaceFolder}/dist/apps/miranum-console/**", - "!**/node_modules/**" - ], - "sourceMapPathOverrides": { - "webpack:///./~/*": "${workspaceFolder}/node_modules/*", - "webpack://?:*/*": "${workspaceFolder}/apps/miranum-console/*" - } - }, - { - "name": "Run miranum-forms", - "type": "extensionHost", - "request": "launch", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-forms" - ], - "outFiles": [ - "${workspaceFolder}/dist/apps/miranum-forms/**/*.js" - ], - "resolveSourceMapLocations": [ - "${workspaceFolder}/dist/apps/miranum-forms/**", - "!**/node_modules/**" - ], - "sourceMapPathOverrides": { - "webpack:///./~/*": "${workspaceFolder}/node_modules/*", - "webpack://?:*/*": "${workspaceFolder}/apps/miranum-forms/*" - } - }, - { - "name": "Run miranum-modeler", - "type": "extensionHost", - "request": "launch", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-modeler" - ], - "outFiles": [ - "${workspaceFolder}/dist/apps/miranum-modeler/**/*.js" - ], - "resolveSourceMapLocations": [ - "${workspaceFolder}/dist/apps/miranum-modeler/**", - "!**/node_modules/**" - ], - "sourceMapPathOverrides": { - "webpack:///./~/*": "${workspaceFolder}/node_modules/*", - "webpack://?:*/*": "${workspaceFolder}/apps/miranum-modeler/*" - } - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Run miranum-console", + "type": "extensionHost", + "request": "launch", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-console" + ], + "outFiles": [ + "${workspaceFolder}/dist/apps/miranum-console/**/*.js" + ], + "resolveSourceMapLocations": [ + "${workspaceFolder}/dist/apps/miranum-console/**", + "!**/node_modules/**" + ], + "sourceMapPathOverrides": { + "webpack:///./~/*": "${workspaceFolder}/node_modules/*", + "webpack://?:*/*": "${workspaceFolder}/apps/miranum-console/*" + } + }, + { + "name": "Run miranum-forms", + "type": "extensionHost", + "request": "launch", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-forms" + ], + "outFiles": [ + "${workspaceFolder}/dist/apps/miranum-forms/**/*.js" + ], + "resolveSourceMapLocations": [ + "${workspaceFolder}/dist/apps/miranum-forms/**", + "!**/node_modules/**" + ], + "sourceMapPathOverrides": { + "webpack:///./~/*": "${workspaceFolder}/node_modules/*", + "webpack://?:*/*": "${workspaceFolder}/apps/miranum-forms/*" + } + }, + { + "name": "Run miranum-modeler", + "type": "extensionHost", + "request": "launch", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-modeler" + ], + "outFiles": [ + "${workspaceFolder}/dist/apps/miranum-modeler/**/*.js" + ], + "resolveSourceMapLocations": [ + "${workspaceFolder}/dist/apps/miranum-modeler/**", + "!**/node_modules/**" + ], + "sourceMapPathOverrides": { + "webpack:///./~/*": "${workspaceFolder}/node_modules/*", + "webpack://?:*/*": "${workspaceFolder}/apps/miranum-modeler/*" + } + }, + { + "name": "Run miranum-config-editor", + "type": "extensionHost", + "request": "launch", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/miranum-config-editor" + ], + "outFiles": [ + "${workspaceFolder}/dist/apps/miranum-config-editor/**/*.js" + ], + "resolveSourceMapLocations": [ + "${workspaceFolder}/dist/apps/miranum-config-editor/**", + "!**/node_modules/**" + ], + "sourceMapPathOverrides": { + "webpack:///./~/*": "${workspaceFolder}/node_modules/*", + "webpack://?:*/*": "${workspaceFolder}/apps/miranum-config-editor/*" + } + } + ] } diff --git a/apps/miranum-config-editor-webview/.babelrc b/apps/miranum-config-editor-webview/.babelrc new file mode 100644 index 00000000..19ebd10e --- /dev/null +++ b/apps/miranum-config-editor-webview/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@nx/js/babel" + ] +} diff --git a/apps/miranum-config-editor-webview/.eslintrc.json b/apps/miranum-config-editor-webview/.eslintrc.json new file mode 100644 index 00000000..a2f20128 --- /dev/null +++ b/apps/miranum-config-editor-webview/.eslintrc.json @@ -0,0 +1,40 @@ +{ + "extends": [ + "../../.eslintrc.json", + "plugin:vue/essential", + "prettier", + "@vue/typescript/recommended", + "@vue/eslint-config-prettier" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": { + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-empty-interface": "warn" + } + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} diff --git a/apps/miranum-config-editor-webview/components.d.ts b/apps/miranum-config-editor-webview/components.d.ts new file mode 100644 index 00000000..2fe01146 --- /dev/null +++ b/apps/miranum-config-editor-webview/components.d.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + VApp: typeof import('vuetify/lib')['VApp'] + VCard: typeof import('vuetify/lib')['VCard'] + VContainer: typeof import('vuetify/lib')['VContainer'] + } +} diff --git a/apps/miranum-config-editor-webview/index.html b/apps/miranum-config-editor-webview/index.html new file mode 100644 index 00000000..5352543c --- /dev/null +++ b/apps/miranum-config-editor-webview/index.html @@ -0,0 +1,18 @@ + + + + + MiranumConfigEditorWebview + + + + + + + + + +
+ + + diff --git a/apps/miranum-config-editor-webview/jest.config.ts b/apps/miranum-config-editor-webview/jest.config.ts new file mode 100644 index 00000000..d16cff2b --- /dev/null +++ b/apps/miranum-config-editor-webview/jest.config.ts @@ -0,0 +1,23 @@ +module.exports = { + displayName: "miranum-config-editor-webview", + preset: "../../jest.preset.js", + transform: { + "^.+.vue$": "@vue/vue2-jest", + ".+.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": + "jest-transform-stub", + "^.+.tsx?$": [ + "ts-jest", + { + tsconfig: "apps/miranum-config-editor-webview/tsconfig.spec.json", + }, + ], + }, + moduleFileExtensions: ["ts", "tsx", "vue", "js", "json"], + coverageDirectory: "../../coverage/apps/miranum-config-editor-webview", + snapshotSerializers: ["jest-serializer-vue"], + globals: { + "vue-jest": { + tsConfig: "apps/miranum-config-editor-webview/tsconfig.spec.json", + }, + }, +}; diff --git a/apps/miranum-config-editor-webview/project.json b/apps/miranum-config-editor-webview/project.json new file mode 100644 index 00000000..fef69254 --- /dev/null +++ b/apps/miranum-config-editor-webview/project.json @@ -0,0 +1,102 @@ +{ + "name": "miranum-config-editor-webview", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/miranum-config-editor-webview/src", + "tags": [], + "targets": { + "observe": { + "executor": "@nx/vite:build", + "outputs": [ + "{options.outputPath}" + ], + "defaultConfiguration": "development", + "options": { + "watch": true, + "outputPath": "dist/apps/miranum-config-editor/miranum-config-editor-webview", + "configFile": "apps/miranum-config-editor-webview/vite.config.ts", + "emptyOutDir": false + }, + "configurations": { + "development": { + "extractLicenses": false, + "optimization": false, + "sourceMap": false, + "vendorChunk": true + } + } + }, + "build": { + "executor": "@nx/vite:build", + "outputs": [ + "{options.outputPath}" + ], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/apps/miranum-config-editor/miranum-config-editor-webview", + "configFile": "apps/miranum-config-editor-webview/vite.config.ts" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "serve": { + "executor": "@nx/vite:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "miranum-config-editor-webview:build" + }, + "configurations": { + "development": { + "buildTarget": "miranum-config-editor-webview:build:development", + "hmr": true + }, + "production": { + "buildTarget": "miranum-config-editor-webview:build:production", + "hmr": false + } + } + }, + "preview": { + "executor": "@nx/vite:preview-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "miranum-config-editor-webview:build" + }, + "configurations": { + "development": { + "buildTarget": "miranum-config-editor-webview:build:development" + }, + "production": { + "buildTarget": "miranum-config-editor-webview:build:production" + } + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}" + ], + "options": { + "jestConfig": "apps/miranum-forms-webview/jest.config.ts", + "passWithNoTests": true + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": [ + "{options.outputFile}" + ], + "options": { + "lintFilePatterns": [ + "apps/miranum-config-editor-webview/**/*.ts" + ] + } + } + } +} diff --git a/apps/miranum-dmn-modeler-webview/public/favicon.ico b/apps/miranum-config-editor-webview/public/favicon.ico similarity index 100% rename from apps/miranum-dmn-modeler-webview/public/favicon.ico rename to apps/miranum-config-editor-webview/public/favicon.ico diff --git a/apps/miranum-config-editor-webview/src/app/App.vue b/apps/miranum-config-editor-webview/src/app/App.vue new file mode 100644 index 00000000..4d33fb3d --- /dev/null +++ b/apps/miranum-config-editor-webview/src/app/App.vue @@ -0,0 +1,180 @@ + + + + + diff --git a/apps/miranum-config-editor-webview/src/app/composables/utils.ts b/apps/miranum-config-editor-webview/src/app/composables/utils.ts new file mode 100644 index 00000000..85b15957 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/app/composables/utils.ts @@ -0,0 +1,25 @@ +/** + * Create a way to resolve a Promise manually. + * @returns - { + * wait - Returns the Promise to await + * done - Resolves the Promise returned by wait + * } + */ +export function createResolver() { + let resolver: (r: T | undefined) => void; + const promise = new Promise((resolve) => { + resolver = (response: T | undefined) => { + resolve(response); + }; + }); + + function wait() { + return promise; + } + + function done(data: T | undefined) { + resolver(data); + } + + return { wait, done }; +} diff --git a/apps/miranum-config-editor-webview/src/app/composables/vscode.ts b/apps/miranum-config-editor-webview/src/app/composables/vscode.ts new file mode 100644 index 00000000..64a7f319 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/app/composables/vscode.ts @@ -0,0 +1,158 @@ +/** + * This module contains everything related to the vscode API. + */ +import { JsonSchema, UISchemaElement } from "@jsonforms/core"; +import { WebviewApi } from "vscode-webview"; + +import jsonSchema from "../../assets/schema.json"; +import jsonUiSchema from "../../assets/uischema.json"; +import jsonData from "../../assets/data.json"; +import { + ConfigEditorData, + MessageType, + VscMessage, +} from "@miranum-ide/vscode/shared/miranum-config-editor"; + +export interface VscState { + schema: JsonSchema; + uischema: UISchemaElement; + data: JSON; +} + +export interface VsCode { + getState(): VscState; + + setState(state: VscState): void; + + updateState(state: Partial): void; + + postMessage(message: VscMessage): void; +} + +export class MissingStateError extends Error { + constructor() { + super("State is missing."); + } +} + +export class VsCodeImpl implements VsCode { + private vscode: WebviewApi; + + constructor() { + this.vscode = acquireVsCodeApi(); + } + + public getState(): VscState { + const state = this.vscode.getState(); + if (!state) { + throw new MissingStateError(); + } + + return state; + } + + public setState(state: VscState) { + this.vscode.setState({ + ...state, + }); + } + + public updateState(state: Partial) { + this.setState({ + ...this.getState(), + ...state, + }); + } + + public postMessage(message: VscMessage) { + this.vscode.postMessage(message); + } +} + +/** + * To simplify the development of the webview, we allow it to run in the browser. + * For this purpose, the functionality of the extension/backend is mocked. + */ +export class VsCodeMock implements VsCode { + private state: VscState | undefined; + + getState(): VscState { + if (!this.state) { + throw new MissingStateError(); + } + + return this.state; + } + + async postMessage(message: VscMessage): Promise { + const { type, payload, logger } = message; + switch (type) { + case MessageType.initialize: { + console.log("[Log]", logger); + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: MessageType.initialize, + payload: { + schema: JSON.stringify(jsonSchema), + uischema: JSON.stringify(jsonUiSchema), + data: JSON.stringify(jsonData), + }, + }, + }), + ); + break; + } + case MessageType.syncDocument: { + console.log( + "[Log] Send data to the backend...", + JSON.parse(payload?.data ?? '{ "data": "No data"}"'), + ); + break; + } + case MessageType.error: { + console.error("[Log]", logger); + break; + } + case MessageType.info: { + console.log("[Log]", logger); + break; + } + } + } + + setState(state: VscState): void { + this.state = state; + console.log("[Log] setState()", this.getState()); + } + + updateState(state: Partial): void { + const currentState = this.getState(); + let schema: JsonSchema; + if (state?.schema) { + schema = state.schema; + } else { + schema = currentState.schema; + } + let uischema: UISchemaElement; + if (state?.uischema) { + uischema = state.uischema; + } else { + uischema = currentState.uischema; + } + let data: JSON; + if (state?.data) { + data = state.data; + } else { + data = currentState.data; + } + + this.state = { + schema, + uischema, + data, + }; + + console.log("[Log] updateState()", this.getState()); + } +} diff --git a/apps/miranum-config-editor-webview/src/assets/data.json b/apps/miranum-config-editor-webview/src/assets/data.json new file mode 100644 index 00000000..59a6d437 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/assets/data.json @@ -0,0 +1,9 @@ +{ + "name": "John Doe", + "vegetarian": false, + "birthDate": "1985-06-02", + "personalData": { + "age": 34 + }, + "postalCode": "12345" +} \ No newline at end of file diff --git a/apps/miranum-config-editor-webview/src/assets/i18n.json b/apps/miranum-config-editor-webview/src/assets/i18n.json new file mode 100644 index 00000000..711ea655 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/assets/i18n.json @@ -0,0 +1,126 @@ +{ + "en": { + "name": { + "label": "Name", + "description": "The name of the person" + }, + "vegetarian": { + "label": "Vegetarian", + "description": "Whether the person is a vegetarian" + }, + "birth": { + "label": "Birth Date", + "description": "" + }, + "nationality": { + "label": "Nationality", + "description": "" + }, + "personal-data": { + "age": { + "label": "Age" + }, + "driving": { + "label": "Driving Skill", + "description": "Indicating experience level" + } + }, + "height": { + "label": "Height" + }, + "occupation": { + "label": "Occupation", + "description": "" + }, + "postal-code": { + "label": "Postal Code" + }, + "error": { + "required": "field is required" + } + }, + "de": { + "name": { + "label": "Name", + "description": "Der Name der Person" + }, + "vegetarian": { + "label": "Vegetarier", + "description": "Isst die Person vegetarisch?" + }, + "birth": { + "label": "Geburtsdatum", + "description": "" + }, + "nationality": { + "label": "Nationalität", + "description": "", + "Other": "Andere" + }, + "personal-data": { + "age": { + "label": "Alter" + }, + "driving": { + "label": "Fahrkenntnisse", + "description": "Fahrerfahrung der Person" + } + }, + "height": { + "label": "Größe" + }, + "occupation": { + "label": "Beruf", + "description": "" + }, + "postal-code": { + "label": "Postleitzahl" + }, + "error": { + "required": "Pflichtfeld" + }, + "Additional Information": "Zusätzliche Informationen" + }, + "bg": { + "name": { + "label": "Име", + "description": "Името на лицето" + }, + "vegetarian": { + "label": "Вегетарианец", + "description": "Дали човекът е вегетарианец" + }, + "birth": { + "label": "Рождена дата", + "description": "" + }, + "nationality": { + "label": "Националност", + "description": "" + }, + "personal-data": { + "age": { + "label": "Възраст", + "description": "Моля, въведете вашата възраст." + }, + "driving": { + "label": "Шофьорски умения", + "description": "Показва ниво на опит" + } + }, + "height": { + "label": "Височина" + }, + "occupation": { + "label": "Професия", + "description": "" + }, + "postal-code": { + "label": "Пощенски код" + }, + "error": { + "required": "полето е задължително" + }, + "Additional Information": "Допълнителна информация" + } +} diff --git a/apps/miranum-config-editor-webview/src/assets/schema.json b/apps/miranum-config-editor-webview/src/assets/schema.json new file mode 100644 index 00000000..b20415b6 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/assets/schema.json @@ -0,0 +1,57 @@ +{ + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 3, + "description": "Please enter your name", + "i18n": "name" + }, + "vegetarian": { + "type": "boolean", + "i18n": "vegetarian" + }, + "birthDate": { + "type": "string", + "format": "date", + "i18n": "birth" + }, + "nationality": { + "type": "string", + "enum": ["DE", "IT", "JP", "US", "RU", "Other"], + "i18n": "nationality" + }, + "personalData": { + "type": "object", + "properties": { + "age": { + "type": "integer", + "description": "Please enter your age.", + "i18n": "personal-data.age" + }, + "height": { + "type": "number", + "i18n": "height" + }, + "drivingSkill": { + "type": "number", + "maximum": 10, + "minimum": 1, + "default": 7, + "i18n": "personal-data.driving" + } + }, + "required": ["age", "height"] + }, + "occupation": { + "type": "string", + "i18n": "occupation" + }, + "postalCode": { + "type": "string", + "maxLength": 5, + "i18n": "postal-code" + } + }, + "required": ["occupation", "nationality"] +} diff --git a/apps/miranum-config-editor-webview/src/assets/uischema.json b/apps/miranum-config-editor-webview/src/assets/uischema.json new file mode 100644 index 00000000..80c36d5b --- /dev/null +++ b/apps/miranum-config-editor-webview/src/assets/uischema.json @@ -0,0 +1,55 @@ +{ + "type": "VerticalLayout", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/name" + }, + { + "type": "Control", + "scope": "#/properties/personalData/properties/age" + }, + { + "type": "Control", + "scope": "#/properties/birthDate" + } + ] + }, + { + "type": "Label", + "text": "Additional Information" + }, + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/personalData/properties/height" + }, + { + "type": "Control", + "scope": "#/properties/nationality" + }, + { + "type": "Control", + "scope": "#/properties/occupation", + "options": { + "suggestion": [ + "Accountant", + "Engineer", + "Freelancer", + "Journalism", + "Physician", + "Student", + "Teacher", + "Other" + ] + } + } + ] + } + ] +} diff --git a/apps/miranum-config-editor-webview/src/main.ts b/apps/miranum-config-editor-webview/src/main.ts new file mode 100644 index 00000000..a24a79ea --- /dev/null +++ b/apps/miranum-config-editor-webview/src/main.ts @@ -0,0 +1,10 @@ +import Vue from "vue"; +import App from "./app/App.vue"; +import vuetify from "./plugins/vuetify"; + +Vue.config.productionTip = false; + +new Vue({ + vuetify, + render: (h) => h(App), +}).$mount("#app"); diff --git a/apps/miranum-config-editor-webview/src/plugins/vuetify.ts b/apps/miranum-config-editor-webview/src/plugins/vuetify.ts new file mode 100644 index 00000000..b58dcf04 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/plugins/vuetify.ts @@ -0,0 +1,49 @@ +import Vue from "vue"; +import Vuetify from "vuetify/lib"; +import { VuetifyPreset } from "vuetify/types/services/presets"; + +Vue.use(Vuetify); + +export const preset: Partial = { + icons: { + iconfont: "mdi", + values: {}, + }, + theme: { + dark: false, + default: "light", + disable: false, + options: { + cspNonce: undefined, + customProperties: undefined, + minifyTheme: undefined, + themeCache: undefined, + }, + themes: { + light: { + primary: "#1976D2", + secondary: "#424242", + accent: "#82B1FF", + error: "#FF5252", + info: "#2196F3", + success: "#4CAF50", + warning: "#FB8C00", + }, + dark: { + primary: "#2196F3", + secondary: "#424242", + accent: "#FF4081", + error: "#FF5252", + info: "#2196F3", + success: "#4CAF50", + warning: "#FB8C00", + }, + }, + }, +}; + +export default new Vuetify({ + preset, + rtl: false, + theme: { dark: false }, +}); diff --git a/apps/miranum-config-editor-webview/src/shims-vue.d.ts b/apps/miranum-config-editor-webview/src/shims-vue.d.ts new file mode 100644 index 00000000..92f1a23c --- /dev/null +++ b/apps/miranum-config-editor-webview/src/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import Vue from "vue"; + export default Vue; + export const entry; +} diff --git a/apps/miranum-config-editor-webview/src/shims-vuetify.d.ts b/apps/miranum-config-editor-webview/src/shims-vuetify.d.ts new file mode 100644 index 00000000..c03502b7 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/shims-vuetify.d.ts @@ -0,0 +1,4 @@ +declare module "vuetify/lib/framework" { + import Vuetify from "vuetify"; + export default Vuetify; +} diff --git a/apps/miranum-config-editor-webview/src/styles.css b/apps/miranum-config-editor-webview/src/styles.css new file mode 100644 index 00000000..90d4ee00 --- /dev/null +++ b/apps/miranum-config-editor-webview/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/miranum-config-editor-webview/tsconfig.app.json b/apps/miranum-config-editor-webview/tsconfig.app.json new file mode 100644 index 00000000..8314507d --- /dev/null +++ b/apps/miranum-config-editor-webview/tsconfig.app.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + }, + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/apps/miranum-config-editor-webview/tsconfig.json b/apps/miranum-config-editor-webview/tsconfig.json new file mode 100644 index 00000000..6c4bc729 --- /dev/null +++ b/apps/miranum-config-editor-webview/tsconfig.json @@ -0,0 +1,38 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": [ + "ESNext", + "DOM" + ], + "moduleResolution": "Node", + "strict": true, + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "skipLibCheck": true, + "types": [ + "vite/client", + "vitest" + ] + }, + "include": [ + "src" + ], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/apps/miranum-config-editor-webview/tsconfig.spec.json b/apps/miranum-config-editor-webview/tsconfig.spec.json new file mode 100644 index 00000000..6d3be742 --- /dev/null +++ b/apps/miranum-config-editor-webview/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] + }, + "include": [ + "vite.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/apps/miranum-config-editor-webview/vite.config.ts b/apps/miranum-config-editor-webview/vite.config.ts new file mode 100644 index 00000000..a7a514c2 --- /dev/null +++ b/apps/miranum-config-editor-webview/vite.config.ts @@ -0,0 +1,55 @@ +/// +import { defineConfig } from "vite"; + +import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin"; +import vue from "@vitejs/plugin-vue2"; +import { VuetifyResolver } from "unplugin-vue-components/resolvers"; +import Component from "unplugin-vue-components/vite"; + +export default defineConfig({ + cacheDir: "../../node_modules/.vite/miranum-config-editor-webview", + + server: { + port: 4200, + host: "localhost", + }, + + preview: { + port: 4300, + host: "localhost", + }, + + plugins: [ + nxViteTsPaths(), + vue(), + Component({ + resolvers: [VuetifyResolver()], + }), + ], + + build: { + target: "es2021", + commonjsOptions: { transformMixedEsModules: true }, + chunkSizeWarningLimit: 1200, + rollupOptions: { + output: { + // don't hash the name of the output file (index.js) + entryFileNames: `[name].js`, + assetFileNames: `[name].[ext]`, + }, + }, + }, + + define: { + "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), + }, + + test: { + globals: true, + cache: { + dir: "../../node_modules/.vitest", + }, + environment: "jsdom", + include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], + }, +}); diff --git a/apps/miranum-config-editor/.eslintrc.json b/apps/miranum-config-editor/.eslintrc.json new file mode 100644 index 00000000..ea8861d0 --- /dev/null +++ b/apps/miranum-config-editor/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": [ + "../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} diff --git a/apps/miranum-config-editor/.vscodeignore b/apps/miranum-config-editor/.vscodeignore new file mode 100644 index 00000000..56b6f123 --- /dev/null +++ b/apps/miranum-config-editor/.vscodeignore @@ -0,0 +1,3 @@ +node_modules +**/favicon.ico +**/index.html diff --git a/apps/miranum-config-editor/CHANGELOG.md b/apps/miranum-config-editor/CHANGELOG.md new file mode 100644 index 00000000..39845608 --- /dev/null +++ b/apps/miranum-config-editor/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +* Initial version of the *Miranum Config Editor* (#412) + + +[unreleased]: https://github.com/Miragon/miranum-ide/compare/release/v0.5.5...HEAD diff --git a/apps/miranum-config-editor/README.md b/apps/miranum-config-editor/README.md new file mode 100644 index 00000000..7fb350f4 --- /dev/null +++ b/apps/miranum-config-editor/README.md @@ -0,0 +1,126 @@ +
+ + +[![Contributors][contributors-shield]][contributors-url] +[![Forks][forks-shield]][forks-url] +[![Stargazers][stars-shield]][stars-url] +[![Issues][issues-shield]][issues-url] +[![MIT License][license-shield]][license-url] + + + +
+
+ + Logo + +

Miranum IDE by Miragon

+ + Twitter Follow + + + LinkedIn Follow + +

+ One IDE for everything! +
+ Report Bug + · + Request Feature +

+
+ +## About The Project [![Version][version-shield]][version-url] [![Installs][installs-shield]][installs-url] + +> Note: [Miranum IDE](https://marketplace.visualstudio.com/items?itemName=miragon-gmbh.miranum-ide) is a collection of *VS Code Plugins* +> that allows you to edit, manage and access all artifacts for your +> process application in one place. +> **Miranum Config Editor** is one component of *Miranum IDE*. + +### Introducing the *Miranum Config Editor* Plugin for VS Code! + +Are you tired of manually editing complex configuration files? +Say goodbye to the hassle and welcome the simplicity of JSON Forms. +Our plugin is designed to make editing config files a breeze, providing a user-friendly interface right within your favorite code editor. +With the **Miranum Config Editor** Plugin, you can easily create, modify, and validate JSON-based configuration files. +Here's what you can expect from our plugin: + +1. Intuitive UI: Our plugin seamlessly integrates with VS Code, providing a clean and intuitive user interface. + Say goodbye to the days of struggling with complex JSON structures. +2. Form-based Editing: Edit your config files using familiar form-based controls. + No more worrying about syntax errors or missing commas. + Our plugin ensures that your JSON remains valid at all times. +3. Real-time Validation: Instantly catch errors and typos as you type. + Our plugin provides real-time validation, highlighting any issues in your config file and offering helpful suggestions. +4. Schema Support: Leverage the power of JSON schemas to define the structure and constraints of your config files. + Our plugin supports schema validation, ensuring that your config files adhere to the specified rules. +5. Customization Options: Tailor the editing experience to your needs. + Customize the form layout, define default values, and specify validation rules to match your specific requirements. +6. Seamless Integration: Our plugin seamlessly integrates with your existing VS Code workflow. + Enjoy all the benefits of a dedicated config editor without leaving your favorite code editor. + +Say goodbye to the days of manual config file editing. +Install the **Miranum Config Editor** Plugin for VS Code today and experience the simplicity and power of form-based config editing. +Boost your productivity and eliminate errors with ease. + +## Quickstart + +### Prerequisites + +This plugin leverages the power of [JSON Forms](https://jsonforms.io/). +To use it, you need your `JSON Schema` and `UI-Schema` file, that define your form. +If you don't have them yet, you can create them using the [Miranum JSON Forms Plugin](https://marketplace.visualstudio.com/items?itemName=miragon-gmbh.miranum-json-forms). +> Note: **Miranum JSON Forms** is a preview release. +> With that plugin you are able to edit `.form.json` files. +> This file will contain the `JSON Schema` **AND** `UI-Schema`. +> You have to manually copy the content out of this file into your `JSON Schema` and `UI-Schema` files. + +Once you have your `JSON Schema` and `UI-Schema` files, you need to set the path to those files in the settings. +To do this, open the setting️s (Code > Preferences > Preferences) and search for `miranum-ide`. +There should be an entry called `Miranum IDE > Config Editor: Base Path` with an empty text field. +You need to enter the path to your `JSON Schema` and `UI-Schema` files in this text field. + +### Usage + +To use the editor, you have to open or create a `.config.json` file. +The plugin will then search for the `JSON Schema` and `UI-Schema` files in the directory you specified in the settings. +To find the right files, you have to stick to the following naming convention: + +| Your Config File | Your JSON Schema | Your UI Schema | +|--------------------------|-----------------------|-------------------------| +| my-config.s3.config.json | schema.s3.config.json | uischema.s3.config.json | + +The plugin will read these files and display your form in the editor. + +🚀 **Now you are ready to start editing!** 🚀 + +## Contributing + +Contributions are what make the open-source community such an amazing place to learn, inspire, and create. +Any contributions you make are **greatly appreciated**. + +To learn more about the frameworks we use and how you can get involved, click [here](https://github.com/Miragon/miranum-ide/blob/main/README.md). +Furthermore, please have a look at our [Code of Conduct](https://miranum.com/docs/components/contributing/). + +### License + +Distributed under the [Apache License Version 2.0](https://github.com/Miragon/miranum-ide/blob/main/LICENSE). + + + + +[contributors-shield]: https://img.shields.io/github/contributors/Miragon/miranum-ide.svg?style=for-the-badge +[contributors-url]: https://github.com/Miragon/miranum-ide/graphs/contributors +[forks-shield]: https://img.shields.io/github/forks/Miragon/miranum-ide.svg?style=for-the-badge +[forks-url]: https://github.com/Miragon/miranum-ide/network/members +[stars-shield]: https://img.shields.io/github/stars/Miragon/miranum-ide.svg?style=for-the-badge +[stars-url]: https://github.com/Miragon/miranum-ide/stargazers +[issues-shield]: https://img.shields.io/github/issues/Miragon/miranum-ide.svg?style=for-the-badge +[issues-url]: https://github.com/Miragon/miranum-ide/issues +[license-shield]: https://img.shields.io/github/license/Miragon/miranum-ide.svg?style=for-the-badge +[license-url]: https://github.com/Miragon/miranum-ide/blob/main/LICENSE + +[version-shield]: https://img.shields.io/visual-studio-marketplace/v/miragon-gmbh.miranum-config-editor +[version-url]: https://marketplace.visualstudio.com/items?itemName=miragon-gmbh.miranum-config-editor +[installs-shield]: https://img.shields.io/visual-studio-marketplace/i/miragon-gmbh.miranum-config-editor +[installs-url]: https://marketplace.visualstudio.com/items?itemName=miragon-gmbh.miranum-config-editor diff --git a/apps/miranum-config-editor/docs/architecture.puml b/apps/miranum-config-editor/docs/architecture.puml new file mode 100644 index 00000000..5beb82d6 --- /dev/null +++ b/apps/miranum-config-editor/docs/architecture.puml @@ -0,0 +1,76 @@ +@startuml +'https://plantuml.com/component-diagram + +skinparam component { + backgroundColor<> LightGray + backgroundColor<> LightGreen + backgroundColor<> LightBlue + backgroundColor<> LightYellow +} + +component extension.ts <> { + component CustomTextEditor +} +component "IoC-Container" <> + +component "WebviewAdapter" as InWebviewAdapter <> +component "DocumentAdapter" as InDocumentAdapter <> + +component { + portin InitWebviewInPort + portin RestoreWebviewInPort + portin ReadVsCodeConfigInPort + portin ReadJsonFormInPort + portin SyncWebviewInPort + portin SyncDocumentInPort + + portout DocumentOutPort + portout WebviewOutPort + portout ReaderOutPort + portout VsCodeConfigOutPort + + component InitWebviewUseCase <> + component RestoreWebviewUseCase <> + component ReadVsCodeConfigUseCase <> + component ReadJsonFormUseCase <> + component SyncWebviewUseCase <> + component SyncDocumentUseCase <> +} + +component "WebviewAdapter" as OutWebviewAdapter <> +component "DocumentAdapter" as OutDocumentAdapter <> +component "ReaderAdapter" as OutReaderAdapter <> +component "VsCodeConfigAdapter" as OutVsCodeConfigAdapter <> + +CustomTextEditor --> InWebviewAdapter : create +CustomTextEditor --> InDocumentAdapter : create +CustomTextEditor --> OutWebviewAdapter : set active webview +CustomTextEditor --> OutDocumentAdapter : set active document + +InWebviewAdapter --> InitWebviewInPort +InWebviewAdapter --> RestoreWebviewInPort +InWebviewAdapter --> ReadVsCodeConfigInPort +InWebviewAdapter --> ReadJsonFormInPort +InWebviewAdapter --> SyncDocumentInPort +InDocumentAdapter --> SyncWebviewInPort + +InitWebviewInPort <.. InitWebviewUseCase +RestoreWebviewInPort <.. RestoreWebviewUseCase +ReadVsCodeConfigInPort <.. ReadVsCodeConfigUseCase +ReadJsonFormInPort <.. ReadJsonFormUseCase +SyncWebviewInPort <.. SyncWebviewUseCase +SyncDocumentInPort <.. SyncDocumentUseCase + +InitWebviewUseCase --> WebviewOutPort +RestoreWebviewUseCase --> WebviewOutPort +ReadVsCodeConfigUseCase --> VsCodeConfigOutPort +ReadJsonFormUseCase --> ReaderOutPort +SyncWebviewUseCase --> WebviewOutPort +SyncDocumentUseCase --> DocumentOutPort + +WebviewOutPort <.. OutWebviewAdapter +VsCodeConfigOutPort <.. OutVsCodeConfigAdapter +ReaderOutPort <.. OutReaderAdapter +DocumentOutPort <.. OutDocumentAdapter + +@enduml diff --git a/apps/miranum-config-editor/docs/development.md b/apps/miranum-config-editor/docs/development.md new file mode 100644 index 00000000..b6c3ed9e --- /dev/null +++ b/apps/miranum-config-editor/docs/development.md @@ -0,0 +1,37 @@ +# Development + +

+ Component Diagram
+ The application's software architecture +

+ +## Build With + +* Typescript +* Vue 2 +* Vuetify + +## Quickstart + +The *Mirnaum Config Editor* Plugin contains the following apps: +* [miranum-config-editor](../README.md) - The backend application +* [miranum-config-editor-webview](../../miranum-config-editor-webview) - The frontend application + +1. Build the plugin + ```shell + # Install dependencies + npm install + + # Build the backend and frontend in watch mode + npx nx run miranum-config-editor:observe-all + ``` + +2. Start the Plugin in VS Code + 1. Start VS Code + 2. Switch to the `Run and Debug` view on the left panel + 3. Select `Run miranum-config-editor` from the dropdown at the top + 4. A new VS Code window will open with the plugin running + 5. In this new window, open the folder [miranum-ide/resources/config-editor-example](../../../resources/config-editor-example) + 6. Open the settings (Code > Preferences > Settings) and search for `miranum-ide` + 7. In the text-field, enter the full path to the JSON Schema and UI-Schema (e.g. `/Users/my-user/miranum-ide/resources/config-editor-example/some/path`) + 8. Close the settings and open the file [configs/miranum-platform.process.config.json](../../../resources/config-editor-example/configs/miranum-platform.process.config.json) diff --git a/apps/miranum-config-editor/jest.config.ts b/apps/miranum-config-editor/jest.config.ts new file mode 100644 index 00000000..e40a6a06 --- /dev/null +++ b/apps/miranum-config-editor/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'miranum-config-editor', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }] + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/apps/miranum-config-editor' +}; diff --git a/apps/miranum-config-editor/package.json b/apps/miranum-config-editor/package.json new file mode 100644 index 00000000..b6d68473 --- /dev/null +++ b/apps/miranum-config-editor/package.json @@ -0,0 +1,62 @@ +{ + "name": "miranum-config-editor", + "displayName": "Miranum Config Editor", + "description": "This extension provides an editor for process configurations.", + "preview": true, + "version": "0.1.0", + "license": "Apache-2.0", + "publisher": "miragon-gmbh", + "homepage": "https://www.miranum.io/", + "icon": "assets/miranum_logo.png", + "galleryBanner": { + "color": "#F0F8FF", + "theme": "light" + }, + "repository": { + "type": "git", + "url": "https://github.com/Miragon/miranum-ide.git" + }, + "bugs": { + "url": "https://github.com/Miragon/miranum-ide/issues" + }, + "engines": { + "vscode": "^1.76.0" + }, + "categories": [ + "Other" + ], + "keywords": [ + "Mirnaum", + "Configuration" + ], + "main": "main.js", + "activationEvents": [], + "contributes": { + "customEditors": [ + { + "viewType": "miranum.configEditor", + "displayName": "Miranum Config Editor", + "selector": [ + { + "filenamePattern": "*.*.config.json" + }, + { + "filenamePattern": "*.*config.json" + } + ], + "priority": "default" + } + ], + "configuration": { + "title": "MiranumConfigEditor", + "properties": { + "miranumIDE.configEditor.basePath": { + "scope": "application", + "type": "string", + "description": "Enter the path to your schema and ui-schema files.", + "pattern": "^(.+)\/([^\/]+)$" + } + } + } + } +} diff --git a/apps/miranum-config-editor/project.json b/apps/miranum-config-editor/project.json new file mode 100644 index 00000000..ba88dc82 --- /dev/null +++ b/apps/miranum-config-editor/project.json @@ -0,0 +1,154 @@ +{ + "name": "miranum-config-editor", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/miranum-config-editor/src", + "projectType": "application", + "implicitDependencies": [ + "miranum-config-editor-webview" + ], + "targets": { + "observe-all": { + "executor": "nx:run-commands", + "parallel": true, + "options": { + "commands": [ + { + "command": "npx nx observe miranum-config-editor", + "prefix": "miranum-config-editor", + "color": "blue" + }, + { + "command": "npx nx observe miranum-config-editor-webview", + "prefix": "miranum-config-editor-webview", + "color": "green" + } + ] + } + }, + "observe": { + "executor": "@nx/webpack:webpack", + "outputs": [ + "{options.outputPath}" + ], + "defaultConfiguration": "development", + "options": { + "watch": true, + "target": "node", + "compiler": "tsc", + "outputPath": "dist/apps/miranum-config-editor", + "deleteOutputPath": false, + "main": "apps/miranum-config-editor/src/main.ts", + "tsConfig": "apps/miranum-config-editor/tsconfig.app.json", + "generatePackageJson": true, + "webpackConfig": "apps/miranum-config-editor/webpack.config.js", + "babelUpwardRootMode": true, + "assets": [ + { + "glob": "images/komet.svg", + "input": "./", + "output": "/assets" + } + ] + }, + "configurations": { + "development": { + "extractLicenses": false, + "optimization": false, + "sourceMap": true + } + } + }, + "build": { + "executor": "@nx/webpack:webpack", + "outputs": [ + "{options.outputPath}" + ], + "defaultConfiguration": "production", + "options": { + "target": "node", + "compiler": "tsc", + "outputPath": "dist/apps/miranum-config-editor", + "deleteOutputPath": false, + "main": "apps/miranum-config-editor/src/main.ts", + "tsConfig": "apps/miranum-config-editor/tsconfig.app.json", + "generatePackageJson": true, + "webpackConfig": "apps/miranum-config-editor/webpack.config.js", + "babelUpwardRootMode": true, + "assets": [ + { + "input": "./images/", + "glob": "komet.svg", + "output": "/assets" + }, + { + "input": "./images/", + "glob": "miranum_logo.png", + "output": "/assets" + }, + { + "input": "./", + "glob": "LICENSE", + "output": "/" + }, + { + "input": "./apps/miranum-config-editor/", + "glob": ".vscodeignore", + "output": "/" + }, + { + "glob": "README.md", + "input": "./apps/miranum-config-editor/", + "output": "/" + }, + { + "glob": "CHANGELOG.md", + "input": "./apps/miranum-config-editor/", + "output": "/" + } + ] + }, + "configurations": { + "production": { + "optimization": true, + "extractLicenses": true, + "inspect": false, + "sourceMap": false, + "fileReplacements": [ + { + "replace": "apps/miranum-config-editor/src/environments/environment.ts", + "with": "apps/miranum-config-editor/src/environments/environment.prod.ts" + } + ] + } + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": [ + "{options.outputFile}" + ], + "options": { + "lintFilePatterns": [ + "apps/miranum-config-editor/**/*.ts" + ] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}" + ], + "options": { + "jestConfig": "apps/miranum-config-editor/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + }, + "tags": [] +} diff --git a/apps/miranum-config-editor/src/adapter/adapterIn.ts b/apps/miranum-config-editor/src/adapter/adapterIn.ts new file mode 100644 index 00000000..a09537a0 --- /dev/null +++ b/apps/miranum-config-editor/src/adapter/adapterIn.ts @@ -0,0 +1,200 @@ +/** + * @module In-Adapter + * @description In the context of the "Hexagonal Architecture", In-Adapters are objects that call our application. \ + * List of Adapters + * - {@link WebviewAdapter} + * - {@link DocumentAdapter} + */ +import { TextDocument, Uri, Webview, workspace } from "vscode"; +import { inject, injectable } from "tsyringe"; + +import { EXTENSION_CONTEXT, setUpdateFrom, updateFrom, UpdateFrom } from "../common"; +import { + InitWebviewCommand, + InitWebviewInPort, + ReadJsonFormInPort, + ReadJsonFormQuery, + ReadVsCodeConfigInPort, + ReadVsCodeConfigQuery, + RestoreWebviewCommand, + RestoreWebviewInPort, + SyncDocumentCommand, + SyncDocumentInPort, + SyncWebviewCommand, + SyncWebviewInPort +} from "../application/portsIn"; +import { ConfigEditorData, MessageType, VscMessage } from "@miranum-ide/vscode/shared/miranum-config-editor"; + +/** + * @class WebviewAdapter + */ +@injectable() +export class WebviewAdapter { + private files: Map> | undefined; + + constructor( + webview: Webview, + document: TextDocument, + @inject("ReadVsCodeConfigInPort") + private readonly readVsCodeConfigInPort: ReadVsCodeConfigInPort, + @inject("ReadJsonFormInPort") + private readonly readJsonFormInPort: ReadJsonFormInPort, + @inject("InitWebviewInPort") + private readonly initWebviewInPort: InitWebviewInPort, + @inject("RestoreWebviewInPort") + private readonly restoreWebviewInPort: RestoreWebviewInPort, + @inject("SyncDocumentInPort") + private readonly syncDocumentInPort: SyncDocumentInPort, + ) { + this.initWebview(webview, document); + this.onDidReceiveMessage(webview, document); + } + + private initWebview(webview: Webview, document: TextDocument) { + webview.options = { enableScripts: true }; + webview.html = getHtml(webview, EXTENSION_CONTEXT.getContext().extensionUri); + + const basePath = this.readVsCodeConfigInPort.readVsCodeConfig( + new ReadVsCodeConfigQuery("miranumIDE.configEditor.basePath"), + ); + this.files = this.readJsonFormInPort.readJsonForm( + new ReadJsonFormQuery(document.fileName, basePath), + ); + } + + private onDidReceiveMessage(webview: Webview, document: TextDocument) { + // Sync webview with a document + webview.onDidReceiveMessage(async (message: VscMessage) => { + if (updateFrom === UpdateFrom.DOCUMENT) { + setUpdateFrom(UpdateFrom.NULL); // reset + return; + } + setUpdateFrom(UpdateFrom.WEBVIEW); + + switch (message.type) { + case MessageType.initialize: { + if (!this.files) { + throw new Error("Files are not initialized"); + } + + const initWebviewCommand = new InitWebviewCommand( + document.fileName, + (await this.files.get("schema")) ?? "", + (await this.files.get("uischema")) ?? "", + document.getText() !== "" ? document.getText() : "{}", + ); + + await this.initWebviewInPort.initWebview(initWebviewCommand); + break; + } + case MessageType.restore: { + // TODO: + // Implement logic if user edited the JSON schema and uischema + // while the webview was in background. + const restoreWebviewCommand = new RestoreWebviewCommand( + document.fileName, + document.getText(), + ); + await this.restoreWebviewInPort.restore(restoreWebviewCommand); + break; + } + case MessageType.syncDocument: { + if (message.payload?.data) { + const syncDocumentCommand = new SyncDocumentCommand( + document.fileName, + JSON.stringify( + JSON.parse(message.payload.data), + undefined, + 2, + ), + ); + await this.syncDocumentInPort.sync(syncDocumentCommand); + } + break; + } + } + }); + } +} + +function getHtml(webview: Webview, extensionUri: Uri): string { + const baseUri = Uri.joinPath(extensionUri, "miranum-config-editor-webview"); + + const scriptUri = webview.asWebviewUri(Uri.joinPath(baseUri, "index.js")); + const styleUri = webview.asWebviewUri(Uri.joinPath(baseUri, "index.css")); + + const nonce = getNonce(); + + return ` + + + + + + + + + + + + + + Miranum Config Editor + + +
+ + + + `; +} + +function getNonce(): string { + let text = ""; + const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} + +/** + * @class DocumentAdapter + */ +@injectable() +export class DocumentAdapter { + constructor( + private readonly document: TextDocument, + @inject("SyncWebviewInPort") + private readonly syncWebviewInPort: SyncWebviewInPort, + ) { + this.onDidChangeTextDocument(); + } + + private onDidChangeTextDocument() { + // Sync document with webview + workspace.onDidChangeTextDocument(async (event) => { + if (event.contentChanges.length === 0) { + return; + } + if (updateFrom === UpdateFrom.WEBVIEW) { + setUpdateFrom(UpdateFrom.NULL); // reset + return; + } + setUpdateFrom(UpdateFrom.DOCUMENT); + + if (this.document.fileName === event.document.fileName) { + const syncWebviewCommand = new SyncWebviewCommand( + this.document.fileName, + event.document.getText(), + ); + + await this.syncWebviewInPort.sync(syncWebviewCommand); + } + }); + } +} diff --git a/apps/miranum-config-editor/src/adapter/adapterOut.ts b/apps/miranum-config-editor/src/adapter/adapterOut.ts new file mode 100644 index 00000000..481c0550 --- /dev/null +++ b/apps/miranum-config-editor/src/adapter/adapterOut.ts @@ -0,0 +1,130 @@ +/** + * @module Out-Adapter + * @description In the context of the "Hexagonal Architecture", Out-Adapters are objects that are called by our application. \ + * List of Adapters: + * - {@link WebviewAdapter} + * - {@link DocumentAdapter} + * - {@link ReaderAdapter} + * - {@link VsCodeConfigAdapter} + */ +import { Range, TextDocument, Uri, Webview, workspace, WorkspaceEdit } from "vscode"; +import { Buffer } from "node:buffer"; + +import { DocumentOutPort, ReaderOutPort, VsCodeConfigOutPort, WebviewOutPort } from "../application/portsOut"; +import { ConfigEditorData, VscMessage } from "@miranum-ide/vscode/shared/miranum-config-editor"; + +/** + * @class WebviewAdapter + */ +export class WebviewAdapter implements WebviewOutPort { + private activeWebview: WebviewWithId | undefined; + + async postMessage( + webviewId: string, + message: VscMessage, + ): Promise { + const webview = this.validate(webviewId); + return webview.postMessage(message); + } + + loadActiveWebviewId(): string { + if (!this.activeWebview) { + throw new Error("No active webview!"); + } + return this.activeWebview.id; + } + + updateActiveWebview(id: string, webview: Webview): boolean { + this.activeWebview = { + id, + webview, + }; + return true; + } + + private validate(webviewId: string): Webview { + if (!this.activeWebview) { + throw new Error("No active webview!"); + } + if (this.activeWebview.id !== webviewId) { + throw new Error("Invalid webview!"); + } + + return this.activeWebview.webview; + } +} + +interface WebviewWithId { + id: string; + webview: Webview; +} + +/** + * @class DocumentAdapter + */ +export class DocumentAdapter implements DocumentOutPort { + private activeDocument: TextDocument | undefined; + + async write(fileName: string, content: string): Promise { + const document = this.validate(fileName); + + if (document.getText() === content) { + throw new Error("No changes to apply!"); + } + + const edit = new WorkspaceEdit(); + + edit.replace(document.uri, new Range(0, 0, document.lineCount, 0), content); + + return workspace.applyEdit(edit); + } + + async save(fileName: string): Promise { + const document = this.validate(fileName); + return document.save(); + } + + loadActiveDocument(): string { + if (!this.activeDocument) { + throw new Error("No active document!"); + } + return this.activeDocument.fileName; + } + + updateActiveDocument(document: TextDocument): boolean { + this.activeDocument = document; + return true; + } + + private validate(fileName: string): TextDocument { + if (!this.activeDocument) { + throw new Error("No active document!"); + } + if (this.activeDocument.fileName !== fileName) { + throw new Error("Invalid document!"); + } + + return this.activeDocument; + } +} + +/** + * @class ReaderAdapter + */ +export class ReaderAdapter implements ReaderOutPort { + private readonly fs = workspace.fs; + + async readFile(fileName: string): Promise { + const uint8Array = await this.fs.readFile(Uri.file(fileName)); + return Buffer.from(uint8Array).toString(); + } +} + +/** + * @class VsCodeConfigAdapter + */ +export class VsCodeConfigAdapter implements VsCodeConfigOutPort { + getConfiguration(section: string): T | undefined { + return workspace.getConfiguration().get(section); + } +} diff --git a/apps/miranum-config-editor/src/application/model.ts b/apps/miranum-config-editor/src/application/model.ts new file mode 100644 index 00000000..e69de29b diff --git a/apps/miranum-config-editor/src/application/portsIn.ts b/apps/miranum-config-editor/src/application/portsIn.ts new file mode 100644 index 00000000..a86d512b --- /dev/null +++ b/apps/miranum-config-editor/src/application/portsIn.ts @@ -0,0 +1,168 @@ +/** + * @module In-Ports + * @description In-Ports are interfaces that are implemented by use cases. \ + * List of In-Ports: + * - {@link InitWebviewInPort} + * - {@link SyncWebviewInPort} + * - {@link SyncDocumentInPort} + * - {@link ReadVsCodeConfigInPort} + * - {@link ReadJsonFormInPort} + * - {@link RestoreWebviewInPort} + */ + +/** + * @interface InitWebviewInPort + * @description This interface is implemented by {@link InitWebviewUseCase}. + */ +export interface InitWebviewInPort { + initWebview(initWebviewCommand: InitWebviewCommand): Promise; +} + +export class InitWebviewCommand { + constructor( + private readonly _webviewId: string, + private readonly _jsonSchema: string, + private readonly _jsonUiSchema: string, + private readonly _content: string, + ) {} + + public get webviewId(): string { + return this._webviewId; + } + + public get jsonSchema(): string { + return this._jsonSchema; + } + + public get jsonUiSchema(): string { + return this._jsonUiSchema; + } + + public get content(): string { + return this._content; + } +} + +/** + * @interface SyncWebviewInPort + * @description This interface is implemented by {@link SyncWebviewUseCase}. + */ +export interface SyncWebviewInPort { + sync(syncWebviewCommand: SyncWebviewCommand): Promise; +} + +export class SyncWebviewCommand { + constructor( + private readonly _webviewId: string, + private readonly _content: string, + ) {} + + public get webviewId(): string { + return this._webviewId; + } + + public get content(): string { + return this._content; + } +} + +/** + * @interface SyncDocumentInPort + * @description This interface is implemented by {@link SyncDocumentUseCase}. + */ +export interface SyncDocumentInPort { + sync(syncDocumentQuery: SyncDocumentCommand): Promise; +} + +export class SyncDocumentCommand { + private readonly _content: string; + + constructor( + private readonly _fileName: string, + content: string, + ) { + if (!this.validate(content)) { + throw new Error("Invalid message"); + } + + this._content = content; + } + + public get content(): string { + if (!this._content) { + throw new Error("Content is undefined"); + } + return this._content; + } + + public get fileName(): string { + return this._fileName; + } + + private validate(content: string): boolean { + // TODO: Validate against JSON schema + return true; + } +} + +/** + * @interface ReadVsCodeConfigInPort + * @description This interface is implemented by {@link ReadVsCodeConfigUseCase}. + */ +export interface ReadVsCodeConfigInPort { + readVsCodeConfig(readVsCodeConfigQuery: ReadVsCodeConfigQuery): string; +} + +export class ReadVsCodeConfigQuery { + constructor(private readonly _key: string) {} + + public get key(): string { + return this._key; + } +} + +/** + * @interface ReadJsonFormInPort + * @description This interface is implemented by {@link ReadJsonFormUseCase}. + */ +export interface ReadJsonFormInPort { + readJsonForm(readJsonFormQuery: ReadJsonFormQuery): Map>; +} + +export class ReadJsonFormQuery { + constructor( + private readonly _fileName: string, + private readonly _basePath: string, + ) {} + + public get fileName(): string { + return this._fileName; + } + + public get basePath(): string { + return this._basePath; + } +} + +/** + * @interface RestoreWebviewInPort + * @description This interface is implemented by {@link RestoreWebviewUseCase}. + */ +export interface RestoreWebviewInPort { + restore(restoreWebviewCommand: RestoreWebviewCommand): Promise; +} + +export class RestoreWebviewCommand { + constructor( + private readonly _webviewId: string, + private readonly _content: string, + ) {} + + public get webviewId(): string { + return this._webviewId; + } + + public get content(): string { + return this._content; + } +} diff --git a/apps/miranum-config-editor/src/application/portsOut.ts b/apps/miranum-config-editor/src/application/portsOut.ts new file mode 100644 index 00000000..0a74d8e1 --- /dev/null +++ b/apps/miranum-config-editor/src/application/portsOut.ts @@ -0,0 +1,29 @@ +import { + ConfigEditorData, + VscMessage, +} from "@miranum-ide/vscode/shared/miranum-config-editor"; + +export interface WebviewOutPort { + postMessage( + webviewId: string, + message: VscMessage, + ): Promise; + + loadActiveWebviewId(): string; +} + +export interface DocumentOutPort { + write(fileName: string, content: string): Promise; + + save(fileName: string): Promise; + + loadActiveDocument(): string; +} + +export interface ReaderOutPort { + readFile(fileName: string): Promise; +} + +export interface VsCodeConfigOutPort { + getConfiguration(section: string): T | undefined; +} diff --git a/apps/miranum-config-editor/src/application/usecases.spec.ts b/apps/miranum-config-editor/src/application/usecases.spec.ts new file mode 100644 index 00000000..58947ed1 --- /dev/null +++ b/apps/miranum-config-editor/src/application/usecases.spec.ts @@ -0,0 +1,28 @@ +import "reflect-metadata"; +import { ReaderOutPort } from "./portsOut"; +import { ReadJsonFormQuery } from "./portsIn"; +import { ReadJsonFormUseCase } from "./usecases"; + +describe("Read Json Schema and UI Schema", () => { + const directory = new Map([ + ["my/base/path/to/schema.s3.config.json", "JSON Schema was read!"], + ["my/base/path/to/uischema.s3.config.json", "UI Schema was read!"], + ]); + const reader: ReaderOutPort = { + readFile(fileName: string): Promise { + return Promise.resolve(directory.get(fileName) ?? ""); + }, + }; + + it("should work", async () => { + const readJsonFormUseCase = new ReadJsonFormUseCase(reader); + const query = new ReadJsonFormQuery("schema.s3.config.json", "my/base/path/to"); + + const files = readJsonFormUseCase.readJsonForm(query); + const schema = await files.get("schema"); + const uiSchema = await files.get("uischema"); + + expect(schema).toBe("JSON Schema was read!"); + expect(uiSchema).toBe("UI Schema was read!"); + }); +}); diff --git a/apps/miranum-config-editor/src/application/usecases.ts b/apps/miranum-config-editor/src/application/usecases.ts new file mode 100644 index 00000000..0c9c9e88 --- /dev/null +++ b/apps/miranum-config-editor/src/application/usecases.ts @@ -0,0 +1,203 @@ +/** + * @module UseCases + * @description Here we implement our Business Logic. \ + * **There are no dependencies outside the application folder.** \ + * List of Use Cases: + * - {@link InitWebviewUseCase} + * - {@link SyncWebviewUseCase} + * - {@link SyncDocumentUseCase} + * - {@link ReadVsCodeConfigUseCase} + * - {@link ReadJsonFormUseCase} + * - {@link RestoreWebviewUseCase} + */ +import { inject, injectable } from "tsyringe"; + +import { + InitWebviewCommand, + InitWebviewInPort, + ReadJsonFormInPort, + ReadJsonFormQuery, + ReadVsCodeConfigInPort, + ReadVsCodeConfigQuery, + RestoreWebviewCommand, + RestoreWebviewInPort, + SyncDocumentCommand, + SyncDocumentInPort, + SyncWebviewCommand, + SyncWebviewInPort +} from "./portsIn"; +import { DocumentOutPort, ReaderOutPort, VsCodeConfigOutPort, WebviewOutPort } from "./portsOut"; +import { ConfigEditorData, MessageType, VscMessage } from "@miranum-ide/vscode/shared/miranum-config-editor"; + +/** + * @class InitWebviewUseCase + * @description This use case takes care of the initialization of the webview. + */ +@injectable() +export class InitWebviewUseCase implements InitWebviewInPort { + constructor( + @inject("WebviewOutPort") private readonly webviewOutPort: WebviewOutPort, + ) {} + + async initWebview(initWebviewCommand: InitWebviewCommand): Promise { + try { + const message: VscMessage = { + type: MessageType.initialize, + payload: { + schema: initWebviewCommand.jsonSchema, + uischema: initWebviewCommand.jsonUiSchema, + data: initWebviewCommand.content, + }, + }; + if ( + await this.webviewOutPort.postMessage( + initWebviewCommand.webviewId, + message, + ) + ) { + return true; + } + // e.g., add retry logic + return false; + } catch (error) { + console.error(error); + return false; + } + } +} + +/** + * @class SyncWebviewUseCase + * @description This use case takes care of the synchronization of the webview with the document. + */ +@injectable() +export class SyncWebviewUseCase implements SyncWebviewInPort { + constructor(@inject("WebviewOutPort") private webviewPort: WebviewOutPort) {} + + async sync(syncWebviewCommand: SyncWebviewCommand): Promise { + try { + const message: VscMessage = { + type: MessageType.syncWebview, + payload: { + data: syncWebviewCommand.content, + }, + }; + if ( + await this.webviewPort.postMessage(syncWebviewCommand.webviewId, message) + ) { + return true; + } + // e.g., add retry logic + return false; + } catch (error) { + console.error(error); + return false; + } + } +} + +/** + * @class SyncDocumentUseCase + * @description This use case takes care of the synchronization of the document with the webview. + */ +@injectable() +export class SyncDocumentUseCase implements SyncDocumentInPort { + constructor( + @inject("DocumentOutPort") private readonly documentOutPort: DocumentOutPort, + ) {} + + async sync(syncDocumentCommand: SyncDocumentCommand): Promise { + if ( + await this.documentOutPort.write( + syncDocumentCommand.fileName, + syncDocumentCommand.content, + ) + ) { + return true; + } + // Handle error + return false; + } +} + +/** + * @class ReadVsCodeConfigUseCase + * @description This use case takes care of reading the VSCode configuration. + */ +@injectable() +export class ReadVsCodeConfigUseCase implements ReadVsCodeConfigInPort { + constructor( + @inject("VsCodeConfigOutPort") + private readonly vsCodeConfigOutPort: VsCodeConfigOutPort, + ) {} + + readVsCodeConfig(readVsCodeConfigQuery: ReadVsCodeConfigQuery): string { + // TODO: What to do when basePath is undefined? + const basePath = this.vsCodeConfigOutPort.getConfiguration( + readVsCodeConfigQuery.key, + ); + + return basePath ?? ""; + } +} + +/** + * @class ReadJsonFormUseCase + * @description This use case takes care of reading the JSON Schema and UI-Schema. + */ +@injectable() +export class ReadJsonFormUseCase implements ReadJsonFormInPort { + constructor( + @inject("ReaderOutPort") private readonly readerOutPort: ReaderOutPort, + ) {} + + readJsonForm(readJsonFormQuery: ReadJsonFormQuery): Map> { + const fileName = readJsonFormQuery.fileName; + const basePath = readJsonFormQuery.basePath; + + const extension = fileName.substring(fileName.indexOf("."), fileName.length); + + const schema = this.readerOutPort.readFile(`${basePath}/schema${extension}`); + const uischema = this.readerOutPort.readFile(`${basePath}/uischema${extension}`); + + return new Map([ + ["schema", schema], + ["uischema", uischema], + ]); + } +} + +/** + * @class RestoreWebviewUseCase + * @description This use case takes care of restoring the webview. + */ +@injectable() +export class RestoreWebviewUseCase implements RestoreWebviewInPort { + constructor( + @inject("WebviewOutPort") private readonly webviewOutPort: WebviewOutPort, + ) {} + + async restore(restoreWebviewCommand: RestoreWebviewCommand): Promise { + try { + const message: VscMessage = { + type: MessageType.restore, + payload: { + data: restoreWebviewCommand.content, + }, + }; + if ( + await this.webviewOutPort.postMessage( + restoreWebviewCommand.webviewId, + message, + ) + ) { + return true; + } + // e.g., add retry logic + return false; + } catch (error) { + console.error(error); + return false; + } + } +} diff --git a/apps/miranum-config-editor/src/common.ts b/apps/miranum-config-editor/src/common.ts new file mode 100644 index 00000000..26b280ea --- /dev/null +++ b/apps/miranum-config-editor/src/common.ts @@ -0,0 +1,39 @@ +import { ExtensionContext } from "vscode"; + +export enum UpdateFrom { + NULL = "", + WEBVIEW = "webview", + DOCUMENT = "document", +} + +export let updateFrom: UpdateFrom; + +export function setUpdateFrom(uf: UpdateFrom): void { + updateFrom = uf; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export class EXTENSION_CONTEXT { + private static instance: EXTENSION_CONTEXT; + + private static context: ExtensionContext; + + private constructor(context: ExtensionContext) { + EXTENSION_CONTEXT.context = context; + } + + public static setContext(context: ExtensionContext): EXTENSION_CONTEXT { + if (this.instance) { + throw new Error("ExtensionUri is already set"); + } + this.instance = new EXTENSION_CONTEXT(context); + return this.instance; + } + + public static getContext(): ExtensionContext { + if (!this.instance) { + throw new Error("ExtensionUri is not set"); + } + return EXTENSION_CONTEXT.context; + } +} diff --git a/apps/miranum-config-editor/src/main.config.ts b/apps/miranum-config-editor/src/main.config.ts new file mode 100644 index 00000000..5508fc61 --- /dev/null +++ b/apps/miranum-config-editor/src/main.config.ts @@ -0,0 +1,82 @@ +import { container, Lifecycle } from "tsyringe"; + +import { + InitWebviewUseCase, + ReadJsonFormUseCase, + ReadVsCodeConfigUseCase, + RestoreWebviewUseCase, + SyncDocumentUseCase, + SyncWebviewUseCase, +} from "./application/usecases"; +import { + DocumentAdapter, + ReaderAdapter, + VsCodeConfigAdapter, + WebviewAdapter, +} from "./adapter/adapterOut"; + +export async function config(): Promise { + try { + await Promise.all([registerUseCases(), registerOutAdapter()]); + return true; + } catch (error) { + console.error(error); + return false; + } +} + +async function registerUseCases() { + container.register( + "ReadVsCodeConfigInPort", + { useClass: ReadVsCodeConfigUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "ReadJsonFormInPort", + { useClass: ReadJsonFormUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "InitWebviewInPort", + { useClass: InitWebviewUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "RestoreWebviewInPort", + { useClass: RestoreWebviewUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "SyncWebviewInPort", + { useClass: SyncWebviewUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "SyncDocumentInPort", + { useClass: SyncDocumentUseCase }, + { lifecycle: Lifecycle.Singleton }, + ); +} + +async function registerOutAdapter() { + container.register( + "WebviewOutPort", + { useClass: WebviewAdapter }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "DocumentOutPort", + { useClass: DocumentAdapter }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "ReaderOutPort", + { useClass: ReaderAdapter }, + { lifecycle: Lifecycle.Singleton }, + ); + container.register( + "VsCodeConfigOutPort", + { useClass: VsCodeConfigAdapter }, + { lifecycle: Lifecycle.Singleton }, + ); +} diff --git a/apps/miranum-config-editor/src/main.ts b/apps/miranum-config-editor/src/main.ts new file mode 100644 index 00000000..bccf8212 --- /dev/null +++ b/apps/miranum-config-editor/src/main.ts @@ -0,0 +1,77 @@ +import "reflect-metadata"; +import { + CancellationToken, + CustomTextEditorProvider, + ExtensionContext, + TextDocument, + WebviewPanel, + window, +} from "vscode"; +import { container } from "tsyringe"; + +import { + DocumentAdapter as InDocumentAdapter, + WebviewAdapter as InWebviewAdapter, +} from "./adapter/adapterIn"; +import { + DocumentAdapter as OutDocumentAdapter, + WebviewAdapter as OutWebviewAdapter, +} from "./adapter/adapterOut"; + +import { config } from "./main.config"; +import { EXTENSION_CONTEXT } from "./common"; + +export async function activate(context: ExtensionContext) { + await config(); + + EXTENSION_CONTEXT.setContext(context); + + // CustomTextEditor + const editor = window.registerCustomEditorProvider( + "miranum.configEditor", + new CustomTextEditor(), + ); + + EXTENSION_CONTEXT.getContext().subscriptions.push(editor); +} + +class CustomTextEditor implements CustomTextEditorProvider { + async resolveCustomTextEditor( + document: TextDocument, + webviewPanel: WebviewPanel, + token: CancellationToken, + ): Promise { + this.initialSetup(webviewPanel, document); + + new InWebviewAdapter( + webviewPanel.webview, + document, + container.resolve("ReadVsCodeConfigInPort"), + container.resolve("ReadJsonFormInPort"), + container.resolve("InitWebviewInPort"), + container.resolve("RestoreWebviewInPort"), + container.resolve("SyncDocumentInPort"), + ); + + new InDocumentAdapter(document, container.resolve("SyncWebviewInPort")); + } + + private initialSetup(webviewPanel: WebviewPanel, document: TextDocument) { + const webviewOutAdapter = container.resolve("WebviewOutPort"); + const documentOutAdapter = + container.resolve("DocumentOutPort"); + + webviewOutAdapter.updateActiveWebview(document.fileName, webviewPanel.webview); + documentOutAdapter.updateActiveDocument(document); + + webviewPanel.onDidChangeViewState((event) => { + if (event.webviewPanel.active) { + webviewOutAdapter.updateActiveWebview( + document.fileName, + webviewPanel.webview, + ); + documentOutAdapter.updateActiveDocument(document); + } + }); + } +} diff --git a/apps/miranum-config-editor/tsconfig.app.json b/apps/miranum-config-editor/tsconfig.app.json new file mode 100644 index 00000000..f5e2e085 --- /dev/null +++ b/apps/miranum-config-editor/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["node"] + }, + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/apps/miranum-config-editor/tsconfig.json b/apps/miranum-config-editor/tsconfig.json new file mode 100644 index 00000000..c1e2dd4e --- /dev/null +++ b/apps/miranum-config-editor/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/apps/miranum-config-editor/tsconfig.spec.json b/apps/miranum-config-editor/tsconfig.spec.json new file mode 100644 index 00000000..9b2a121d --- /dev/null +++ b/apps/miranum-config-editor/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/miranum-config-editor/webpack.config.js b/apps/miranum-config-editor/webpack.config.js new file mode 100644 index 00000000..32cc85ae --- /dev/null +++ b/apps/miranum-config-editor/webpack.config.js @@ -0,0 +1,13 @@ +// Helper for combining webpack config objects +const { merge } = require("webpack-merge"); +const { composePlugins, withNx } = require("@nx/webpack"); + +module.exports = (config, context) => { + return merge(config, { + // overwrite values here + externals: { + vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ + // modules added here also need to be added in the .vscodeignore file + }, + }); +}; diff --git a/apps/miranum-extension-pack/CHANGELOG.md b/apps/miranum-extension-pack/CHANGELOG.md index 39562f44..486f3fc7 100644 --- a/apps/miranum-extension-pack/CHANGELOG.md +++ b/apps/miranum-extension-pack/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +* **\[Miranum Config Editor\]** Add new plugin for editing config files (#412) + ### Changed * Update dependencies and migrate to Nx Version 17 (#418) diff --git a/apps/miranum-extension-pack/package.json b/apps/miranum-extension-pack/package.json index 5ae6c7e2..7d20ec2c 100644 --- a/apps/miranum-extension-pack/package.json +++ b/apps/miranum-extension-pack/package.json @@ -34,6 +34,7 @@ }, "icon": "miranum_logo.png", "extensionPack": [ + "miragon-gmbh.miranum-config-editor", "miragon-gmbh.miranum-console", "miragon-gmbh.miranum-json-forms", "miragon-gmbh.miranum-vs-code-forms", @@ -45,8 +46,8 @@ "BPMN", "DMN", "Camunda", - "JSON", "JSON Schema", + "JSON Forms", "Forms", "Formbuilder" ], diff --git a/apps/miranum-bpmn-modeler-webview/.babelrc b/apps/miranum-modeler-bpmn-webview/.babelrc similarity index 100% rename from apps/miranum-bpmn-modeler-webview/.babelrc rename to apps/miranum-modeler-bpmn-webview/.babelrc diff --git a/apps/miranum-bpmn-modeler-webview/.eslintrc.json b/apps/miranum-modeler-bpmn-webview/.eslintrc.json similarity index 51% rename from apps/miranum-bpmn-modeler-webview/.eslintrc.json rename to apps/miranum-modeler-bpmn-webview/.eslintrc.json index 165ad82d..2e51bcc9 100644 --- a/apps/miranum-bpmn-modeler-webview/.eslintrc.json +++ b/apps/miranum-modeler-bpmn-webview/.eslintrc.json @@ -1,13 +1,25 @@ { - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], + "extends": [ + "../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], "overrides": [ { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], "rules": {} }, { - "files": ["*.ts", "*.tsx"], + "files": [ + "*.ts", + "*.tsx" + ], "rules": { "@typescript-eslint/no-explicit-any": "warn", "no-fallthrough": [ @@ -19,7 +31,10 @@ } }, { - "files": ["*.js", "*.jsx"], + "files": [ + "*.js", + "*.jsx" + ], "rules": {} } ] diff --git a/apps/miranum-bpmn-modeler-webview/index.html b/apps/miranum-modeler-bpmn-webview/index.html similarity index 100% rename from apps/miranum-bpmn-modeler-webview/index.html rename to apps/miranum-modeler-bpmn-webview/index.html diff --git a/apps/miranum-bpmn-modeler-webview/jest.config.ts b/apps/miranum-modeler-bpmn-webview/jest.config.ts similarity index 68% rename from apps/miranum-bpmn-modeler-webview/jest.config.ts rename to apps/miranum-modeler-bpmn-webview/jest.config.ts index a6503879..2d0977c1 100644 --- a/apps/miranum-bpmn-modeler-webview/jest.config.ts +++ b/apps/miranum-modeler-bpmn-webview/jest.config.ts @@ -1,5 +1,5 @@ module.exports = { - displayName: "miranum-bpmn-modeler-webview", + displayName: "miranum-modeler-bpmn-webview", preset: "../../jest.preset.js", transform: { "^.+.vue$": "@vue/vue2-jest", @@ -8,16 +8,16 @@ module.exports = { "^.+.tsx?$": [ "ts-jest", { - tsconfig: "apps/miranum-bpmn-modeler-webview/tsconfig.spec.json", + tsconfig: "apps/miranum-modeler-bpmn-webview/tsconfig.spec.json", }, ], }, moduleFileExtensions: ["ts", "tsx", "vue", "js", "json"], - coverageDirectory: "../../coverage/apps/miranum-bpmn-modeler-webview", + coverageDirectory: "../../coverage/apps/miranum-modeler-bpmn-webview", snapshotSerializers: ["jest-serializer-vue"], globals: { "vue-jest": { - tsConfig: "apps/miranum-bpmn-modeler-webview/tsconfig.spec.json", + tsConfig: "apps/miranum-modeler-bpmn-webview/tsconfig.spec.json", }, }, }; diff --git a/apps/miranum-bpmn-modeler-webview/project.json b/apps/miranum-modeler-bpmn-webview/project.json similarity index 72% rename from apps/miranum-bpmn-modeler-webview/project.json rename to apps/miranum-modeler-bpmn-webview/project.json index 6c830f5b..cace90d0 100644 --- a/apps/miranum-bpmn-modeler-webview/project.json +++ b/apps/miranum-modeler-bpmn-webview/project.json @@ -1,8 +1,8 @@ { - "name": "miranum-bpmn-modeler-webview", + "name": "miranum-modeler-bpmn-webview", "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", - "sourceRoot": "apps/miranum-bpmn-modeler-webview/src", + "sourceRoot": "apps/miranum-modeler-bpmn-webview/src", "tags": [], "targets": { "observe": { @@ -13,8 +13,8 @@ "defaultConfiguration": "development", "options": { "watch": true, - "outputPath": "dist/apps/miranum-modeler/miranum-bpmn-modeler-webview", - "configFile": "apps/miranum-bpmn-modeler-webview/vite.config.ts", + "outputPath": "dist/apps/miranum-modeler/miranum-modeler-bpmn-webview", + "configFile": "apps/miranum-modeler-bpmn-webview/vite.config.ts", "emptyOutDir": false }, "configurations": { @@ -33,8 +33,8 @@ ], "defaultConfiguration": "production", "options": { - "outputPath": "dist/apps/miranum-modeler/miranum-bpmn-modeler-webview", - "configFile": "apps/miranum-bpmn-modeler-webview/vite.config.ts" + "outputPath": "dist/apps/miranum-modeler/miranum-modeler-bpmn-webview", + "configFile": "apps/miranum-modeler-bpmn-webview/vite.config.ts" }, "configurations": { "development": { @@ -51,7 +51,7 @@ "{workspaceRoot}/coverage/{projectRoot}" ], "options": { - "jestConfig": "apps/miranum-bpmn-modeler-webview/jest.config.ts", + "jestConfig": "apps/miranum-modeler-bpmn-webview/jest.config.ts", "passWithNoTests": true } }, @@ -62,7 +62,7 @@ ], "options": { "lintFilePatterns": [ - "apps/miranum-bpmn-modeler-webview/**/*.ts" + "apps/miranum-modeler-bpmn-webview/**/*.ts" ] } }, @@ -70,7 +70,7 @@ "executor": "@nx/vite:dev-server", "defaultConfiguration": "development", "options": { - "buildTarget": "miranum-bpmn-modeler-webview:build" + "buildTarget": "miranum-modeler-bpmn-webview:build" } } } diff --git a/apps/miranum-bpmn-modeler-webview/public/favicon.ico b/apps/miranum-modeler-bpmn-webview/public/favicon.ico similarity index 100% rename from apps/miranum-bpmn-modeler-webview/public/favicon.ico rename to apps/miranum-modeler-bpmn-webview/public/favicon.ico diff --git a/apps/miranum-bpmn-modeler-webview/src/app/ContentController.ts b/apps/miranum-modeler-bpmn-webview/src/app/ContentController.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/ContentController.ts rename to apps/miranum-modeler-bpmn-webview/src/app/ContentController.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/descriptors/.gitkeep b/apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/descriptors/.gitkeep similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/descriptors/.gitkeep rename to apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/descriptors/.gitkeep diff --git a/apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/MiragonProvider.ts b/apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/MiragonProvider.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/MiragonProvider.ts rename to apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/MiragonProvider.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/index.ts b/apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/index.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/index.ts rename to apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/index.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/parts/FormStartProp.ts b/apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/parts/FormStartProp.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/parts/FormStartProp.ts rename to apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/parts/FormStartProp.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/parts/FormUserProp.ts b/apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/parts/FormUserProp.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/PropertieProvider/provider/parts/FormUserProp.ts rename to apps/miranum-modeler-bpmn-webview/src/app/PropertieProvider/provider/parts/FormUserProp.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/TemplateElementFactory.ts b/apps/miranum-modeler-bpmn-webview/src/app/TemplateElementFactory.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/TemplateElementFactory.ts rename to apps/miranum-modeler-bpmn-webview/src/app/TemplateElementFactory.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/formKeys.ts b/apps/miranum-modeler-bpmn-webview/src/app/formKeys.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/formKeys.ts rename to apps/miranum-modeler-bpmn-webview/src/app/formKeys.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/index.ts b/apps/miranum-modeler-bpmn-webview/src/app/index.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/index.ts rename to apps/miranum-modeler-bpmn-webview/src/app/index.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/app/utils.ts b/apps/miranum-modeler-bpmn-webview/src/app/utils.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/app/utils.ts rename to apps/miranum-modeler-bpmn-webview/src/app/utils.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/main.ts b/apps/miranum-modeler-bpmn-webview/src/main.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/main.ts rename to apps/miranum-modeler-bpmn-webview/src/main.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/styles.css b/apps/miranum-modeler-bpmn-webview/src/styles.css similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/styles.css rename to apps/miranum-modeler-bpmn-webview/src/styles.css diff --git a/apps/miranum-bpmn-modeler-webview/src/types/bpmn-js.d.ts b/apps/miranum-modeler-bpmn-webview/src/types/bpmn-js.d.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/types/bpmn-js.d.ts rename to apps/miranum-modeler-bpmn-webview/src/types/bpmn-js.d.ts diff --git a/apps/miranum-bpmn-modeler-webview/src/types/diagram-js.d.ts b/apps/miranum-modeler-bpmn-webview/src/types/diagram-js.d.ts similarity index 100% rename from apps/miranum-bpmn-modeler-webview/src/types/diagram-js.d.ts rename to apps/miranum-modeler-bpmn-webview/src/types/diagram-js.d.ts diff --git a/apps/miranum-bpmn-modeler-webview/tsconfig.app.json b/apps/miranum-modeler-bpmn-webview/tsconfig.app.json similarity index 100% rename from apps/miranum-bpmn-modeler-webview/tsconfig.app.json rename to apps/miranum-modeler-bpmn-webview/tsconfig.app.json diff --git a/apps/miranum-bpmn-modeler-webview/tsconfig.json b/apps/miranum-modeler-bpmn-webview/tsconfig.json similarity index 100% rename from apps/miranum-bpmn-modeler-webview/tsconfig.json rename to apps/miranum-modeler-bpmn-webview/tsconfig.json diff --git a/apps/miranum-bpmn-modeler-webview/tsconfig.spec.json b/apps/miranum-modeler-bpmn-webview/tsconfig.spec.json similarity index 100% rename from apps/miranum-bpmn-modeler-webview/tsconfig.spec.json rename to apps/miranum-modeler-bpmn-webview/tsconfig.spec.json diff --git a/apps/miranum-bpmn-modeler-webview/uml/Camunda7ElementTemplate.puml b/apps/miranum-modeler-bpmn-webview/uml/Camunda7ElementTemplate.puml similarity index 100% rename from apps/miranum-bpmn-modeler-webview/uml/Camunda7ElementTemplate.puml rename to apps/miranum-modeler-bpmn-webview/uml/Camunda7ElementTemplate.puml diff --git a/apps/miranum-bpmn-modeler-webview/uml/changeDiagram.bpmn b/apps/miranum-modeler-bpmn-webview/uml/changeDiagram.bpmn similarity index 100% rename from apps/miranum-bpmn-modeler-webview/uml/changeDiagram.bpmn rename to apps/miranum-modeler-bpmn-webview/uml/changeDiagram.bpmn diff --git a/apps/miranum-bpmn-modeler-webview/uml/openWebview.bpmn b/apps/miranum-modeler-bpmn-webview/uml/openWebview.bpmn similarity index 100% rename from apps/miranum-bpmn-modeler-webview/uml/openWebview.bpmn rename to apps/miranum-modeler-bpmn-webview/uml/openWebview.bpmn diff --git a/apps/miranum-bpmn-modeler-webview/uml/webview.puml b/apps/miranum-modeler-bpmn-webview/uml/webview.puml similarity index 100% rename from apps/miranum-bpmn-modeler-webview/uml/webview.puml rename to apps/miranum-modeler-bpmn-webview/uml/webview.puml diff --git a/apps/miranum-bpmn-modeler-webview/vite.config.ts b/apps/miranum-modeler-bpmn-webview/vite.config.ts similarity index 96% rename from apps/miranum-bpmn-modeler-webview/vite.config.ts rename to apps/miranum-modeler-bpmn-webview/vite.config.ts index 32787090..a6019a6d 100644 --- a/apps/miranum-bpmn-modeler-webview/vite.config.ts +++ b/apps/miranum-modeler-bpmn-webview/vite.config.ts @@ -5,7 +5,7 @@ import { viteStaticCopy } from "vite-plugin-static-copy"; import path from "path"; export default defineConfig({ - cacheDir: "../../node_modules/.vite/miranum-bpmn-modeler-webview", + cacheDir: "../../node_modules/.vite/miranum-modeler-bpmn-webview", resolve: { alias: [ diff --git a/apps/miranum-dmn-modeler-webview/.babelrc b/apps/miranum-modeler-dmn-webview/.babelrc similarity index 100% rename from apps/miranum-dmn-modeler-webview/.babelrc rename to apps/miranum-modeler-dmn-webview/.babelrc diff --git a/apps/miranum-dmn-modeler-webview/.eslintrc.json b/apps/miranum-modeler-dmn-webview/.eslintrc.json similarity index 51% rename from apps/miranum-dmn-modeler-webview/.eslintrc.json rename to apps/miranum-modeler-dmn-webview/.eslintrc.json index 165ad82d..2e51bcc9 100644 --- a/apps/miranum-dmn-modeler-webview/.eslintrc.json +++ b/apps/miranum-modeler-dmn-webview/.eslintrc.json @@ -1,13 +1,25 @@ { - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], + "extends": [ + "../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], "overrides": [ { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], "rules": {} }, { - "files": ["*.ts", "*.tsx"], + "files": [ + "*.ts", + "*.tsx" + ], "rules": { "@typescript-eslint/no-explicit-any": "warn", "no-fallthrough": [ @@ -19,7 +31,10 @@ } }, { - "files": ["*.js", "*.jsx"], + "files": [ + "*.js", + "*.jsx" + ], "rules": {} } ] diff --git a/apps/miranum-dmn-modeler-webview/index.html b/apps/miranum-modeler-dmn-webview/index.html similarity index 100% rename from apps/miranum-dmn-modeler-webview/index.html rename to apps/miranum-modeler-dmn-webview/index.html diff --git a/apps/miranum-dmn-modeler-webview/jest.config.ts b/apps/miranum-modeler-dmn-webview/jest.config.ts similarity index 68% rename from apps/miranum-dmn-modeler-webview/jest.config.ts rename to apps/miranum-modeler-dmn-webview/jest.config.ts index ad5685ce..3f8ea9ab 100644 --- a/apps/miranum-dmn-modeler-webview/jest.config.ts +++ b/apps/miranum-modeler-dmn-webview/jest.config.ts @@ -1,5 +1,5 @@ module.exports = { - displayName: "miranum-dmn-modeler-webview", + displayName: "miranum-modeler-dmn-webview", preset: "../../jest.preset.js", transform: { "^.+.vue$": "@vue/vue2-jest", @@ -8,16 +8,16 @@ module.exports = { "^.+.tsx?$": [ "ts-jest", { - tsconfig: "apps/miranum-dmn-modeler-webview/tsconfig.spec.json", + tsconfig: "apps/miranum-modeler-dmn-webview/tsconfig.spec.json", }, ], }, moduleFileExtensions: ["ts", "tsx", "vue", "js", "json"], - coverageDirectory: "../../coverage/apps/miranum-dmn-modeler-webview", + coverageDirectory: "../../coverage/apps/miranum-modeler-dmn-webview", snapshotSerializers: ["jest-serializer-vue"], globals: { "vue-jest": { - tsConfig: "apps/miranum-dmn-modeler-webview/tsconfig.spec.json", + tsConfig: "apps/miranum-modeler-dmn-webview/tsconfig.spec.json", }, }, }; diff --git a/apps/miranum-dmn-modeler-webview/project.json b/apps/miranum-modeler-dmn-webview/project.json similarity index 71% rename from apps/miranum-dmn-modeler-webview/project.json rename to apps/miranum-modeler-dmn-webview/project.json index f28e1d6e..9436d572 100644 --- a/apps/miranum-dmn-modeler-webview/project.json +++ b/apps/miranum-modeler-dmn-webview/project.json @@ -1,8 +1,8 @@ { - "name": "miranum-dmn-modeler-webview", + "name": "miranum-modeler-dmn-webview", "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", - "sourceRoot": "apps/miranum-dmn-modeler-webview/src", + "sourceRoot": "apps/miranum-modeler-dmn-webview/src", "tags": [], "targets": { "observe": { @@ -13,8 +13,8 @@ "defaultConfiguration": "development", "options": { "watch": true, - "outputPath": "dist/apps/miranum-modeler/miranum-dmn-modeler-webview", - "configFile": "apps/miranum-dmn-modeler-webview/vite.config.ts", + "outputPath": "dist/apps/miranum-modeler/miranum-modeler-dmn-webview", + "configFile": "apps/miranum-modeler-dmn-webview/vite.config.ts", "emptyOutDir": false }, "configurations": { @@ -33,8 +33,8 @@ ], "defaultConfiguration": "production", "options": { - "outputPath": "dist/apps/miranum-modeler/miranum-dmn-modeler-webview", - "configFile": "apps/miranum-dmn-modeler-webview/vite.config.ts" + "outputPath": "dist/apps/miranum-modeler/miranum-modeler-dmn-webview", + "configFile": "apps/miranum-modeler-dmn-webview/vite.config.ts" }, "configurations": { "production": { @@ -48,7 +48,7 @@ "{workspaceRoot}/coverage/{projectRoot}" ], "options": { - "jestConfig": "apps/miranum-dmn-modeler-webview/jest.config.ts", + "jestConfig": "apps/miranum-modeler-dmn-webview/jest.config.ts", "passWithNoTests": true } }, @@ -59,7 +59,7 @@ ], "options": { "lintFilePatterns": [ - "apps/miranum-dmn-modeler-webview/**/*.ts" + "apps/miranum-modeler-dmn-webview/**/*.ts" ] } } diff --git a/apps/miranum-dmn-modeler-webview/public/empty.dmn b/apps/miranum-modeler-dmn-webview/public/empty.dmn similarity index 100% rename from apps/miranum-dmn-modeler-webview/public/empty.dmn rename to apps/miranum-modeler-dmn-webview/public/empty.dmn diff --git a/apps/miranum-modeler-dmn-webview/public/favicon.ico b/apps/miranum-modeler-dmn-webview/public/favicon.ico new file mode 100644 index 00000000..317ebcb2 Binary files /dev/null and b/apps/miranum-modeler-dmn-webview/public/favicon.ico differ diff --git a/apps/miranum-dmn-modeler-webview/src/app/ContentController.ts b/apps/miranum-modeler-dmn-webview/src/app/ContentController.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/app/ContentController.ts rename to apps/miranum-modeler-dmn-webview/src/app/ContentController.ts diff --git a/apps/miranum-dmn-modeler-webview/src/app/index.ts b/apps/miranum-modeler-dmn-webview/src/app/index.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/app/index.ts rename to apps/miranum-modeler-dmn-webview/src/app/index.ts diff --git a/apps/miranum-dmn-modeler-webview/src/app/utils.ts b/apps/miranum-modeler-dmn-webview/src/app/utils.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/app/utils.ts rename to apps/miranum-modeler-dmn-webview/src/app/utils.ts diff --git a/apps/miranum-dmn-modeler-webview/src/main.ts b/apps/miranum-modeler-dmn-webview/src/main.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/main.ts rename to apps/miranum-modeler-dmn-webview/src/main.ts diff --git a/apps/miranum-dmn-modeler-webview/src/styles.css b/apps/miranum-modeler-dmn-webview/src/styles.css similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/styles.css rename to apps/miranum-modeler-dmn-webview/src/styles.css diff --git a/apps/miranum-dmn-modeler-webview/src/types/diagram-js.d.ts b/apps/miranum-modeler-dmn-webview/src/types/diagram-js.d.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/types/diagram-js.d.ts rename to apps/miranum-modeler-dmn-webview/src/types/diagram-js.d.ts diff --git a/apps/miranum-dmn-modeler-webview/src/types/dmn-js.d.ts b/apps/miranum-modeler-dmn-webview/src/types/dmn-js.d.ts similarity index 100% rename from apps/miranum-dmn-modeler-webview/src/types/dmn-js.d.ts rename to apps/miranum-modeler-dmn-webview/src/types/dmn-js.d.ts diff --git a/apps/miranum-dmn-modeler-webview/tsconfig.app.json b/apps/miranum-modeler-dmn-webview/tsconfig.app.json similarity index 100% rename from apps/miranum-dmn-modeler-webview/tsconfig.app.json rename to apps/miranum-modeler-dmn-webview/tsconfig.app.json diff --git a/apps/miranum-dmn-modeler-webview/tsconfig.json b/apps/miranum-modeler-dmn-webview/tsconfig.json similarity index 100% rename from apps/miranum-dmn-modeler-webview/tsconfig.json rename to apps/miranum-modeler-dmn-webview/tsconfig.json diff --git a/apps/miranum-dmn-modeler-webview/tsconfig.spec.json b/apps/miranum-modeler-dmn-webview/tsconfig.spec.json similarity index 100% rename from apps/miranum-dmn-modeler-webview/tsconfig.spec.json rename to apps/miranum-modeler-dmn-webview/tsconfig.spec.json diff --git a/apps/miranum-dmn-modeler-webview/uml/changeDiagram.bpmn b/apps/miranum-modeler-dmn-webview/uml/changeDiagram.bpmn similarity index 100% rename from apps/miranum-dmn-modeler-webview/uml/changeDiagram.bpmn rename to apps/miranum-modeler-dmn-webview/uml/changeDiagram.bpmn diff --git a/apps/miranum-dmn-modeler-webview/uml/openWebview.bpmn b/apps/miranum-modeler-dmn-webview/uml/openWebview.bpmn similarity index 100% rename from apps/miranum-dmn-modeler-webview/uml/openWebview.bpmn rename to apps/miranum-modeler-dmn-webview/uml/openWebview.bpmn diff --git a/apps/miranum-dmn-modeler-webview/uml/webview.puml b/apps/miranum-modeler-dmn-webview/uml/webview.puml similarity index 100% rename from apps/miranum-dmn-modeler-webview/uml/webview.puml rename to apps/miranum-modeler-dmn-webview/uml/webview.puml diff --git a/apps/miranum-dmn-modeler-webview/vite.config.ts b/apps/miranum-modeler-dmn-webview/vite.config.ts similarity index 96% rename from apps/miranum-dmn-modeler-webview/vite.config.ts rename to apps/miranum-modeler-dmn-webview/vite.config.ts index 3e7ac78d..8bced653 100644 --- a/apps/miranum-dmn-modeler-webview/vite.config.ts +++ b/apps/miranum-modeler-dmn-webview/vite.config.ts @@ -4,7 +4,7 @@ import { viteStaticCopy } from "vite-plugin-static-copy"; import path from "path"; export default defineConfig({ - cacheDir: "../../node_modules/.vite/miranum-dmn-modeler-webview", + cacheDir: "../../node_modules/.vite/miranum-modeler-dmn-webview", resolve: { alias: [ diff --git a/apps/miranum-modeler/project.json b/apps/miranum-modeler/project.json index dc7953f9..4dcc3030 100644 --- a/apps/miranum-modeler/project.json +++ b/apps/miranum-modeler/project.json @@ -4,8 +4,8 @@ "sourceRoot": "apps/miranum-modeler/src", "projectType": "application", "implicitDependencies": [ - "miranum-bpmn-modeler-webview", - "miranum-dmn-modeler-webview" + "miranum-modeler-bpmn-webview", + "miranum-modeler-dmn-webview" ], "targets": { "observe-all": { @@ -19,13 +19,13 @@ "color": "blue" }, { - "command": "npx nx observe miranum-bpmn-modeler-webview", - "prefix": "miranum-bpmn-modeler-webview", + "command": "npx nx observe miranum-modeler-bpmn-webview", + "prefix": "miranum-modeler-bpmn-webview", "color": "green" }, { - "command": "npx nx observe miranum-dmn-modeler-webview", - "prefix": "miranum-dmn-modeler-webview", + "command": "npx nx observe miranum-modeler-dmn-webview", + "prefix": "miranum-modeler-dmn-webview", "color": "yellow" } ] diff --git a/apps/miranum-modeler/src/app/BpmnModeler.ts b/apps/miranum-modeler/src/app/BpmnModeler.ts index a9f75e19..e0faf986 100644 --- a/apps/miranum-modeler/src/app/BpmnModeler.ts +++ b/apps/miranum-modeler/src/app/BpmnModeler.ts @@ -370,7 +370,7 @@ export class BpmnModeler implements CustomTextEditorProvider { * @private */ private getHtmlForWebview(webview: Webview, extensionUri: Uri) { - const pathToWebview = Uri.joinPath(extensionUri, "miranum-bpmn-modeler-webview"); + const pathToWebview = Uri.joinPath(extensionUri, "miranum-modeler-bpmn-webview"); const scriptUri = webview.asWebviewUri(Uri.joinPath(pathToWebview, "index.js")); const styleUri = webview.asWebviewUri(Uri.joinPath(pathToWebview, "index.css")); diff --git a/apps/miranum-modeler/src/app/DmnModeler.ts b/apps/miranum-modeler/src/app/DmnModeler.ts index db22c213..cb7f7767 100644 --- a/apps/miranum-modeler/src/app/DmnModeler.ts +++ b/apps/miranum-modeler/src/app/DmnModeler.ts @@ -290,7 +290,7 @@ export class DmnModeler implements vscode.CustomTextEditorProvider { private getHtmlForWebview(webview: vscode.Webview, extensionUri: vscode.Uri) { const pathToWebview = vscode.Uri.joinPath( extensionUri, - "miranum-dmn-modeler-webview", + "miranum-modeler-dmn-webview", ); const scriptUri = webview.asWebviewUri( diff --git a/docs/development.md b/docs/development.md index 7cc0f889..c3c249bc 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,7 +1,7 @@ # Development * [Setup local dev environment](#setup-local-dev-environment) - * [Miranum Deployment Proxy](#miranum-deployment-proxy) + * [Miranum Deployment Proxy](#miranum-deployment) * [Miranum CLI](#miranum-cli) * [Miranum VS Code Extension](#miranum-vs-code-extensions) * [Testing](#testing) @@ -64,11 +64,11 @@ npx nx create miranum-cli ### Miranum VS Code Extensions We provide several VS Code Extensions. You can find them under the [apps](../apps) folder. -In most cases our extensions need a so called [webview](https://code.visualstudio.com/api/extension-guides/webview). +In most cases, our extensions need a so-called [webview](https://code.visualstudio.com/api/extension-guides/webview). The source code of the webview is maintained separately. This means that `miranum-` and `miranum--webview` form one VS Code Extension. -In order to start a extension in development mode locally, you have to build the extension and webview. +To start an extension in development mode locally, you have to build the extension and webview. Therefore, you can trigger the watch command: ```bash @@ -76,14 +76,14 @@ Therefore, you can trigger the watch command: npx nx observe-all miranum- ``` -If not already done, you have to open this project with VS Code. Then select *Run and Debug* and choose the extension ( -see figure below). Use the `F5` key or the debug menu option `Run Miranum ...` to start the Extension Development Host. +If not already done, you have to open this project with VS Code. +Then select *Run and Debug* and choose the extension (see the figure below). +Use the `F5` key or the debug menu option `Run Miranum ...` to start the Extension Development Host. This will open a second window in which you can use/test the extension. ![vscode_run_debug.png](../images/vscode_run_debug.png) -If the Extension Development Host is already running you can update it with `cmd + r` on mac (`crtl + r` probably on -windows/linux). +If the Extension Development Host is already running, you can update it with `cmd + r` on Mac (`crtl + r` windows/linux). ## Testing @@ -134,7 +134,7 @@ gitGraph ## CI/CD **Feature Branch** -After every commit the *test* workflow is executed that runs the lint command and all available tests. +After every commit, the *test* workflow is executed that runs the lint command and all available tests. **Pull Request** For every open Pull Request (PR) the *pr-labeler* workflow is executed that adds labels to the PR for every app, lib, diff --git a/docs/quickstart.md b/docs/quickstart.md index c93f13f4..34437718 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,11 +1,11 @@ # Quickstart -This monorepo uses Nx as build system for the application. +This monorepo uses Nx as the build system for the application. - [Setup](#setup) - [Getting Started](#getting-started) - [Create a new app or lib](#create-a-new-app-or-lib) - - [Adding capabilities to the workspace](#adding-capabilities-to-the-workspace) + - _[Adding capabilities to the workspace](#adding-capabilities-to-the-workspace)_ - _[Generate a new application](#generate-a-new-application)_ - _[Generate a new library](#generate-a-new-library)_ - _[Generate a new VS Code Plugin](#generate-a-new-vs-code-plugin)_ @@ -96,9 +96,9 @@ Libraries are shareable across libraries and applications. They can be imported npx nx g @nx/node:lib my-awesome-lib --publishable --importPath @miranum-ide/my-awesome-lib ``` -### Generate a new VS Code Plugin +## Generate a new VS Code Plugin -1. Run `npx nx g @nx/node:app my-app` to generate a node application. +1. Run `npx nx g @nx/node:app my-app --directory apps` to generate a node application. 2. Add a `package.json` file under `src` to your new app with the commands required for vscode. @@ -161,24 +161,38 @@ npx nx g @nx/node:lib my-awesome-lib --publishable --importPath @miranum-ide/my- "request": "launch", "args": [ "--disable-extensions", - "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/my-app" + "--extensionDevelopmentPath=${workspaceFolder}/dist/apps/" ], - "outFiles": ["${workspaceFolder}/dist/apps/my-app/**/*.js"], + "outFiles": ["${workspaceFolder}/dist/apps//**/*.js"], "resolveSourceMapLocations": [ - "${workspaceFolder}/dist/apps/my-app/**", + "${workspaceFolder}/dist/apps//**", "!**/node_modules/**" ], "sourceMapPathOverrides": { "webpack:///./~/*": "${workspaceFolder}/node_modules/*", - "webpack://?:*/*": "${workspaceFolder}/apps/my-app/*" + "webpack://?:*/*": "${workspaceFolder}/apps//*" } } ``` - > _*Note:*_ Replace `my-app` with the actual name from Step 1. + > _*Note:*_ Replace `` with the actual name from Step 1. 5. Add standard extension code to the `main.ts` +### Add a new Webview +If your VS Code Plugin needs a webview, you can use the build in *build executors* to create it. +Dependent on the framework you want to use, there may be different executors available. +In the long run, we want to have only **Vue 3** as a dependency. +However, right now because of the **Miranum Forms Plugin** we have to use **Vue 2**. + +1. This will generate a new folder under `apps/` + + ```shell + npx nx g @nx/web:rollup my-webview --directory apps --bundler vite + ``` + +2. Alter the `main.ts` file and add the `App.vue` in your new application. + ## Development commands ### Development server diff --git a/libs/vscode/shared/miranum-config-editor/.eslintrc.json b/libs/vscode/shared/miranum-config-editor/.eslintrc.json new file mode 100644 index 00000000..fecdeef9 --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": [ + "../../../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} diff --git a/libs/vscode/shared/miranum-config-editor/README.md b/libs/vscode/shared/miranum-config-editor/README.md new file mode 100644 index 00000000..61ac902e --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/README.md @@ -0,0 +1,13 @@ +# miranum-config-editor-shared + +This library was generated with [Nx](https://nx.dev). + + + + + +## Running unit tests + +Run `nx test miranum-config-editor-shared` to execute the unit tests via [Jest](https://jestjs.io). + + diff --git a/libs/vscode/shared/miranum-config-editor/jest.config.ts b/libs/vscode/shared/miranum-config-editor/jest.config.ts new file mode 100644 index 00000000..f0d58434 --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'miranum-config-editor-shared', + preset: '../../../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }] + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../../../coverage/libs/vscode/shared/miranum-config-editor' +}; diff --git a/libs/vscode/shared/miranum-config-editor/project.json b/libs/vscode/shared/miranum-config-editor/project.json new file mode 100644 index 00000000..262b833b --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/project.json @@ -0,0 +1,36 @@ +{ + "name": "miranum-config-editor-shared", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/vscode/shared/miranum-config-editor/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": [ + "{options.outputFile}" + ], + "options": { + "lintFilePatterns": [ + "libs/vscode/shared/miranum-config-editor/**/*.ts" + ] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}" + ], + "options": { + "jestConfig": "libs/vscode/shared/miranum-config-editor/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + }, + "tags": [] +} diff --git a/libs/vscode/shared/miranum-config-editor/src/index.ts b/libs/vscode/shared/miranum-config-editor/src/index.ts new file mode 100644 index 00000000..fb4d8eca --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/src/index.ts @@ -0,0 +1 @@ +export * from "./lib/types"; diff --git a/libs/vscode/shared/miranum-config-editor/src/lib/types.ts b/libs/vscode/shared/miranum-config-editor/src/lib/types.ts new file mode 100644 index 00000000..f7ab8d4a --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/src/lib/types.ts @@ -0,0 +1,28 @@ +export interface VscMessage { + type: string; + payload?: T; + logger?: string; // if something should be logged in VSCode +} + +/** + * @interface ConfigEditorData + * @description This interface is used to transfer data between the webview and the document. + * @property {string} schema - JSON schema + * @property {string} uischema - JSON uischema + * @property {string} data - JSON data + */ +export interface ConfigEditorData { + schema?: string; + uischema?: string; + data?: string; +} + +export enum MessageType { + initialize = "initialize", // initialize the webview + restore = "restore", // restore the webview + syncWebview = "syncWebview", // user made changes in the document + syncDocument = "syncDocument", // user made changes in the webview + watcher = "watcher", // user made changes in schema or uischema + info = "info", + error = "error", +} diff --git a/libs/vscode/shared/miranum-config-editor/tsconfig.json b/libs/vscode/shared/miranum-config-editor/tsconfig.json new file mode 100644 index 00000000..2c9d3a5e --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs" + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/vscode/shared/miranum-config-editor/tsconfig.lib.json b/libs/vscode/shared/miranum-config-editor/tsconfig.lib.json new file mode 100644 index 00000000..28369ef7 --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/tsconfig.lib.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/libs/vscode/shared/miranum-config-editor/tsconfig.spec.json b/libs/vscode/shared/miranum-config-editor/tsconfig.spec.json new file mode 100644 index 00000000..6668655f --- /dev/null +++ b/libs/vscode/shared/miranum-config-editor/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index 806e1d7b..a7cae4cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,9 @@ "dependencies": { "@bpmn-io/element-template-chooser": "^1.0.0", "@bpmn-io/properties-panel": "^3.13.0", + "@jsonforms/core": "^3.0.0", + "@jsonforms/vue2": "^3.0.0", + "@jsonforms/vue2-vuetify": "^3.0.0", "@koumoul/vjsf": "^2.22.0", "@muenchen/digiwf-form-builder": "^1.0.1", "@muenchen/digiwf-form-builder-settings": "^1.0.1", @@ -37,9 +40,11 @@ "min-dash": "^4.1.1", "react": "18.2.0", "react-dom": "18.2.0", + "reflect-metadata": "^0.1.13", "regenerator-runtime": "0.14.0", "squirrelly": "^9.0.0", "tslib": "^2.6.2", + "tsyringe": "^4.8.0", "uuid": "^9.0.1", "vue": "^2.7.10", "vuetify": "^2.6.15", @@ -48,7 +53,7 @@ "devDependencies": { "@emotion/react": "11.11.1", "@emotion/styled": "11.11.0", - "@mdi/font": "^7.2.96", + "@mdi/font": "^5.9.55", "@mdi/js": "^7.2.96", "@nx/cypress": "17.0.2", "@nx/esbuild": "17.0.2", @@ -77,6 +82,7 @@ "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "@vitejs/plugin-react": "^4.0.4", + "@vitejs/plugin-vue2": "^2.2.0", "@vitest/coverage-v8": "0.34.6", "@vitest/ui": "0.34.6", "@vscode/test-electron": "^2.3.4", @@ -4129,6 +4135,47 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonforms/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@jsonforms/core/-/core-3.0.0.tgz", + "integrity": "sha512-DcUGLNaeAE411oA8d5dPuPEF2/nDmALAfQRsaA3GPAre2D76kJXyBb8TFMjLMRJCVIR0q5LsiRRdmLnuPVHKqA==", + "dependencies": { + "@types/json-schema": "^7.0.3", + "ajv": "^8.6.1", + "ajv-formats": "^2.1.0", + "lodash": "^4.17.15" + } + }, + "node_modules/@jsonforms/vue2": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@jsonforms/vue2/-/vue2-3.0.0.tgz", + "integrity": "sha512-G5TiVvSzvNl6BTNqYBOzNxXg32ICWDZnGU5EZOrkj7lO06J3nC3s33fo/njWA0vgKiUyAuL2FDHxqIgQ2NIPOg==", + "dependencies": { + "lodash": "^4.17.15" + }, + "peerDependencies": { + "@jsonforms/core": "3.0.0", + "vue": "^2.7.0" + } + }, + "node_modules/@jsonforms/vue2-vuetify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@jsonforms/vue2-vuetify/-/vue2-vuetify-3.0.0.tgz", + "integrity": "sha512-HHas1izuEGq7m2Gx9O8BJv7VaHXciNhIBCcksxmdkm9x+MYPgH44BCetAMsy7dfN21aIytRXZRSM2YfEA2OQZA==", + "dependencies": { + "ajv": "^8.6.1", + "dayjs": "^1.10.6", + "lodash": "^4.17.15", + "v-mask": "^2.3.0" + }, + "peerDependencies": { + "@jsonforms/core": "3.0.0", + "@jsonforms/vue2": "3.0.0", + "@mdi/font": "^5.9.55", + "vue": "^2.7.0", + "vuetify": "^2.4.0" + } + }, "node_modules/@koumoul/vjsf": { "version": "2.23.2", "resolved": "https://registry.npmjs.org/@koumoul/vjsf/-/vjsf-2.23.2.tgz", @@ -4223,10 +4270,9 @@ } }, "node_modules/@mdi/font": { - "version": "7.3.67", - "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.3.67.tgz", - "integrity": "sha512-SWxvzRbUQRfewlIV+OF4/YF4DkeTjMWoT8Hh9yeU/5UBVdJZj9Uf4a9+cXjknSIhIaMxZ/4N1O/s7ojApOOGjg==", - "dev": true + "version": "5.9.55", + "resolved": "https://registry.npmjs.org/@mdi/font/-/font-5.9.55.tgz", + "integrity": "sha512-jswRF6q3eq8NWpWiqct6q+6Fg/I7nUhrxYJfiEM8JJpap0wVJLQdbKtyS65GdlK7S7Ytnx3TTi/bmw+tBhkGmg==" }, "node_modules/@mdi/js": { "version": "7.3.67", @@ -9159,8 +9205,7 @@ "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", - "dev": true + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -9744,6 +9789,19 @@ "vite": "^4.2.0" } }, + "node_modules/@vitejs/plugin-vue2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.2.0.tgz", + "integrity": "sha512-1km7zEuZ/9QRPvzXSjikbTYGQPG86Mq1baktpC4sXqsXlb02HQKfi+fl8qVS703JM7cgm24Ga9j+RwKmvFn90A==", + "dev": true, + "engines": { + "node": "^14.18.0 || >= 16.0.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0", + "vue": "^2.7.0-0" + } + }, "node_modules/@vitest/coverage-v8": { "version": "0.34.6", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz", @@ -11537,7 +11595,6 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "devOptional": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -11553,7 +11610,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "devOptional": true, "dependencies": { "ajv": "^8.0.0" }, @@ -15475,8 +15531,7 @@ "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", - "dev": true + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/de-indent": { "version": "1.0.2", @@ -18110,8 +18165,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "devOptional": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -23277,8 +23331,7 @@ "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "devOptional": true + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-source-map": { "version": "0.6.1", @@ -27098,7 +27151,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "devOptional": true, "engines": { "node": ">=6" } @@ -27370,8 +27422,7 @@ "node_modules/reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", @@ -27518,7 +27569,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -30165,6 +30215,22 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsyringe": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", + "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -30596,7 +30662,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "devOptional": true, "dependencies": { "punycode": "^2.1.0" } @@ -30650,6 +30715,11 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v-mask": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v-mask/-/v-mask-2.3.0.tgz", + "integrity": "sha512-ap7pTtCTvj25CqX4VYXqudCBd0+XvYyhiiLbzWQQR7AMQosJ2+DPu0a94P9stk0EGmGcmYxJaPkFkfjD8hquWQ==" + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index 35c81c8d..2af9ea94 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "devDependencies": { "@emotion/react": "11.11.1", "@emotion/styled": "11.11.0", - "@mdi/font": "^7.2.96", + "@mdi/font": "^5.9.55", "@mdi/js": "^7.2.96", "@nx/cypress": "17.0.2", "@nx/esbuild": "17.0.2", @@ -42,6 +42,7 @@ "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "@vitejs/plugin-react": "^4.0.4", + "@vitejs/plugin-vue2": "^2.2.0", "@vitest/coverage-v8": "0.34.6", "@vitest/ui": "0.34.6", "@vscode/test-electron": "^2.3.4", @@ -90,6 +91,9 @@ "dependencies": { "@bpmn-io/element-template-chooser": "^1.0.0", "@bpmn-io/properties-panel": "^3.13.0", + "@jsonforms/core": "^3.0.0", + "@jsonforms/vue2": "^3.0.0", + "@jsonforms/vue2-vuetify": "^3.0.0", "@koumoul/vjsf": "^2.22.0", "@muenchen/digiwf-form-builder": "^1.0.1", "@muenchen/digiwf-form-builder-settings": "^1.0.1", @@ -116,9 +120,11 @@ "min-dash": "^4.1.1", "react": "18.2.0", "react-dom": "18.2.0", + "reflect-metadata": "^0.1.13", "regenerator-runtime": "0.14.0", "squirrelly": "^9.0.0", "tslib": "^2.6.2", + "tsyringe": "^4.8.0", "uuid": "^9.0.1", "vue": "^2.7.10", "vuetify": "^2.6.15", diff --git a/resources/config-editor-example/README.md b/resources/config-editor-example/README.md new file mode 100644 index 00000000..c390b4c0 --- /dev/null +++ b/resources/config-editor-example/README.md @@ -0,0 +1,16 @@ +# config-editor-example + + . + ├── configs + │ ├── dev-config.json + │ └── prod-config.json + │ + ├── element-templates + │ └── .gitkeep + │ + ├── forms + │ ├── control.form + │ └── start.form + │ + ├── miranum.json + └── example-bpmn.bpmn diff --git a/resources/config-editor-example/config-editor-example.bpmn b/resources/config-editor-example/config-editor-example.bpmn new file mode 100644 index 00000000..1d508590 --- /dev/null +++ b/resources/config-editor-example/config-editor-example.bpmn @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/config-editor-example/configs/miranum-platform.process.config.json b/resources/config-editor-example/configs/miranum-platform.process.config.json new file mode 100644 index 00000000..bc57c9fc --- /dev/null +++ b/resources/config-editor-example/configs/miranum-platform.process.config.json @@ -0,0 +1,20 @@ +{ + "statusConfig": [ + { + "key": "offen", + "label": "Offen", + "position": 1 + }, + { + "key": "inBearbeitung", + "label": "In Bearbeitung", + "position": 2 + }, + { + "key": "abgeschlossen", + "label": "Abgeschlossen", + "position": 3 + } + ], + "configs": [] +} \ No newline at end of file diff --git a/resources/config-editor-example/element-templates/ .gitkeep b/resources/config-editor-example/element-templates/ .gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/resources/config-editor-example/forms/config-editor-example_control.form b/resources/config-editor-example/forms/config-editor-example_control.form new file mode 100644 index 00000000..96ffb9f9 --- /dev/null +++ b/resources/config-editor-example/forms/config-editor-example_control.form @@ -0,0 +1,20 @@ +{ + "key": "config-editor-example_control", + "schema": { + "type": "object", + "x-display": "stepper", + "allOf": [ + { + "title": "Abschnitt", + "description": "", + "type": "object", + "x-options": { + "sectionsTitlesClasses": [ + "d-none" + ] + }, + "allOf": [] + } + ] + } +} \ No newline at end of file diff --git a/resources/config-editor-example/forms/config-editor-example_start.form b/resources/config-editor-example/forms/config-editor-example_start.form new file mode 100644 index 00000000..135e95db --- /dev/null +++ b/resources/config-editor-example/forms/config-editor-example_start.form @@ -0,0 +1,20 @@ +{ + "key": "config-editor-example_start", + "schema": { + "type": "object", + "x-display": "stepper", + "allOf": [ + { + "title": "Abschnitt", + "description": "", + "type": "object", + "x-options": { + "sectionsTitlesClasses": [ + "d-none" + ] + }, + "allOf": [] + } + ] + } +} \ No newline at end of file diff --git a/resources/config-editor-example/miranum.json b/resources/config-editor-example/miranum.json new file mode 100644 index 00000000..de7d0640 --- /dev/null +++ b/resources/config-editor-example/miranum.json @@ -0,0 +1,30 @@ +{ + "projectVersion": "1.0.0", + "name": "config-editor-example", + "workspace": [ + { "type": "bpmn", "path": "", "extension": ".bpmn" }, + { "type": "dmn", "path": "", "extension": ".dmn" }, + { "type": "form", "path": "forms", "extension": ".form" }, + { "type": "element-template", "path": "element-templates", "extension": ".json" }, + { "type": "config", "path": "configs", "extension": ".config.json" } + ], + "deployment": [ + { + "plugin": "rest", + "targetEnvironments": [ + { + "name": "local", + "url": "http://localhost:8080" + }, + { + "name": "dev", + "url": "http://localhost:8080" + }, + { + "name": "test", + "url": "http://localhost:8080" + } + ] + } + ] +} \ No newline at end of file diff --git a/resources/config-editor-example/some/path/process.form.json b/resources/config-editor-example/some/path/process.form.json new file mode 100644 index 00000000..371f103a --- /dev/null +++ b/resources/config-editor-example/some/path/process.form.json @@ -0,0 +1,49 @@ +{ + "schema": { + "type": "object", + "properties": { + "statusConfig": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string", + "enum": [ + "offen", + "inBearbeitung", + "abgeschlossen" + ] + }, + "label": { + "type": "string" + }, + "position": { + "type": "integer" + } + } + } + }, + "config": { + "type": "array", + "items": { + "type": "object", + "properties": {} + } + } + } + }, + "uischema": { + "type": "VerticalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/statusConfig" + }, + { + "type": "Control", + "scope": "#/properties/config" + } + ] + } +} \ No newline at end of file diff --git a/resources/config-editor-example/some/path/schema.process.config.json b/resources/config-editor-example/some/path/schema.process.config.json new file mode 100644 index 00000000..76f20feb --- /dev/null +++ b/resources/config-editor-example/some/path/schema.process.config.json @@ -0,0 +1,34 @@ +{ + "type": "object", + "properties": { + "statusConfig": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string", + "enum": [ + "offen", + "inBearbeitung", + "abgeschlossen" + ] + }, + "label": { + "type": "string" + }, + "position": { + "type": "integer" + } + } + } + }, + "config": { + "type": "array", + "items": { + "type": "object", + "properties": {} + } + } + } +} \ No newline at end of file diff --git a/resources/config-editor-example/some/path/uischema.process.config.json b/resources/config-editor-example/some/path/uischema.process.config.json new file mode 100644 index 00000000..a31c6b41 --- /dev/null +++ b/resources/config-editor-example/some/path/uischema.process.config.json @@ -0,0 +1,13 @@ +{ + "type": "VerticalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/statusConfig" + }, + { + "type": "Control", + "scope": "#/properties/config" + } + ] +} \ No newline at end of file diff --git a/resources/example-process/test.dmn b/resources/example-process/test.dmn index 70300984..774bdfa7 100644 --- a/resources/example-process/test.dmn +++ b/resources/example-process/test.dmn @@ -1,8 +1,8 @@ - + - + @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/tsconfig.base.json b/tsconfig.base.json index a4d91c2b..5059beba 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -49,6 +49,9 @@ ], "@miranum-ide/vscode/shared/miranum-modeler": [ "libs/vscode/shared/miranum-modeler/src/index.ts" + ], + "@miranum-ide/vscode/shared/miranum-config-editor": [ + "libs/vscode/shared/miranum-config-editor/src/index.ts" ] } },