diff --git a/.vscode/launch.json b/.vscode/launch.json index f23ca9c3fa..2c8afa3370 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -55,7 +55,8 @@ // "VERSION": "0.6.289", "ELASTIC_INDEX_NAME": "local_storage_index", "UPLOAD_URL": "/files", - "AI_BOT_URL": "http://localhost:4010" + "AI_BOT_URL": "http://localhost:4010", + "STATS_URL": "http://host.docker.internal:4900", }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "runtimeVersion": "20", diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index b118d34aa7..a705578206 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -533,6 +533,9 @@ dependencies: '@rush-temp/model-support': specifier: file:./projects/model-support.tgz version: file:projects/model-support.tgz + '@rush-temp/model-survey': + specifier: file:./projects/model-survey.tgz + version: file:projects/model-survey.tgz '@rush-temp/model-tags': specifier: file:./projects/model-tags.tgz version: file:projects/model-tags.tgz @@ -545,6 +548,9 @@ dependencies: '@rush-temp/model-templates': specifier: file:./projects/model-templates.tgz version: file:projects/model-templates.tgz + '@rush-temp/model-test-management': + specifier: file:./projects/model-test-management.tgz + version: file:projects/model-test-management.tgz '@rush-temp/model-text-editor': specifier: file:./projects/model-text-editor.tgz version: file:projects/model-text-editor.tgz @@ -986,6 +992,15 @@ dependencies: '@rush-temp/support-resources': specifier: file:./projects/support-resources.tgz version: file:projects/support-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2) + '@rush-temp/survey': + specifier: file:./projects/survey.tgz + version: file:projects/survey.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2) + '@rush-temp/survey-assets': + specifier: file:./projects/survey-assets.tgz + version: file:projects/survey-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2) + '@rush-temp/survey-resources': + specifier: file:./projects/survey-resources.tgz + version: file:projects/survey-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2) '@rush-temp/tags': specifier: file:./projects/tags.tgz version: file:projects/tags.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2) @@ -1022,6 +1037,15 @@ dependencies: '@rush-temp/templates-resources': specifier: file:./projects/templates-resources.tgz version: file:projects/templates-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2) + '@rush-temp/test-management': + specifier: file:./projects/test-management.tgz + version: file:projects/test-management.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2) + '@rush-temp/test-management-assets': + specifier: file:./projects/test-management-assets.tgz + version: file:projects/test-management-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2) + '@rush-temp/test-management-resources': + specifier: file:./projects/test-management-resources.tgz + version: file:projects/test-management-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2) '@rush-temp/tests-sanity': specifier: file:./projects/tests-sanity.tgz version: file:projects/tests-sanity.tgz @@ -22727,7 +22751,7 @@ packages: dev: false file:projects/desktop.tgz(bufferutil@4.0.8)(sass@1.71.1)(utf-8-validate@6.0.4): - resolution: {integrity: sha512-VjzxhhavCElN2Ak6+7CforJ3IJK0/iTE6crFhcRZrbq4RajWlGEHpD/o7O3mun0xepqA0QxpHCkTIO6SQdPsOg==, tarball: file:projects/desktop.tgz} + resolution: {integrity: sha512-rjywmlFY/JneloAn6/L8+zLke89G1qy9ROO+fB2hJwYZDK0JGaN0CE68Sq8iZX6fJ+sAIGW6IsbbfpsvhmhUag==, tarball: file:projects/desktop.tgz} id: file:projects/desktop.tgz name: '@rush-temp/desktop' version: 0.0.0 @@ -24471,7 +24495,7 @@ packages: dev: false file:projects/model-all.tgz: - resolution: {integrity: sha512-lZSE4CGfPJX/cTsbqnSoz/ge496Cwl3zeRFHM2wrpgfCFyeCNp00xpRv62LPGe38dvHo/IIzy+Uu0RSVPHUOPw==, tarball: file:projects/model-all.tgz} + resolution: {integrity: sha512-Fxv8P/cfFWJfFli1C70fOej/quvHGGyzJBLpbEixsPV2F+pqX53mwpTzAPqVkHLFVwbRkpnociSpaJQYyx0Beg==, tarball: file:projects/model-all.tgz} name: '@rush-temp/model-all' version: 0.0.0 dependencies: @@ -24981,7 +25005,7 @@ packages: dev: false file:projects/model-recruit.tgz: - resolution: {integrity: sha512-BdP6zfox/ew3/p1cG4jllbe5XNq1UBloo1GmYlbiKf8KalP+PwKUEO/sTNfhdJssVtxCbCTdDXAywt7Tht7OQw==, tarball: file:projects/model-recruit.tgz} + resolution: {integrity: sha512-YxkIn1kk3DNsJsw1ZtSxBgwGJXBbVW/Qms0gei//XbhwvbLJ7PfUX1QSI8HtK5Sgk0s6Qwk0TO6eIQmfQn2jxw==, tarball: file:projects/model-recruit.tgz} name: '@rush-temp/model-recruit' version: 0.0.0 dependencies: @@ -25643,6 +25667,24 @@ packages: - supports-color dev: false + file:projects/model-survey.tgz: + resolution: {integrity: sha512-PmumdtOkNxmrWv+HQ3mJzjMo2tNPOryNofr53EMElCDEZEn3MPW7l35pRZXg2TUpiPqDKpmFl0UoBLYTHPZ7qQ==, tarball: file:projects/model-survey.tgz} + name: '@rush-temp/model-survey' + version: 0.0.0 + dependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + prettier: 3.2.5 + typescript: 5.6.2 + transitivePeerDependencies: + - supports-color + dev: false + file:projects/model-tags.tgz: resolution: {integrity: sha512-zAxxOBsWAAnh3A9pBqBcleZu1bI9CBzbHB2wunYf8bjMytLX10lv9b8S5IT7HwYc031Q0JLrIU7qFu0MwZLjlg==, tarball: file:projects/model-tags.tgz} name: '@rush-temp/model-tags' @@ -25719,6 +25761,24 @@ packages: - supports-color dev: false + file:projects/model-test-management.tgz: + resolution: {integrity: sha512-p0y76Msm6v7Zg8KlvMDiWV3BKCDEw8KjV9sUwC+wkMvKnJ4tOtErd+OdnJFKOyGbtX6yX8rCSp6NIJwqmMmhSA==, tarball: file:projects/model-test-management.tgz} + name: '@rush-temp/model-test-management' + version: 0.0.0 + dependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + prettier: 3.2.5 + typescript: 5.6.2 + transitivePeerDependencies: + - supports-color + dev: false + file:projects/model-text-editor.tgz: resolution: {integrity: sha512-z1TlVHF8VxcMeChSZ70ZGJsKdGSKisnpnPGuLmp2yYS30ckD5ohoj4KeqgbKu+qT+72FYSg4COXFoAYnszgfoA==, tarball: file:projects/model-text-editor.tgz} name: '@rush-temp/model-text-editor' @@ -27488,7 +27548,7 @@ packages: dev: false file:projects/prod.tgz(bufferutil@4.0.8)(sass@1.71.1)(ts-node@10.9.2)(utf-8-validate@6.0.4): - resolution: {integrity: sha512-LpzXVVxqqH4eEF3U7B9uOy/zBFWAZ+FGeGqIBCo9N7UzWxndKf7LZx+eYJQ8gsg5aVoqlGAbXjZJHHSVERGeJQ==, tarball: file:projects/prod.tgz} + resolution: {integrity: sha512-vNHiwvJN+OiPr+lWDdxC3+YB6vZPF0QHYXMXrmHcagQH5vEfVzRPmL9F8pTnx/MHPvAlDt4DqgQls77F8LFYgg==, tarball: file:projects/prod.tgz} id: file:projects/prod.tgz name: '@rush-temp/prod' version: 0.0.0 @@ -29382,7 +29442,7 @@ packages: dev: false file:projects/server-indexer.tgz(esbuild@0.20.1)(ts-node@10.9.2): - resolution: {integrity: sha512-H/iX6BGnUy04J35NoefNnWyoCqEd5RFve5SMXioIuA4tWqglHcAz8JqyPPLlfN+onrsh4Pz0tTVRV6lOZXSXWw==, tarball: file:projects/server-indexer.tgz} + resolution: {integrity: sha512-X0K8LN7D/inN8B9B+/ERJTAm1l0gQ7fA9nOdMMVUHEVZqmq6WoiSZ+vPxdY/dx+MQlYFTcPumxLgZiVCZET4Og==, tarball: file:projects/server-indexer.tgz} id: file:projects/server-indexer.tgz name: '@rush-temp/server-indexer' version: 0.0.0 @@ -29663,7 +29723,7 @@ packages: dev: false file:projects/server-pipeline.tgz: - resolution: {integrity: sha512-VCAeDWNsMsyk2flDq7dhTEuS204IxDIMmB8t44NfPWwciiA/9dwla/bq1Fewnmb/28XS1xdw0UuE+X+qX0AHGA==, tarball: file:projects/server-pipeline.tgz} + resolution: {integrity: sha512-nDWnNg7fzZRCx/xLnxVoi/VBXn0JQotVBhwAgPeOn8EtgZ0ZZBMSLMU2S7rrsJFM8KLCCeIF0HJ4qUkTRrOefw==, tarball: file:projects/server-pipeline.tgz} name: '@rush-temp/server-pipeline' version: 0.0.0 dependencies: @@ -30832,6 +30892,111 @@ packages: - ts-node dev: false + file:projects/survey-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2): + resolution: {integrity: sha512-jqqAAeJVmFwHqA2l6rghsG0C0xdPUhdH6TBtVlQ2CiMA2w+h3fhcpjZ2T9dmx7ovL6XZaOzXpA96rwuVKmgscg==, tarball: file:projects/survey-assets.tgz} + id: file:projects/survey-assets.tgz + name: '@rush-temp/survey-assets' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@types/node': 20.11.19 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + prettier: 3.2.5 + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + dev: false + + file:projects/survey-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2): + resolution: {integrity: sha512-gjJ7S5P7EX8WlBteXR2xkQpSVupNu1lvsWGIaVhNhbZN2zShtm6ud+Dafen9RS2BJ8KrI+L3aQHT3UFj9rgh1g==, tarball: file:projects/survey-resources.tgz} + id: file:projects/survey-resources.tgz + name: '@rush-temp/survey-resources' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2) + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + prettier: 3.2.5 + prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19) + sass: 1.71.1 + svelte: 4.2.19 + svelte-check: 3.6.9(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19) + svelte-eslint-parser: 0.33.1(svelte@4.2.19) + svelte-loader: 3.2.0(svelte@4.2.19) + svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)(typescript@5.6.2) + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - stylus + - sugarss + - supports-color + - ts-node + dev: false + + file:projects/survey.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2): + resolution: {integrity: sha512-6LcozohIYU7ftHjG6jQq+0+Gcv0VlY6FMAEl6edEaSB/FZVmiC4KPoczG7adIH/aOVMqHm6C99lZqLd0PD6NlQ==, tarball: file:projects/survey.tgz} + id: file:projects/survey.tgz + name: '@rush-temp/survey' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + prettier: 3.2.5 + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + dev: false + file:projects/tags-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2): resolution: {integrity: sha512-HjhtvtxGTdHWK1mnrsyMIfazKoV9qWbV5H+6Bdp9WzJHUdkQxJEgoSD6OsTuiMAMsmQBtyhHJ4SKfUy733dtTg==, tarball: file:projects/tags-assets.tgz} id: file:projects/tags-assets.tgz @@ -31256,6 +31421,113 @@ packages: - ts-node dev: false + file:projects/test-management-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2): + resolution: {integrity: sha512-5goSfMWyruB2GJwVYnn8e9YYJW523dDrcME75Og3+yem8W+yUcteJ+Sy2qgMNjCzC6ADzxCM5TIHItnCpH0gjQ==, tarball: file:projects/test-management-assets.tgz} + id: file:projects/test-management-assets.tgz + name: '@rush-temp/test-management-assets' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@types/node': 20.11.19 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + prettier: 3.2.5 + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + dev: false + + file:projects/test-management-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2): + resolution: {integrity: sha512-o+axSz7dIMDinwB3h8Ntr1pP35PGsUtKtTUvEqJFQ1lA+KQdTJ9akLrijzp9T6xRSdTPa6WNG6yjtqM8yhC70w==, tarball: file:projects/test-management-resources.tgz} + id: file:projects/test-management-resources.tgz + name: '@rush-temp/test-management-resources' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2) + fast-equals: 5.0.1 + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + prettier: 3.2.5 + prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19) + sass: 1.71.1 + svelte: 4.2.19 + svelte-check: 3.6.9(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19) + svelte-eslint-parser: 0.33.1(svelte@4.2.19) + svelte-loader: 3.2.0(svelte@4.2.19) + svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)(typescript@5.6.2) + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - stylus + - sugarss + - supports-color + - ts-node + dev: false + + file:projects/test-management.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2): + resolution: {integrity: sha512-zLxjXJwufmBoWJS5xoCGxG9uybC/T7UtJ+g4PlSnDv16aGSPDbnybLtQ0uorYvlOESpcSgQGrVLCgOhIB90tfw==, tarball: file:projects/test-management.tgz} + id: file:projects/test-management.tgz + name: '@rush-temp/test-management' + version: 0.0.0 + dependencies: + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2) + lexorank: 1.0.5 + prettier: 3.2.5 + ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2) + typescript: 5.6.2 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + dev: false + file:projects/tests-sanity.tgz: resolution: {integrity: sha512-noV3nlBP0OvM6i4C5YUevkhltHxG/2bct4pusP3O3AEQ7Za+A4qwzpsE08pHfA9f9pedEG677GE4EmG9x61rVQ==, tarball: file:projects/tests-sanity.tgz} name: '@rush-temp/tests-sanity' @@ -31658,7 +31930,7 @@ packages: dev: false file:projects/tool.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4): - resolution: {integrity: sha512-VMtn5vIgitHobfk3a7XXFR5cr1nCbF/KasUqkn+o+EBDB3H+1n9krwH41lyS9KRHDe6HelYQVcBAPbCn87oPcA==, tarball: file:projects/tool.tgz} + resolution: {integrity: sha512-0sEkRVGviHVTW+esQKFXrECZU6kNST4WxDodKO4DRO9FFB6zdlnFFzjy7+QCjNtP6irb4AEgOXVWWBmdZYk4dw==, tarball: file:projects/tool.tgz} id: file:projects/tool.tgz name: '@rush-temp/tool' version: 0.0.0 @@ -31748,7 +32020,7 @@ packages: dev: false file:projects/tracker-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2): - resolution: {integrity: sha512-6wsyMyxPpL8OKwTKistPKvRxkmmptqXJwxFZ5VOOlGuEwqXFYIPYZNR6taZd33fq1Y97L+vKeP65rWmXhbRIdQ==, tarball: file:projects/tracker-resources.tgz} + resolution: {integrity: sha512-k1Lw3hvnvA+K22hLtdZKz4+ZQbk451p8bQL0RIHZ/yS/dIBLlBpBUU279YAqH2zxlmlFt1+C1WsTsrrPRdfx7A==, tarball: file:projects/tracker-resources.tgz} id: file:projects/tracker-resources.tgz name: '@rush-temp/tracker-resources' version: 0.0.0 diff --git a/desktop/package.json b/desktop/package.json index fbe76ee9ee..a640770c88 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -204,6 +204,12 @@ "@hcengineering/analytics-collector-resources": "^0.6.0", "@hcengineering/ai-bot": "^0.6.0", "@hcengineering/ai-bot-resources": "^0.6.0", + "@hcengineering/test-management": "^0.6.0", + "@hcengineering/test-management-assets": "^0.6.0", + "@hcengineering/test-management-resources": "^0.6.0", + "@hcengineering/survey": "^0.6.0", + "@hcengineering/survey-assets": "^0.6.0", + "@hcengineering/survey-resources": "^0.6.0", "electron-squirrel-startup": "~1.0.0", "dotenv": "~16.0.0", "electron-context-menu": "^4.0.4", diff --git a/desktop/src/ui/platform.ts b/desktop/src/ui/platform.ts index 74aecd76d9..6dd5ac6c33 100644 --- a/desktop/src/ui/platform.ts +++ b/desktop/src/ui/platform.ts @@ -53,6 +53,8 @@ import { questionsId } from '@hcengineering/questions' import { trainingId } from '@hcengineering/training' import { documentsId } from '@hcengineering/controlled-documents' import aiBot, { aiBotId } from '@hcengineering/ai-bot' +import { testManagementId } from '@hcengineering/test-management' +import { surveyId } from '@hcengineering/survey' import '@hcengineering/activity-assets' import '@hcengineering/attachment-assets' @@ -94,6 +96,8 @@ import '@hcengineering/products-assets' import '@hcengineering/controlled-documents-assets' import '@hcengineering/analytics-collector-assets' import '@hcengineering/text-editor-assets' +import '@hcengineering/test-management-assets' +import '@hcengineering/survey-assets' import { coreId } from '@hcengineering/core' import presentation, { parsePreviewConfig, parseUploadConfig, presentationId } from '@hcengineering/presentation' @@ -185,6 +189,8 @@ function configureI18n (): void { addStringsLoader(loveId, async (lang: string) => await import(`@hcengineering/love-assets/lang/${lang}.json`)) addStringsLoader(printId, async (lang: string) => await import(`@hcengineering/print-assets/lang/${lang}.json`)) addStringsLoader(analyticsCollectorId, async (lang: string) => await import(`@hcengineering/analytics-collector-assets/lang/${lang}.json`)) + addStringsLoader(testManagementId, async (lang: string) => await import(`@hcengineering/test-management-assets/lang/${lang}.json`)) + addStringsLoader(surveyId, async (lang: string) => await import(`@hcengineering/survey-assets/lang/${lang}.json`)) } export async function configurePlatform (): Promise { @@ -306,6 +312,8 @@ export async function configurePlatform (): Promise { addLocation(loveId, () => import(/* webpackChunkName: "love" */ '@hcengineering/love-resources')) addLocation(printId, () => import(/* webpackChunkName: "print" */ '@hcengineering/print-resources')) addLocation(textEditorId, () => import(/* webpackChunkName: "text-editor" */ '@hcengineering/text-editor-resources')) + addLocation(testManagementId, () => import(/* webpackChunkName: "test-management" */ '@hcengineering/test-management-resources')) + addLocation(surveyId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/survey-resources')) setMetadata(client.metadata.FilterModel, 'ui') setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin]) diff --git a/dev/docker-compose.yaml b/dev/docker-compose.yaml index 1ac0aa0855..2ad74469fb 100644 --- a/dev/docker-compose.yaml +++ b/dev/docker-compose.yaml @@ -102,7 +102,7 @@ services: environment: - PORT=4900 - SERVER_SECRET=secret - restart: unless-stopped + restart: unless-stopped workspace: image: hardcoreeng/workspace extra_hosts: @@ -221,7 +221,6 @@ services: links: - mongodb - minio - - rekoni - account - stats # - apm-server @@ -261,7 +260,6 @@ services: links: - postgres - minio - - rekoni - account - stats # - apm-server @@ -296,10 +294,6 @@ services: restart: unless-stopped ports: - 4004:4004 - deploy: - resources: - limits: - memory: 1024M fulltext: image: hardcoreeng/fulltext extra_hosts: @@ -319,10 +313,6 @@ services: - STATS_URL=http://host.docker.internal:4900 - REKONI_URL=http://host.docker.internal:4004 - ACCOUNTS_URL=http://host.docker.internal:3000 - deploy: - resources: - limits: - memory: 300M fulltext_pg: image: hardcoreeng/fulltext extra_hosts: @@ -343,10 +333,6 @@ services: - STATS_URL=http://host.docker.internal:4900 - REKONI_URL=http://host.docker.internal:4004 - ACCOUNTS_URL=http://host.docker.internal:3000 - deploy: - resources: - limits: - memory: 300M print: image: hardcoreeng/print extra_hosts: @@ -358,10 +344,6 @@ services: - SECRET=secret - STORAGE_CONFIG=${STORAGE_CONFIG} - STATS_URL=http://host.docker.internal:4900 - deploy: - resources: - limits: - memory: 300M sign: image: hardcoreeng/sign extra_hosts: @@ -382,10 +364,6 @@ services: - SERVICE_ID=sign-service - BRANDING_PATH=/var/cfg/branding.json - STATS_URL=http://host.docker.internal:4900 - deploy: - resources: - limits: - memory: 300M analytics: image: hardcoreeng/analytics-collector extra_hosts: @@ -402,10 +380,6 @@ services: - ACCOUNTS_URL=http://host.docker.internal:3000 - SUPPORT_WORKSPACE=support - STATS_URL=http://host.docker.internal:4900 - deploy: - resources: - limits: - memory: 300M aiBot: image: hardcoreeng/ai-bot ports: @@ -426,10 +400,6 @@ services: - STATS_URL=http://host.docker.internal:4900 # - LOVE_ENDPOINT=http://host.docker.internal:8096 # - OPENAI_API_KEY=token - deploy: - resources: - limits: - memory: 300M # telegram-bot: # image: hardcoreeng/telegram-bot # extra_hosts: @@ -445,10 +415,6 @@ services: # - ACCOUNTS_URL=http://host.docker.internal:3000 # - SERVICE_ID=telegram-bot-service # - STATS_URL=http://host.docker.internal:4900 -# deploy: -# resources: -# limits: -# memory: 300M volumes: db: dbpg: diff --git a/dev/prod/package.json b/dev/prod/package.json index 2b7474a8e7..42817fccb0 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -233,6 +233,12 @@ "@hcengineering/products-resources": "^0.1.0", "@hcengineering/ai-bot": "^0.6.0", "@hcengineering/ai-bot-resources": "^0.6.0", + "@hcengineering/test-management": "^0.6.0", + "@hcengineering/test-management-assets": "^0.6.0", + "@hcengineering/test-management-resources": "^0.6.0", + "@hcengineering/survey": "^0.6.0", + "@hcengineering/survey-assets": "^0.6.0", + "@hcengineering/survey-resources": "^0.6.0", "@sentry/svelte": "~7.101.0", "posthog-js": "~1.122.0" } diff --git a/dev/prod/src/platform.ts b/dev/prod/src/platform.ts index 047464e2d9..e4d7992db2 100644 --- a/dev/prod/src/platform.ts +++ b/dev/prod/src/platform.ts @@ -60,6 +60,8 @@ import textEditor, { textEditorId } from '@hcengineering/text-editor' import analyticsCollector, {analyticsCollectorId} from '@hcengineering/analytics-collector' import { uploaderId } from '@hcengineering/uploader' import aiBot, { aiBotId } from '@hcengineering/ai-bot' +import { testManagementId } from '@hcengineering/test-management' +import { surveyId } from '@hcengineering/survey' import { bitrixId } from '@hcengineering/bitrix' @@ -103,6 +105,8 @@ import '@hcengineering/controlled-documents-assets' import '@hcengineering/analytics-collector-assets' import '@hcengineering/text-editor-assets' import '@hcengineering/uploader-assets' +import '@hcengineering/test-management-assets' +import '@hcengineering/survey-assets' import github, { githubId } from '@hcengineering/github' import '@hcengineering/github-assets' @@ -231,6 +235,8 @@ function configureI18n(): void { addStringsLoader(loveId, async (lang: string) => await import(`@hcengineering/love-assets/lang/${lang}.json`)) addStringsLoader(printId, async (lang: string) => await import(`@hcengineering/print-assets/lang/${lang}.json`)) addStringsLoader(analyticsCollectorId, async (lang: string) => await import(`@hcengineering/analytics-collector-assets/lang/${lang}.json`)) + addStringsLoader(testManagementId, async (lang: string) => await import(`@hcengineering/test-management-assets/lang/${lang}.json`)) + addStringsLoader(surveyId, async (lang: string) => await import(`@hcengineering/survey-assets/lang/${lang}.json`)) } export async function configurePlatform() { @@ -399,6 +405,8 @@ export async function configurePlatform() { addLocation(printId, () => import(/* webpackChunkName: "print" */ '@hcengineering/print-resources')) addLocation(textEditorId, () => import(/* webpackChunkName: "text-editor" */ '@hcengineering/text-editor-resources')) addLocation(uploaderId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/uploader-resources')) + addLocation(testManagementId, () => import(/* webpackChunkName: "test-management" */ '@hcengineering/test-management-resources')) + addLocation(surveyId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/survey-resources')) setMetadata(client.metadata.FilterModel, 'ui') setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin]) diff --git a/dev/prod/webpack.config.js b/dev/prod/webpack.config.js index 3669c434cd..c9d9529061 100644 --- a/dev/prod/webpack.config.js +++ b/dev/prod/webpack.config.js @@ -330,6 +330,7 @@ module.exports = [ disableDotRule: true }, host: '0.0.0.0', + allowedHosts: 'all', hot: true, client: { logging: "info", diff --git a/models/all/package.json b/models/all/package.json index 9102565911..141d6e641a 100644 --- a/models/all/package.json +++ b/models/all/package.json @@ -110,6 +110,8 @@ "@hcengineering/model-analytics-collector": "^0.6.0", "@hcengineering/model-server-ai-bot": "^0.6.0", "@hcengineering/model-ai-bot": "^0.6.0", - "@hcengineering/model-server-fulltext": "^0.6.0" + "@hcengineering/model-server-fulltext": "^0.6.0", + "@hcengineering/model-test-management": "^0.6.0", + "@hcengineering/model-survey": "^0.6.0" } } diff --git a/models/all/src/index.ts b/models/all/src/index.ts index 0563d6749f..afbd4957fb 100644 --- a/models/all/src/index.ts +++ b/models/all/src/index.ts @@ -95,11 +95,17 @@ import documents, { documentsId, createModel as documentsModel } from '@hcengine import products, { productsId, createModel as productsModel } from '@hcengineering/model-products' import { serverProductsId, createModel as serverProductsModel } from '@hcengineering/model-server-products' import { serverTrainingId, createModel as serverTrainingModel } from '@hcengineering/model-server-training' +import testManagement, { + testManagementId, + createModel as testManagementModel +} from '@hcengineering/model-test-management' + import { serverDocumentsId, createModel as serverDocumentsModel } from '@hcengineering/model-server-controlled-documents' import { serverFulltextId, createModel as serverFulltextModel } from '@hcengineering/model-server-fulltext' +import { surveyId, createModel as surveyModel } from '@hcengineering/model-survey' import { type Plugin } from '@hcengineering/platform' @@ -404,6 +410,18 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[ classFilter: defaultFilter } ], + [ + testManagementModel, + testManagementId, + { + label: testManagement.string.ConfigLabel, + description: testManagement.string.ConfigDescription, + enabled: false, + beta: false, + classFilter: defaultFilter + } + ], + [surveyModel, surveyId], [serverCoreModel, serverCoreId], [serverAttachmentModel, serverAttachmentId], diff --git a/models/all/src/migration.ts b/models/all/src/migration.ts index 4366401105..e3f441eaf6 100644 --- a/models/all/src/migration.ts +++ b/models/all/src/migration.ts @@ -52,6 +52,8 @@ import { productsOperation } from '@hcengineering/model-products' import { requestOperation } from '@hcengineering/model-request' import { analyticsCollectorOperation } from '@hcengineering/model-analytics-collector' import { workbenchOperation } from '@hcengineering/model-workbench' +import { testManagementOperation } from '@hcengineering/model-test-management' +import { surveyOperation } from '@hcengineering/model-survey' export const migrateOperations: [string, MigrateOperation][] = [ ['core', coreOperation], @@ -92,5 +94,7 @@ export const migrateOperations: [string, MigrateOperation][] = [ // We should call notification migration after activityServer and chunter ['notification', notificationOperation], ['analyticsCollector', analyticsCollectorOperation], - ['workbench', workbenchOperation] + ['workbench', workbenchOperation], + ['testManagement', testManagementOperation], + ['survey', surveyOperation] ] diff --git a/models/calendar/src/index.ts b/models/calendar/src/index.ts index b2c9099059..d5ab86ce8d 100644 --- a/models/calendar/src/index.ts +++ b/models/calendar/src/index.ts @@ -68,6 +68,7 @@ export { calendarId } from '@hcengineering/calendar' export { calendarOperation } from './migration' export const DOMAIN_CALENDAR = 'calendar' as Domain +export const DOMAIN_EVENT = 'event' as Domain @Model(calendar.class.Calendar, core.class.Doc, DOMAIN_CALENDAR) @UX(calendar.string.Calendar, calendar.icon.Calendar) @@ -85,7 +86,7 @@ export class TExternalCalendar extends TCalendar implements ExternalCalendar { externalUser!: string } -@Model(calendar.class.Event, core.class.AttachedDoc, DOMAIN_CALENDAR) +@Model(calendar.class.Event, core.class.AttachedDoc, DOMAIN_EVENT) @UX(calendar.string.Event, calendar.icon.Calendar) export class TEvent extends TAttachedDoc implements Event { declare space: Ref diff --git a/models/calendar/src/migration.ts b/models/calendar/src/migration.ts index de39d23ec4..47b3d13706 100644 --- a/models/calendar/src/migration.ts +++ b/models/calendar/src/migration.ts @@ -24,7 +24,7 @@ import { type MigrationUpgradeClient } from '@hcengineering/model' import { DOMAIN_SPACE } from '@hcengineering/model-core' -import { DOMAIN_CALENDAR } from '.' +import { DOMAIN_CALENDAR, DOMAIN_EVENT } from '.' import calendar from './plugin' async function migrateCalendars (client: MigrationClient): Promise { @@ -136,6 +136,16 @@ export const calendarOperation: MigrateOperation = { { state: 'migrate_calendars', func: migrateCalendars + }, + { + state: 'move-events', + func: async (client) => { + await client.move( + DOMAIN_CALENDAR, + { _class: { $in: client.hierarchy.getDescendants(calendar.class.Event) } }, + DOMAIN_EVENT + ) + } } ]) }, diff --git a/models/controlled-documents/src/migration.ts b/models/controlled-documents/src/migration.ts index 3c25413b42..a609ba304f 100644 --- a/models/controlled-documents/src/migration.ts +++ b/models/controlled-documents/src/migration.ts @@ -2,50 +2,51 @@ // Copyright @ 2022-2023 Hardcore Engineering Inc. // +import attachment, { type Attachment } from '@hcengineering/attachment' import { + clone, + loadCollaborativeDoc, + saveCollaborativeDoc, + YAbstractType, + YXmlElement, + YXmlText +} from '@hcengineering/collaboration' +import { + type ChangeControl, + type ControlledDocument, + createChangeControl, + createDocumentTemplate, + type DocumentCategory, + documentsId, + DocumentState +} from '@hcengineering/controlled-documents' +import { + type Class, type Data, - type Ref, - TxOperations, - generateId, + type Doc, DOMAIN_TX, + generateId, makeCollaborativeDoc, MeasureMetricsContext, - type Class, - type Doc, - SortingOrder + type Ref, + SortingOrder, + toIdMap, + TxOperations } from '@hcengineering/core' import { createDefaultSpace, createOrUpdate, - type MigrateUpdate, - type MigrationDocumentQuery, - tryMigrate, - tryUpgrade, type MigrateOperation, + type MigrateUpdate, type MigrationClient, - type MigrationUpgradeClient + type MigrationDocumentQuery, + type MigrationUpgradeClient, + tryMigrate, + tryUpgrade } from '@hcengineering/model' +import { DOMAIN_ATTACHMENT } from '@hcengineering/model-attachment' import core from '@hcengineering/model-core' import tags from '@hcengineering/tags' -import { - type ChangeControl, - type DocumentCategory, - DocumentState, - documentsId, - createDocumentTemplate, - type ControlledDocument, - createChangeControl -} from '@hcengineering/controlled-documents' -import { - loadCollaborativeDoc, - saveCollaborativeDoc, - YXmlElement, - YXmlText, - YAbstractType, - clone -} from '@hcengineering/collaboration' -import attachment, { type Attachment } from '@hcengineering/attachment' -import { DOMAIN_ATTACHMENT } from '@hcengineering/model-attachment' import documents, { DOMAIN_DOCUMENTS } from './index' @@ -210,6 +211,7 @@ async function createDocumentCategories (tx: TxOperations): Promise { { code: 'CM', title: 'Client Management' } ] + const catsCache = toIdMap(await tx.findAll(documents.class.DocumentCategory, {})) const ops = tx.apply() for (const c of categories) { await createOrUpdate( @@ -217,7 +219,8 @@ async function createDocumentCategories (tx: TxOperations): Promise { documents.class.DocumentCategory, documents.space.QualityDocuments, { ...c, attachments: 0 }, - ((documents.category.DOC as string) + ' - ' + c.code) as Ref + ((documents.category.DOC as string) + ' - ' + c.code) as Ref, + catsCache ) } await ops.commit() diff --git a/models/recruit/package.json b/models/recruit/package.json index 1114b3ee65..cd72bec5b1 100644 --- a/models/recruit/package.json +++ b/models/recruit/package.json @@ -52,6 +52,7 @@ "@hcengineering/recruit": "^0.6.29", "@hcengineering/recruit-resources": "^0.6.0", "@hcengineering/setting": "^0.6.17", + "@hcengineering/survey": "^0.6.0", "@hcengineering/task": "^0.6.20", "@hcengineering/ui": "^0.6.15", "@hcengineering/view": "^0.6.13", diff --git a/models/recruit/src/migration.ts b/models/recruit/src/migration.ts index 05520bd0ee..87313df3db 100644 --- a/models/recruit/src/migration.ts +++ b/models/recruit/src/migration.ts @@ -14,7 +14,15 @@ // import { getCategories } from '@anticrm/skillset' -import core, { DOMAIN_TX, TxOperations, type Ref, type Space, type Status } from '@hcengineering/core' +import core, { + DOMAIN_TX, + toIdMap, + TxOperations, + type Doc, + type Ref, + type Space, + type Status +} from '@hcengineering/core' import { createOrUpdate, migrateSpace, @@ -26,7 +34,7 @@ import { type ModelLogger } from '@hcengineering/model' import tags, { type TagCategory } from '@hcengineering/model-tags' -import task, { DOMAIN_TASK, createSequence, migrateDefaultStatusesBase } from '@hcengineering/model-task' +import task, { createSequence, DOMAIN_TASK, migrateDefaultStatusesBase } from '@hcengineering/model-task' import { recruitId, type Applicant } from '@hcengineering/recruit' import { DOMAIN_CALENDAR } from '@hcengineering/model-calendar' @@ -194,10 +202,16 @@ async function createDefaults (client: MigrationUpgradeClient, tx: TxOperations) }, recruit.category.Other ) + const ops = tx.apply() - for (const c of getCategories()) { + const cats = getCategories().filter((it, idx, arr) => arr.findIndex((qt) => qt.id === it.id) === idx) + + const existingCategories = toIdMap( + await client.findAll(tags.class.TagCategory, { targetClass: recruit.mixin.Candidate }) + ) + for (const c of cats) { await createOrUpdate( - tx, + ops, tags.class.TagCategory, core.space.Workspace, { @@ -207,9 +221,11 @@ async function createDefaults (client: MigrationUpgradeClient, tx: TxOperations) tags: c.skills, default: false }, - (recruit.category.Category + '.' + c.id) as Ref + (recruit.category.Category + '.' + c.id) as Ref, + existingCategories ) } + await ops.commit() await createSequence(tx, recruit.class.Review) await createSequence(tx, recruit.class.Opinion) diff --git a/models/recruit/src/types.ts b/models/recruit/src/types.ts index cf94bbb76b..c33b39cc64 100644 --- a/models/recruit/src/types.ts +++ b/models/recruit/src/types.ts @@ -18,6 +18,7 @@ import { Account, IndexKind, type CollaborativeDoc, + type Collection as Array, type Domain, type Markup, type Ref, @@ -59,6 +60,7 @@ import type { Vacancy, VacancyList } from '@hcengineering/recruit' +import survey, { type Poll } from '@hcengineering/survey' import recruit from './plugin' @Model(recruit.class.Vacancy, task.class.Project) @@ -159,6 +161,9 @@ export class TApplicant extends TTask implements Applicant { @Prop(TypeRef(core.class.Status), task.string.TaskState, { _id: recruit.attribute.State }) @Index(IndexKind.Indexed) declare status: Ref + + @Prop(Collection(survey.class.Poll), survey.string.Polls) + polls?: Array } @Model(recruit.class.ApplicantMatch, core.class.AttachedDoc, DOMAIN_TASK) diff --git a/models/server-activity/src/index.ts b/models/server-activity/src/index.ts index f46cc9b2ab..72530fd081 100644 --- a/models/server-activity/src/index.ts +++ b/models/server-activity/src/index.ts @@ -44,14 +44,13 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverActivity.trigger.ActivityMessagesHandler, - txMatch: { - 'tx.objectClass': { $nin: [activity.class.ActivityMessage, notification.class.DocNotifyContext] } - }, + arrays: true, isAsync: true }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverActivity.trigger.OnDocRemoved + trigger: serverActivity.trigger.OnDocRemoved, + arrays: true }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { diff --git a/models/server-ai-bot/src/index.ts b/models/server-ai-bot/src/index.ts index 7fd057182d..b57e134b5c 100644 --- a/models/server-ai-bot/src/index.ts +++ b/models/server-ai-bot/src/index.ts @@ -37,6 +37,7 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverAiBot.trigger.OnMessageSend, + arrays: true, isAsync: true }) diff --git a/models/server-collaboration/src/index.ts b/models/server-collaboration/src/index.ts index 30e6796737..1e7b7d8077 100644 --- a/models/server-collaboration/src/index.ts +++ b/models/server-collaboration/src/index.ts @@ -23,6 +23,7 @@ export { serverCollaborationId } from '@hcengineering/server-collaboration' export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverCollaboration.trigger.OnDelete + trigger: serverCollaboration.trigger.OnDelete, + arrays: true }) } diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index c1fcc304a1..c337b396d7 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -16,6 +16,7 @@ import { type Builder, Mixin, Model } from '@hcengineering/model' +import contact from '@hcengineering/contact' import core, { type Ref } from '@hcengineering/core' import { TClass, TDoc } from '@hcengineering/model-core' import { TNotificationType } from '@hcengineering/model-notification' @@ -33,7 +34,6 @@ import serverNotification, { type TypeMatch, type TypeMatchFunc } from '@hcengineering/server-notification' -import contact from '@hcengineering/contact' export { serverNotificationId } from '@hcengineering/server-notification' @@ -89,7 +89,8 @@ export function createModel (builder: Builder): void { }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.OnDocRemove + trigger: serverNotification.trigger.OnDocRemove, + arrays: true }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { diff --git a/models/server-request/src/index.ts b/models/server-request/src/index.ts index 007cceb17d..50ecf97463 100644 --- a/models/server-request/src/index.ts +++ b/models/server-request/src/index.ts @@ -25,7 +25,8 @@ export { serverRequestId } from '@hcengineering/server-request' export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverRequest.trigger.OnRequest + trigger: serverRequest.trigger.OnRequest, + arrays: true }) builder.mixin(request.class.Request, core.class.Class, serverNotification.mixin.TextPresenter, { diff --git a/models/server-tags/src/index.ts b/models/server-tags/src/index.ts index 842b1d05d7..456b0a5315 100644 --- a/models/server-tags/src/index.ts +++ b/models/server-tags/src/index.ts @@ -23,7 +23,8 @@ export { serverTagsId } from '@hcengineering/server-tags' export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverTags.trigger.onTagReference + trigger: serverTags.trigger.onTagReference, + arrays: true }) builder.mixin, ObjectDDParticipant>( diff --git a/models/server-task/src/index.ts b/models/server-task/src/index.ts index 80e2227a88..c02b5d2f67 100644 --- a/models/server-task/src/index.ts +++ b/models/server-task/src/index.ts @@ -22,6 +22,7 @@ export { serverTaskId } from '@hcengineering/server-task' export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverTask.trigger.OnStateUpdate + trigger: serverTask.trigger.OnStateUpdate, + arrays: true }) } diff --git a/models/server-time/src/index.ts b/models/server-time/src/index.ts index 152eacf9f0..16266df90d 100644 --- a/models/server-time/src/index.ts +++ b/models/server-time/src/index.ts @@ -38,6 +38,7 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverTime.trigger.OnTask, + arrays: true, isAsync: true }) diff --git a/models/server-view/src/index.ts b/models/server-view/src/index.ts index dec068e8f0..ed9a64ec72 100644 --- a/models/server-view/src/index.ts +++ b/models/server-view/src/index.ts @@ -15,10 +15,10 @@ import core, { type Doc } from '@hcengineering/core' import { type Builder, Mixin } from '@hcengineering/model' -import serverCore, { type TriggerControl } from '@hcengineering/server-core' -import serverView, { type ServerLinkIdProvider } from '@hcengineering/server-view' import { TClass } from '@hcengineering/model-core' import { type Resource } from '@hcengineering/platform' +import serverCore, { type TriggerControl } from '@hcengineering/server-core' +import serverView, { type ServerLinkIdProvider } from '@hcengineering/server-view' export { serverViewId } from '@hcengineering/server-view' @@ -31,6 +31,10 @@ export function createModel (builder: Builder): void { builder.createModel(TServerLinkIdProvider) builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverView.trigger.OnCustomAttributeRemove + trigger: serverView.trigger.OnCustomAttributeRemove, + txMatch: { + _class: core.class.TxRemoveDoc, + objectClass: core.class.Attribute + } }) } diff --git a/models/survey/.eslintrc.js b/models/survey/.eslintrc.js new file mode 100644 index 0000000000..c1cf82cba0 --- /dev/null +++ b/models/survey/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/model/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/models/survey/.npmignore b/models/survey/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/survey/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/survey/config/rig.json b/models/survey/config/rig.json new file mode 100644 index 0000000000..2f6be36605 --- /dev/null +++ b/models/survey/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "model" +} diff --git a/models/survey/package.json b/models/survey/package.json new file mode 100644 index 0000000000..fa69730e8f --- /dev/null +++ b/models/survey/package.json @@ -0,0 +1,43 @@ +{ + "name": "@hcengineering/model-survey", + "version": "0.6.0", + "main": "lib/index.js", + "svelte": "src/index.ts", + "types": "types/index.d.ts", + "author": "Hardcore Engineering Inc", + "template": "@hcengineering/model-package", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "build:watch": "compile", + "format": "format src", + "_phase:build": "compile transpile src", + "_phase:format": "format src", + "_phase:validate": "compile validate" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-n": "^15.4.0", + "eslint": "^8.54.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "prettier": "^3.1.0", + "typescript": "^5.3.3" + }, + "dependencies": { + "@hcengineering/activity": "^0.6.0", + "@hcengineering/core": "^0.6.32", + "@hcengineering/model": "^0.6.11", + "@hcengineering/model-chunter": "^0.6.0", + "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-view": "^0.6.0", + "@hcengineering/model-workbench": "^0.6.1", + "@hcengineering/platform": "^0.6.11", + "@hcengineering/survey": "^0.6.0", + "@hcengineering/survey-resources": "^0.6.0", + "@hcengineering/ui": "^0.6.15" + } +} diff --git a/models/survey/src/index.ts b/models/survey/src/index.ts new file mode 100644 index 0000000000..4db5607ef7 --- /dev/null +++ b/models/survey/src/index.ts @@ -0,0 +1,119 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import activity from '@hcengineering/activity' +import { AccountRole } from '@hcengineering/core' +import { type Builder } from '@hcengineering/model' +import core from '@hcengineering/model-core' +import chunter from '@hcengineering/model-chunter' +import view, { type Viewlet } from '@hcengineering/model-view' +import workbench from '@hcengineering/model-workbench' +import { surveyId } from '@hcengineering/survey' +import { TPoll, TSurvey } from './types' +import survey from './plugin' + +export { surveyId } from '@hcengineering/survey' +export { surveyOperation } from './migration' +export default survey +export * from './types' + +export function createModel (builder: Builder): void { + builder.createModel(TPoll, TSurvey) + + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: survey.string.Application, + icon: survey.icon.Application, + alias: surveyId, + accessLevel: AccountRole.User, + hidden: false, + locationResolver: survey.resolver.Location, + navigatorModel: { + spaces: [], + specials: [ + { + id: 'surveys', + label: survey.string.Surveys, + icon: survey.icon.Survey, + component: workbench.component.SpecialView, + componentProps: { + _class: survey.class.Survey, + icon: survey.icon.Survey, + label: survey.string.Surveys, + createLabel: survey.string.CreateSurvey, + createComponent: survey.component.CreateSurvey + } + } + ] + } + }, + survey.app.Survey + ) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: survey.class.Survey, + descriptor: view.viewlet.Table, + config: ['', 'modifiedOn'], + configOptions: { + hiddenKeys: ['name', 'questions'], + sortable: true + } + }, + survey.viewlet.TableSurvey + ) + + builder.mixin(survey.class.Survey, core.class.Class, view.mixin.ObjectPanel, { + component: survey.component.EditSurveyPanel + }) + + builder.mixin(survey.class.Survey, core.class.Class, view.mixin.ObjectPresenter, { + presenter: survey.component.SurveyPresenter + }) + + builder.mixin(survey.class.Survey, core.class.Class, activity.mixin.ActivityDoc, {}) + + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: survey.class.Survey, + components: { input: chunter.component.ChatMessageInput } + }) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: survey.class.Poll, + descriptor: view.viewlet.Table, + config: ['', 'modifiedOn'], + configOptions: { + hiddenKeys: ['name', 'survey', 'results'], + sortable: true + } + }, + survey.viewlet.TablePoll + ) + + builder.mixin(survey.class.Poll, core.class.Class, view.mixin.ObjectPresenter, { + presenter: survey.component.PollPresenter + }) + + builder.mixin(survey.class.Poll, core.class.Class, view.mixin.CollectionEditor, { + editor: survey.component.PollCollection + }) +} diff --git a/models/survey/src/migration.ts b/models/survey/src/migration.ts new file mode 100644 index 0000000000..3248ce2754 --- /dev/null +++ b/models/survey/src/migration.ts @@ -0,0 +1,42 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { + createDefaultSpace, + type MigrateOperation, + type MigrationClient, + type MigrationUpgradeClient, + type ModelLogger, + tryMigrate, + tryUpgrade +} from '@hcengineering/model' + +import survey, { surveyId } from './index' + +export const surveyOperation: MigrateOperation = { + async migrate (client: MigrationClient, logger: ModelLogger): Promise { + await tryMigrate(client, surveyId, []) + }, + async upgrade (state: Map>, client: () => Promise): Promise { + await tryUpgrade(state, client, surveyId, [ + { + state: 'createSpace', + func: async (client) => { + await createDefaultSpace(client, survey.space.Survey, { name: 'Surveys', description: 'Surveys' }) + } + } + ]) + } +} diff --git a/models/survey/src/plugin.ts b/models/survey/src/plugin.ts new file mode 100644 index 0000000000..d6011d4409 --- /dev/null +++ b/models/survey/src/plugin.ts @@ -0,0 +1,20 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { mergeIds } from '@hcengineering/platform' +import { surveyId } from '@hcengineering/survey' +import survey from '@hcengineering/survey-resources/src/plugin' + +export default mergeIds(surveyId, survey, {}) diff --git a/models/survey/src/types.ts b/models/survey/src/types.ts new file mode 100644 index 0000000000..f71a2e10ef --- /dev/null +++ b/models/survey/src/types.ts @@ -0,0 +1,54 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { IndexKind, type Domain, type Ref } from '@hcengineering/core' +import { ArrOf, Hidden, Index, Model, Prop, TypeRecord, TypeRef, TypeString, UX } from '@hcengineering/model' +import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core' +import { getEmbeddedLabel } from '@hcengineering/platform' +import { type Poll, type Question, type Survey } from '@hcengineering/survey' +import survey from './plugin' + +export const DOMAIN_SURVEY = 'survey' as Domain + +@Model(survey.class.Survey, core.class.Doc, DOMAIN_SURVEY) +@UX(survey.string.Survey, survey.icon.Survey, 'SURV', 'name', undefined, survey.string.Surveys) +export class TSurvey extends TDoc implements Survey { + @Prop(TypeString(), survey.string.Name) + @Index(IndexKind.FullText) + name!: string + + @Prop(TypeString(), survey.string.Prompt) + prompt!: string + + @Prop(ArrOf(TypeRecord()), survey.string.Questions) + questions?: Question[] +} + +@Model(survey.class.Poll, core.class.Doc, DOMAIN_SURVEY) +@UX(survey.string.Poll, survey.icon.Poll, 'POLL', undefined, undefined, survey.string.Polls) +export class TPoll extends TAttachedDoc implements Poll { + @Prop(TypeRef(survey.class.Survey), survey.string.Survey) + survey!: Ref + + @Prop(TypeString(), survey.string.Name) + name!: string + + @Prop(TypeString(), survey.string.Prompt) + prompt!: string + + @Prop(ArrOf(TypeRecord()), getEmbeddedLabel('Answers')) + @Hidden() + results?: { question: string, answer: string[] }[] +} diff --git a/models/survey/tsconfig.json b/models/survey/tsconfig.json new file mode 100644 index 0000000000..9765b6086d --- /dev/null +++ b/models/survey/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/model/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "tsBuildInfoFile": ".build/build.tsbuildinfo" + } +} \ No newline at end of file diff --git a/models/test-management/.eslintrc.js b/models/test-management/.eslintrc.js new file mode 100644 index 0000000000..c1cf82cba0 --- /dev/null +++ b/models/test-management/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/model/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/models/test-management/.npmignore b/models/test-management/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/test-management/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/test-management/config/rig.json b/models/test-management/config/rig.json new file mode 100644 index 0000000000..2f6be36605 --- /dev/null +++ b/models/test-management/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "model" +} diff --git a/models/test-management/package.json b/models/test-management/package.json new file mode 100644 index 0000000000..3607dcccd8 --- /dev/null +++ b/models/test-management/package.json @@ -0,0 +1,59 @@ +{ + "name": "@hcengineering/model-test-management", + "version": "0.6.0", + "main": "lib/index.js", + "svelte": "src/index.ts", + "types": "types/index.d.ts", + "author": "Anticrm Platform Contributors", + "template": "@hcengineering/model-package", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "build:watch": "compile", + "format": "format src", + "_phase:build": "compile transpile src", + "_phase:format": "format src", + "_phase:validate": "compile validate" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.6.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-n": "^15.4.0", + "eslint": "^8.54.0", + "@typescript-eslint/parser": "^6.11.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "prettier": "^3.1.0", + "typescript": "^5.3.3" + }, + "dependencies": { + "@hcengineering/attachment": "^0.6.14", + "@hcengineering/activity": "^0.6.0", + "@hcengineering/chunter": "^0.6.20", + "@hcengineering/contact": "^0.6.24", + "@hcengineering/core": "^0.6.32", + "@hcengineering/model": "^0.6.11", + "@hcengineering/model-attachment": "^0.6.0", + "@hcengineering/model-contact": "^0.6.1", + "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/model-presentation": "^0.6.0", + "@hcengineering/model-print": "^0.6.0", + "@hcengineering/model-tracker": "^0.6.0", + "@hcengineering/model-view": "^0.6.0", + "@hcengineering/model-workbench": "^0.6.1", + "@hcengineering/model-activity": "^0.6.0", + "@hcengineering/notification": "^0.6.23", + "@hcengineering/platform": "^0.6.11", + "@hcengineering/setting": "^0.6.17", + "@hcengineering/tags": "^0.6.16", + "@hcengineering/time": "^0.6.0", + "@hcengineering/test-management": "^0.6.0", + "@hcengineering/test-management-resources": "^0.6.0", + "@hcengineering/ui": "^0.6.15", + "@hcengineering/view": "^0.6.13", + "@hcengineering/workbench": "^0.6.16", + "@hcengineering/model-preference": "^0.6.0" + } +} diff --git a/models/test-management/src/defaultTypes.ts b/models/test-management/src/defaultTypes.ts new file mode 100644 index 0000000000..3495aff78a --- /dev/null +++ b/models/test-management/src/defaultTypes.ts @@ -0,0 +1,51 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +import { type Builder } from '@hcengineering/model' +import core from '@hcengineering/model-core' + +import { TDefaultProjectTypeData } from './types' +import testManagement from './plugin' + +export function defineDefaultSpace (builder: Builder): void { + defineDefaultProject(builder) +} + +function defineDefaultProject (builder: Builder): void { + builder.createModel(TDefaultProjectTypeData) + + builder.createDoc( + core.class.SpaceTypeDescriptor, + core.space.Model, + { + name: testManagement.string.TestProject, + description: testManagement.string.FullDescription, + icon: testManagement.icon.TestProject, + baseClass: testManagement.class.TestProject, + availablePermissions: [ + core.permission.UpdateSpace, + core.permission.ArchiveSpace, + core.permission.ForbidDeleteObject + ] + }, + testManagement.descriptors.ProjectType + ) + + builder.createDoc(core.class.SpaceType, core.space.Model, { + name: 'Default project type', + descriptor: testManagement.descriptors.ProjectType, + roles: 0, + targetClass: testManagement.mixin.DefaultProjectTypeData + }) +} diff --git a/models/test-management/src/index.ts b/models/test-management/src/index.ts new file mode 100644 index 0000000000..6b3a4dac7c --- /dev/null +++ b/models/test-management/src/index.ts @@ -0,0 +1,422 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import activity from '@hcengineering/activity' +import chunter from '@hcengineering/chunter' +import core from '@hcengineering/model-core' +import { SortingOrder } from '@hcengineering/core' + +import { type Builder } from '@hcengineering/model' +import view, { createAction } from '@hcengineering/model-view' +import workbench from '@hcengineering/model-workbench' +import print from '@hcengineering/model-print' +import tracker from '@hcengineering/model-tracker' +import { type ViewOptionsModel } from '@hcengineering/view' + +import { testManagementId } from '@hcengineering/test-management' + +import { + DOMAIN_TEST_MANAGEMENT, + TTypeTestCaseType, + TTypeTestCasePriority, + TTypeTestCaseStatus, + TTestProject, + TTestSuite, + TTestCase, + TDefaultProjectTypeData, + TTestRun, + TTypeTestRunResult, + TTestRunItem +} from './types' + +import testManagement from './plugin' +import { definePresenters } from './presenters' + +export { testManagementId } from '@hcengineering/test-management/src/index' + +function defineApplication (builder: Builder): void { + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: testManagement.string.TestManagementApplication, + icon: testManagement.icon.TestManagementApplication, + alias: testManagementId, + hidden: false, + locationResolver: testManagement.resolver.Location, + navigatorModel: { + spaces: [ + { + id: 'projects', + label: testManagement.string.Projects, + spaceClass: testManagement.class.TestProject, + addSpaceLabel: testManagement.string.CreateProject, + createComponent: testManagement.component.CreateProject, + icon: testManagement.icon.Home, + specials: [ + { + id: 'library', + label: testManagement.string.TestLibrary, + icon: testManagement.icon.TestLibrary, + component: workbench.component.SpecialView, + componentProps: { + _class: testManagement.class.TestCase, + icon: testManagement.icon.TestLibrary, + label: testManagement.string.TestLibrary, + createLabel: testManagement.string.CreateTestCase, + createComponent: testManagement.component.CreateTestCase + }, + navigationModel: { + navigationComponent: view.component.FoldersBrowser, + navigationComponentLabel: testManagement.string.TestSuites, + navigationComponentIcon: testManagement.icon.TestSuites, + mainComponentLabel: testManagement.string.TestCases, + mainComponentIcon: testManagement.icon.TestCases, + createComponent: testManagement.component.CreateTestSuite, + navigationComponentProps: { + _class: testManagement.class.TestSuite, + icon: testManagement.icon.TestSuites, + title: testManagement.string.TestSuites, + createLabel: testManagement.string.CreateTestSuite, + createComponent: testManagement.component.CreateTestSuite, + titleKey: 'name', + parentKey: 'parent', + noParentId: testManagement.ids.NoParent, + getFolderLink: testManagement.function.GetTestSuiteLink, + allObjectsLabel: testManagement.string.AllTestCases, + allObjectsIcon: testManagement.icon.TestSuites + }, + syncWithLocationQuery: true + } + } + /* TODO: UBERF-8584 + { + id: opt.testRunsId, + label: testManagement.string.TestRuns, + icon: testManagement.icon.TestRuns, + component: workbench.component.SpecialView, + componentProps: { + _class: testManagement.class.TestRun, + icon: testManagement.icon.TestRuns, + title: testManagement.string.TestRuns, + createLabel: testManagement.string.NewTestRun, + createComponent: testManagement.component.CreateTestRun + } + } */ + ] + } + ] + }, + navHeaderComponent: testManagement.component.NewTestCaseHeader + }, + testManagement.app.TestManagement + ) +} + +export function createModel (builder: Builder): void { + builder.createModel( + TTypeTestCaseType, + TTypeTestCasePriority, + TTypeTestCaseStatus, + TTestProject, + TTestSuite, + TTestCase, + TDefaultProjectTypeData, + TTestRun, + TTestRunItem, + TTypeTestRunResult + ) + + builder.mixin(testManagement.class.TestProject, core.class.Class, activity.mixin.ActivityDoc, {}) + + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: testManagement.class.TestProject, + components: { input: chunter.component.ChatMessageInput } + }) + + defineTestSuite(builder) + defineTestCase(builder) + defineTestRun(builder) + + definePresenters(builder) + + defineApplication(builder) + + builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectIcon, { + component: testManagement.component.TestCaseStatusPresenter + }) + + builder.createDoc(core.class.DomainIndexConfiguration, core.space.Model, { + domain: DOMAIN_TEST_MANAGEMENT, + disabled: [ + { space: 1 }, + { attachedToClass: 1 }, + { status: 1 }, + { project: 1 }, + { priority: 1 }, + { assignee: 1 }, + { sprint: 1 }, + { component: 1 }, + { category: 1 }, + { modifiedOn: 1 }, + { modifiedBy: 1 }, + { createdBy: 1 }, + { relations: 1 }, + { milestone: 1 }, + { createdOn: -1 } + ] + }) + + defineSpaceType(builder) +} + +function defineSpaceType (builder: Builder): void { + builder.createDoc( + core.class.SpaceTypeDescriptor, + core.space.Model, + { + name: testManagement.string.TestProject, + description: testManagement.string.FullDescription, + icon: testManagement.icon.TestProject, + baseClass: testManagement.class.TestProject, + availablePermissions: [ + core.permission.UpdateSpace, + core.permission.ArchiveSpace, + core.permission.ForbidDeleteObject + ] + }, + testManagement.descriptors.ProjectType + ) + + builder.createDoc( + core.class.SpaceType, + core.space.Model, + { + name: 'Default project type', + descriptor: testManagement.descriptors.ProjectType, + roles: 0, + targetClass: testManagement.mixin.DefaultProjectTypeData + }, + testManagement.spaceType.DefaultProject + ) +} + +function defineTestSuite (builder: Builder): void { + builder.mixin(testManagement.class.TestSuite, core.class.Class, activity.mixin.ActivityDoc, {}) + + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: testManagement.class.TestSuite, + components: { input: chunter.component.ChatMessageInput } + }) + + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectEditor, { + editor: testManagement.component.EditTestSuite + }) + + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectPanel, { + component: testManagement.component.EditTestSuite + }) + + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.TestSuitePresenter + }) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: testManagement.class.TestSuite, + descriptor: view.viewlet.Table, + config: ['', 'description'], + configOptions: { + strict: true + } + }, + testManagement.viewlet.TableTestSuites + ) + + // Actions + + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.IgnoreActions, { + actions: [ + view.action.Open, + view.action.OpenInNewTab, + print.action.Print, + tracker.action.EditRelatedTargets, + tracker.action.NewRelatedIssue + ] + }) + + createAction( + builder, + { + action: testManagement.actionImpl.CreateChildTestSuite, + label: testManagement.string.CreateTestSuite, + icon: testManagement.icon.TestSuite, + category: testManagement.category.TestSuite, + input: 'none', + target: testManagement.class.TestSuite, + context: { + mode: ['context', 'browser'], + application: testManagement.app.TestManagement, + group: 'create' + } + }, + testManagement.action.CreateChildTestSuite + ) +} + +function defineTestCase (builder: Builder): void { + builder.mixin(testManagement.class.TestCase, core.class.Class, activity.mixin.ActivityDoc, {}) + + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: testManagement.class.TestCase, + components: { input: chunter.component.ChatMessageInput } + }) + + builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectEditor, { + editor: testManagement.component.EditTestCase + }) + + builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectPanel, { + component: testManagement.component.EditTestCase + }) + + builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.TestCasePresenter + }) + + builder.mixin(testManagement.class.TypeTestCaseStatus, core.class.Class, view.mixin.AttributeFilter, { + component: view.component.ValueFilter + }) + + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.AttributePresenter, { + presenter: testManagement.component.TestSuiteRefPresenter + }) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: testManagement.class.TestCase, + descriptor: view.viewlet.Table, + config: ['', { key: 'attachedTo', label: testManagement.string.TestSuite }, 'status', 'assignee'], + configOptions: { + strict: true + } + }, + testManagement.viewlet.TableTestCase + ) + + const viewOptions: ViewOptionsModel = { + groupBy: ['attachedTo'], + orderBy: [ + ['status', SortingOrder.Ascending], + ['modifiedOn', SortingOrder.Descending], + ['createdOn', SortingOrder.Descending] + ], + other: [ + { + key: 'shouldShowAll', + type: 'toggle', + defaultValue: false, + actionTarget: 'category', + action: view.function.ShowEmptyGroups, + label: view.string.ShowEmptyGroups + } + ] + } + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: testManagement.class.TestCase, + descriptor: view.viewlet.List, + configOptions: { + strict: true, + hiddenKeys: ['title'] + }, + config: [ + { key: '', displayProps: { fixed: 'left', key: 'lead' } }, + { + key: 'status', + props: { kind: 'list', size: 'small', shouldShowName: false } + }, + { key: 'modifiedOn', displayProps: { key: 'modified', fixed: 'right', dividerBefore: true } }, + { + key: 'assignee', + props: { kind: 'list', shouldShowName: false, avatarSize: 'x-small' }, + displayProps: { key: 'assignee', fixed: 'right' } + } + ], + viewOptions + }, + testManagement.viewlet.ListTestCase + ) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: testManagement.class.TestCase, + descriptor: view.viewlet.Table, + config: ['', 'assignee', 'modifiedOn'], + configOptions: { + sortable: true + }, + variant: 'short' + }, + testManagement.viewlet.SuiteTestCases + ) +} + +function defineTestRun (builder: Builder): void { + builder.mixin(testManagement.class.TestRun, core.class.Class, activity.mixin.ActivityDoc, {}) + + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: testManagement.class.TestRun, + components: { input: chunter.component.ChatMessageInput } + }) + + builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectEditor, { + editor: testManagement.component.EditTestRun + }) + + builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectPanel, { + component: testManagement.component.EditTestRun + }) + + builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.TestRunPresenter + }) + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: testManagement.class.TestRun, + descriptor: view.viewlet.Table, + config: [''], + configOptions: { + strict: true + } + }, + testManagement.viewlet.TableTestRun + ) +} + +export { testManagementOperation } from './migration' +export { default } from './plugin' diff --git a/models/test-management/src/migration.ts b/models/test-management/src/migration.ts new file mode 100644 index 0000000000..3169396e42 --- /dev/null +++ b/models/test-management/src/migration.ts @@ -0,0 +1,21 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient } from '@hcengineering/model' + +export const testManagementOperation: MigrateOperation = { + async migrate (client: MigrationClient): Promise {}, + async upgrade (state: Map>, client: () => Promise): Promise {} +} diff --git a/models/test-management/src/plugin.ts b/models/test-management/src/plugin.ts new file mode 100644 index 0000000000..abf37a268f --- /dev/null +++ b/models/test-management/src/plugin.ts @@ -0,0 +1,49 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { testManagementId } from '@hcengineering/test-management' +import testManganement from '@hcengineering/test-management-resources/src/plugin' +import type { Doc, Ref } from '@hcengineering/core' +import { mergeIds } from '@hcengineering/platform' +import { type AnyComponent } from '@hcengineering/ui/src/types' +import type { Action, ActionCategory, ViewAction } from '@hcengineering/view' + +export default mergeIds(testManagementId, testManganement, { + action: { + DeleteTestCase: '' as Ref>, + CreateChildTestSuite: '' as Ref, + EditTestSuite: '' as Ref + }, + actionImpl: { + CreateChildTestSuite: '' as ViewAction, + EditTestSuite: '' as ViewAction + }, + category: { + TestSuite: '' as Ref + }, + component: { + CreateTestCase: '' as AnyComponent, + TestCasePresenter: '' as AnyComponent, + ProjectPresenter: '' as AnyComponent, + ProjectSpacePresenter: '' as AnyComponent, + TestSuitePresenter: '' as AnyComponent, + EditTestSuite: '' as AnyComponent, + EditTestCase: '' as AnyComponent, + CreateTestRun: '' as AnyComponent, + TestRunPresenter: '' as AnyComponent, + EditTestRun: '' as AnyComponent, + TestSuiteRefPresenter: '' as AnyComponent + } +}) diff --git a/models/test-management/src/presenters.ts b/models/test-management/src/presenters.ts new file mode 100644 index 0000000000..0b45b6df50 --- /dev/null +++ b/models/test-management/src/presenters.ts @@ -0,0 +1,56 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type Builder } from '@hcengineering/model' +import core from '@hcengineering/model-core' +import view from '@hcengineering/model-view' +import testManagement from './plugin' + +/** + * Define presenters + */ +export function definePresenters (builder: Builder): void { + // + // Project + // + builder.mixin(testManagement.class.TestProject, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.ProjectPresenter + }) + + builder.mixin(testManagement.class.TestProject, core.class.Class, view.mixin.SpacePresenter, { + presenter: testManagement.component.ProjectSpacePresenter + }) + + // + // Test Suite + // + builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.TestSuitePresenter + }) + + // + // Test Case + // + builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectPresenter, { + presenter: testManagement.component.TestCasePresenter + }) + + // + // Type Test Case Status + // + builder.mixin(testManagement.class.TypeTestCaseStatus, core.class.Class, view.mixin.AttributePresenter, { + presenter: testManagement.component.TestCaseStatusPresenter + }) +} diff --git a/models/test-management/src/types.ts b/models/test-management/src/types.ts new file mode 100644 index 0000000000..1fca881944 --- /dev/null +++ b/models/test-management/src/types.ts @@ -0,0 +1,233 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import type { Employee } from '@hcengineering/contact' +import type { + TestCase, + TestSuite, + TestCaseType, + TestCasePriority, + TestCaseStatus, + TestProject, + TestRun, + TestRunResult, + TestRunItem +} from '@hcengineering/test-management' +import { type Attachment } from '@hcengineering/attachment' +import contact from '@hcengineering/contact' +import chunter from '@hcengineering/chunter' +import { getEmbeddedLabel } from '@hcengineering/platform' +import { + Account, + DateRangeMode, + IndexKind, + type RolesAssignment, + type Role, + Ref, + type Domain, + type Timestamp, + type Type, + type CollectionSize, + type CollaborativeDoc, + type Class +} from '@hcengineering/core' +import { + Mixin, + Model, + Prop, + TypeRef, + UX, + TypeMarkup, + Index, + TypeCollaborativeDoc, + TypeString, + Collection, + ReadOnly, + TypeDate, + Hidden +} from '@hcengineering/model' +import attachment from '@hcengineering/model-attachment' +import core, { TAttachedDoc, TDoc, TType, TTypedSpace } from '@hcengineering/model-core' + +import testManagement from './plugin' + +export { testManagementId } from '@hcengineering/test-management/src/index' + +export const DOMAIN_TEST_MANAGEMENT = 'test-management' as Domain + +/** @public */ +export function TypeTestCaseType (): Type { + return { _class: testManagement.class.TypeTestCaseType, label: testManagement.string.TestCaseType } +} + +@Model(testManagement.class.TypeTestCaseType, core.class.Type, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestCaseType) +export class TTypeTestCaseType extends TType {} + +/** @public */ +export function TypeTestCasePriority (): Type { + return { _class: testManagement.class.TypeTestCasePriority, label: testManagement.string.TestCasePriority } +} + +@Model(testManagement.class.TypeTestCasePriority, core.class.Type, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestCasePriority) +export class TTypeTestCasePriority extends TType {} + +/** @public */ +export function TypeTestCaseStatus (): Type { + return { _class: testManagement.class.TypeTestCaseStatus, label: testManagement.string.TestCaseStatus } +} + +@Model(testManagement.class.TypeTestCaseStatus, core.class.Type, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestCaseStatus) +export class TTypeTestCaseStatus extends TType {} + +@Model(testManagement.class.TestProject, core.class.TypedSpace) +@UX(testManagement.string.TestProject) +export class TTestProject extends TTypedSpace implements TestProject { + @Prop(TypeMarkup(), testManagement.string.FullDescription) + @Index(IndexKind.FullText) + fullDescription?: string +} + +@Mixin(testManagement.mixin.DefaultProjectTypeData, testManagement.class.TestProject) +@UX(getEmbeddedLabel('Default project'), testManagement.icon.TestProject) +export class TDefaultProjectTypeData extends TTestProject implements RolesAssignment { + [key: Ref]: Ref[] +} + +/** + * @public + */ +@Model(testManagement.class.TestSuite, core.class.Doc, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestSuite, testManagement.icon.TestSuite, testManagement.string.TestSuite) +export class TTestSuite extends TDoc implements TestSuite { + @Prop(TypeString(), testManagement.string.SuiteName) + @Index(IndexKind.FullText) + name!: string + + @Prop(TypeMarkup(), testManagement.string.SuiteDescription) + @Index(IndexKind.FullText) + description?: string + + @Prop(TypeRef(testManagement.class.TestSuite), testManagement.string.TestSuite) + parent!: Ref + + @Prop(Collection(testManagement.class.TestCase), testManagement.string.TestCases, { + shortLabel: testManagement.string.TestCase + }) + testCases?: CollectionSize + + declare space: Ref +} + +/** + * @public + */ +@Model(testManagement.class.TestCase, core.class.AttachedDoc, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestCase, testManagement.icon.TestCase, testManagement.string.TestCase) +export class TTestCase extends TAttachedDoc implements TestCase { + @Prop(TypeRef(testManagement.class.TestProject), core.string.Space) + @Index(IndexKind.Indexed) + @Hidden() + declare space: Ref + + @Prop(TypeRef(testManagement.class.TestSuite), core.string.AttachedTo) + @Index(IndexKind.Indexed) + declare attachedTo: Ref + + @Prop(TypeRef(testManagement.class.TestSuite), core.string.AttachedToClass) + @Index(IndexKind.Indexed) + @Hidden() + declare attachedToClass: Ref> + + @Prop(TypeString(), core.string.Collection) + @Hidden() + override collection: 'testCases' = 'testCases' + + @Prop(TypeString(), testManagement.string.TestName) + @Index(IndexKind.FullText) + name!: string + + @Prop(TypeCollaborativeDoc(), testManagement.string.FullDescription) + @Index(IndexKind.FullText) + description!: CollaborativeDoc + + @Prop(TypeTestCaseType(), testManagement.string.TestType) + @ReadOnly() + type!: TestCaseType + + @Prop(TypeTestCasePriority(), testManagement.string.TestPriority) + @ReadOnly() + priority!: TestCasePriority + + @Prop(TypeTestCaseStatus(), testManagement.string.TestStatus) + @ReadOnly() + status!: TestCaseStatus + + @Prop(TypeRef(contact.mixin.Employee), testManagement.string.TestAssignee) + assignee!: Ref + + @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) + attachments?: CollectionSize + + @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) + comments?: number +} + +@Model(testManagement.class.TestRun, core.class.Doc, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestRun) +export class TTestRun extends TDoc implements TestRun { + @Prop(TypeString(), testManagement.string.TestRunName) + @Index(IndexKind.FullText) + name!: string + + @Prop(TypeCollaborativeDoc(), testManagement.string.FullDescription) + @Index(IndexKind.FullText) + description!: CollaborativeDoc + + @Prop(TypeDate(DateRangeMode.DATETIME), testManagement.string.DueDate) + dueDate?: Timestamp + + @Prop(Collection(testManagement.class.TestRunItem), testManagement.string.TestRunItems, { + shortLabel: testManagement.string.TestRunItem + }) + items?: CollectionSize +} + +/** @public */ +export function TypeTestRunResult (): Type { + return { _class: testManagement.class.TypeTestRunResult, label: testManagement.string.TestRunResult } +} + +@Model(testManagement.class.TypeTestRunResult, core.class.Type, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestRunResult) +export class TTypeTestRunResult extends TType {} + +@Model(testManagement.class.TestRunItem, core.class.AttachedDoc, DOMAIN_TEST_MANAGEMENT) +@UX(testManagement.string.TestRunItem) +export class TTestRunItem extends TAttachedDoc implements TestRunItem { + @Prop(TypeRef(testManagement.class.TestRun), testManagement.string.TestRun) + testRun!: Ref + + @Prop(TypeRef(testManagement.class.TestCase), testManagement.string.TestCase) + testCase!: Ref + + @Prop(TypeTestRunResult(), testManagement.string.TestRunResult) + result?: TestRunResult + + @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) + comments?: number +} diff --git a/models/test-management/tsconfig.json b/models/test-management/tsconfig.json new file mode 100644 index 0000000000..9765b6086d --- /dev/null +++ b/models/test-management/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/model/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "tsBuildInfoFile": ".build/build.tsbuildinfo" + } +} \ No newline at end of file diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index 0fa27261a0..c1f25d7a67 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -88,7 +88,8 @@ export default mergeIds(viewId, view, { ImageViewer: '' as AnyComponent, VideoViewer: '' as AnyComponent, PDFViewer: '' as AnyComponent, - TextViewer: '' as AnyComponent + TextViewer: '' as AnyComponent, + FoldersBrowser: '' as AnyComponent }, string: { Table: '' as IntlString, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..049b9510a8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "platform", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/packages/model/src/utils.ts b/packages/model/src/utils.ts index 9de31e4027..4de9fcc283 100644 --- a/packages/model/src/utils.ts +++ b/packages/model/src/utils.ts @@ -1,4 +1,4 @@ -import { Class, Data, Doc, DocumentUpdate, Ref, Space, TxOperations } from '@hcengineering/core' +import { Class, Data, Doc, DocumentUpdate, Ref, Space, TxOperations, type IdMap } from '@hcengineering/core' import { deepEqual } from 'fast-equals' function toUndef (value: any): any { @@ -40,9 +40,10 @@ export async function createOrUpdate ( _class: Ref>, space: Ref, data: Data, - _id: Ref + _id: Ref, + cache?: IdMap ): Promise { - const existingDoc = await client.findOne(_class, { _id }) + const existingDoc = cache !== undefined ? cache.get(_id) : await client.findOne(_class, { _id }) if (existingDoc !== undefined) { const { _class: _oldClass, _id, space: _oldSpace, modifiedBy, modifiedOn, ...oldData } = existingDoc if (modifiedBy === client.txFactory.account) { diff --git a/packages/ui/src/components/SectionEmpty.svelte b/packages/ui/src/components/SectionEmpty.svelte new file mode 100644 index 0000000000..468b0c8b2f --- /dev/null +++ b/packages/ui/src/components/SectionEmpty.svelte @@ -0,0 +1,38 @@ + + + + +
+
+ +
+ + + +
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 135709bed7..53e08dd656 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -272,6 +272,7 @@ export { default as TimeZonesPopup } from './components/TimeZonesPopup.svelte' export { default as CodeForm } from './components/CodeForm.svelte' export { default as CodeInput } from './components/CodeInput.svelte' export { default as TimeLeft } from './components/TimeLeft.svelte' +export { default as SectionEmpty } from './components/SectionEmpty.svelte' export { default as Dock } from './components/Dock.svelte' diff --git a/plugins/contact-resources/src/components/EditEmployee.svelte b/plugins/contact-resources/src/components/EditEmployee.svelte index 32f61b560d..61f006ecfb 100644 --- a/plugins/contact-resources/src/components/EditEmployee.svelte +++ b/plugins/contact-resources/src/components/EditEmployee.svelte @@ -148,7 +148,6 @@
-
{#if channels === undefined} diff --git a/plugins/recruit-resources/src/components/review/CreateReview.svelte b/plugins/recruit-resources/src/components/review/CreateReview.svelte index b74bef5342..b00d4ab55a 100644 --- a/plugins/recruit-resources/src/components/review/CreateReview.svelte +++ b/plugins/recruit-resources/src/components/review/CreateReview.svelte @@ -13,7 +13,7 @@ // limitations under the License. --> + + + + 0} + on:close={() => { + dispatch('close') + }} + on:changeContent +> +
+
+ +
+
+
diff --git a/plugins/survey-resources/src/components/EditQuestion.svelte b/plugins/survey-resources/src/components/EditQuestion.svelte new file mode 100644 index 0000000000..441d78543e --- /dev/null +++ b/plugins/survey-resources/src/components/EditQuestion.svelte @@ -0,0 +1,462 @@ + + + +
+
+ {#if question === undefined} +
+
+ +
+ {/if} +
+ {#if question !== undefined && question.kind !== QuestionKind.STRING} +
+ {#each options as option, index (index)} +
{ + dragOver(ev, index) + }} + on:dragleave={(ev) => { + dragLeave(ev, index) + }} + on:drop={dragDrop} + class:is-dragged={index === draggedIndex} + class:dragged-over={draggedIndex !== undefined && + draggedOverIndex === index && + draggedOverIndex !== draggedIndex && + draggedOverIndex !== draggedIndex + 1} + > +
{ + dragStart(ev, index) + }} + on:dragend={dragEnd} + > +
+
+ { + await changeOption(index) + }} + /> +
+
+ {/each} +
+ {#if !readonly} +
{ + dragOver(ev, options.length) + }} + on:dragleave={(ev) => { + dragLeave(ev, options.length) + }} + on:drop={dragDrop} + class:dragged-over={draggedOverIndex === options.length && draggedIndex !== options.length - 1} + > +
+ {/if} + {/if} +
+ + diff --git a/plugins/survey-resources/src/components/EditSurvey.svelte b/plugins/survey-resources/src/components/EditSurvey.svelte new file mode 100644 index 0000000000..9e3fcc9d60 --- /dev/null +++ b/plugins/survey-resources/src/components/EditSurvey.svelte @@ -0,0 +1,183 @@ + + + + + +{#if object !== undefined} +
+
+ + {#if showPeviewButton} +
+
+ +
+
+
+ + +
+ {#each questions as question, index} +
{ + dragOver(ev, index) + }} + on:dragleave={(ev) => { + dragLeave(ev, index) + }} + on:drop={dragDrop} + class:dragged-over={draggedIndex !== undefined && + draggedOverIndex === index && + draggedOverIndex !== draggedIndex && + draggedOverIndex !== draggedIndex + 1} + > + { + draggedIndex = index + }} + on:dragEnd={() => { + draggedIndex = undefined + draggedOverIndex = undefined + }} + /> +
+ {/each} + {#if !readonly} +
{ + dragOver(ev, questions.length) + }} + on:dragleave={(ev) => { + dragLeave(ev, questions.length) + }} + on:drop={dragDrop} + class:dragged-over={draggedOverIndex === questions.length && draggedIndex !== questions.length - 1} + > + +
+ {/if} +
+
+{/if} + + diff --git a/plugins/survey-resources/src/components/EditSurveyPanel.svelte b/plugins/survey-resources/src/components/EditSurveyPanel.svelte new file mode 100644 index 0000000000..f96f0926b9 --- /dev/null +++ b/plugins/survey-resources/src/components/EditSurveyPanel.svelte @@ -0,0 +1,91 @@ + + + +{#if object} + { + dispatch('close') + }} + withoutInput={readonly} + > + + +
{object.name}
+
+
+ + +