diff --git a/.vscode/launch.json b/.vscode/launch.json index 51fee10554..d3ee324774 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -138,11 +138,10 @@ "env": { "MONGO_URL": "mongodb://localhost:27017", "DB_URL": "mongodb://localhost:27017", - // "DB_URL": "postgresql://postgres:example@localhost:5432", // "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", "SERVER_SECRET": "secret", - "REGION_INFO":"|Mongo;pg|Postgres;cockroach|CockroachDB", - "TRANSACTOR_URL": "ws://host.docker.internal:3333,ws://host.docker.internal:3331;;pg,ws://host.docker.internal:3332;;cockroach", + "REGION_INFO":"|Mongo;cockroach|CockroachDB", + "TRANSACTOR_URL": "ws://host.docker.internal:3333,ws://host.docker.internal:3332;;cockroach", "ACCOUNTS_URL": "http://localhost:3000", "ACCOUNT_PORT": "3000", "FRONT_URL": "http://localhost:8080", @@ -154,8 +153,6 @@ "MINIO_SECRET_KEY": "minioadmin", "MINIO_ENDPOINT": "localhost" // "DISABLE_SIGNUP": "true", - // "INIT_SCRIPT_URL": "https://raw.githubusercontent.com/hcengineering/init/main/script.yaml", - // "INIT_WORKSPACE": "onboarding", }, "runtimeVersion": "20", "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], @@ -187,8 +184,6 @@ "MINIO_SECRET_KEY": "minioadmin", "MINIO_ENDPOINT": "localhost" // "DISABLE_SIGNUP": "true", - // "INIT_SCRIPT_URL": "https://raw.githubusercontent.com/hcengineering/init/main/script.yaml", - // "INIT_WORKSPACE": "onboarding", }, "runtimeVersion": "20", "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], @@ -236,8 +231,8 @@ "WS_OPERATION": "all+backup", "BACKUP_STORAGE": "minio|minio?accessKey=minioadmin&secretKey=minioadmin", "BACKUP_BUCKET": "dev-backups", - // "INIT_SCRIPT_URL": "https://raw.githubusercontent.com/hcengineering/init/main/script.yaml", - // "INIT_WORKSPACE": "onboarding", + // "INIT_REPO_DIR": "${workspaceRoot}/pods/workspace/init", + // "INIT_WORKSPACE": "staging-dev" }, "runtimeVersion": "20", "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], @@ -269,8 +264,8 @@ "WS_OPERATION": "all+backup", "BACKUP_STORAGE": "minio|minio?accessKey=minioadmin&secretKey=minioadmin", "BACKUP_BUCKET": "dev-backups", - // "INIT_SCRIPT_URL": "https://raw.githubusercontent.com/hcengineering/init/main/script.yaml", - // "INIT_WORKSPACE": "onboarding", + // "INIT_REPO_DIR": "${workspaceRoot}/pods/workspace/init", + // "INIT_WORKSPACE": "staging-dev" }, "runtimeVersion": "20", "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index d473d98ee2..f534b77f1f 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -478,6 +478,9 @@ importers: '@rush-temp/model-server-calendar': specifier: file:./projects/model-server-calendar.tgz version: file:projects/model-server-calendar.tgz + '@rush-temp/model-server-card': + specifier: file:./projects/model-server-card.tgz + version: file:projects/model-server-card.tgz '@rush-temp/model-server-chunter': specifier: file:./projects/model-server-chunter.tgz version: file:projects/model-server-chunter.tgz @@ -823,6 +826,12 @@ importers: '@rush-temp/server-calendar-resources': specifier: file:./projects/server-calendar-resources.tgz version: file:projects/server-calendar-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)) + '@rush-temp/server-card': + specifier: file:./projects/server-card.tgz + version: file:projects/server-card.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)) + '@rush-temp/server-card-resources': + specifier: file:./projects/server-card-resources.tgz + version: file:projects/server-card-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)) '@rush-temp/server-chunter': specifier: file:./projects/server-chunter.tgz version: file:projects/server-chunter.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)) @@ -4038,7 +4047,7 @@ packages: version: 0.0.0 '@rush-temp/card@file:projects/card.tgz': - resolution: {integrity: sha512-rEy3T9z44ZC/94K3q01+0gbaZ0sJBlwB7KvmQuAbiZMU31t+pzS+yoIYkry7YHm/Ca7kd7H4uvcROiAr7yb91w==, tarball: file:projects/card.tgz} + resolution: {integrity: sha512-/vbzO3L239DHkxNpG5cw/ngDrvuvXrRcoq46Y7uJzNwSNAOMpiiRSMdpj4dr2bmPXEhkFGPeA0mKLJwXLseEhw==, tarball: file:projects/card.tgz} version: 0.0.0 '@rush-temp/chunter-assets@file:projects/chunter-assets.tgz': @@ -4326,7 +4335,7 @@ packages: version: 0.0.0 '@rush-temp/model-all@file:projects/model-all.tgz': - resolution: {integrity: sha512-gkINR6HbfTB1ZSXTI2WHg9B+zIZtcSmb+Bb9fVxbGtq6e+RnxSlOlvjEBoru3ElfIO8x6SYd/KoQhRossQQKnQ==, tarball: file:projects/model-all.tgz} + resolution: {integrity: sha512-aDRtqYlITENsW02SJbs+KjoynFL+/QYQmYQVN6++EqsnAT+jHGPl/UpnmSr3ZMcALGcwTx61LKQ1nnxNen8tyA==, tarball: file:projects/model-all.tgz} version: 0.0.0 '@rush-temp/model-analytics-collector@file:projects/model-analytics-collector.tgz': @@ -4350,7 +4359,7 @@ packages: version: 0.0.0 '@rush-temp/model-card@file:projects/model-card.tgz': - resolution: {integrity: sha512-7yhnpluYR/Gypgi3kKPtEVe1NpcG8YfE7S3ACF56GIqXideFnlXYWJ8PjUDQ9Ub5BHUulGYTXKsFUqcHRxQDZA==, tarball: file:projects/model-card.tgz} + resolution: {integrity: sha512-diGAGkQiQNXD27/ln6i6al/sr7X2dOUdiTx6114JOahvZngprIhzdJLdXuW44BnQHTugr4j0Sp1zOwQXKcTBVA==, tarball: file:projects/model-card.tgz} version: 0.0.0 '@rush-temp/model-chunter@file:projects/model-chunter.tgz': @@ -4461,6 +4470,10 @@ packages: resolution: {integrity: sha512-tZOPOELF87VVVRzz1CpJN2JWcTMcpO5l+9pbFEB0YHiGZnBd0oujKLMRiSaI4xXiGo0vhA9BjuHpMvcw7zzw0A==, tarball: file:projects/model-server-calendar.tgz} version: 0.0.0 + '@rush-temp/model-server-card@file:projects/model-server-card.tgz': + resolution: {integrity: sha512-yMw0GV5uufsqDDev756PLadZksaAwUcL1eq52hijUSI4yYC1cr5wvJLW97/g/znWX6kZuHC7lAGvrBcgHf2axw==, tarball: file:projects/model-server-card.tgz} + version: 0.0.0 + '@rush-temp/model-server-chunter@file:projects/model-server-chunter.tgz': resolution: {integrity: sha512-qZkbTEVB25W2XQRrvecg/aTQ+kJhY4uBaq6AVGaEf9jS7ZI7NBzk71rXSv9800GGIe0CPWRpSP/453yZQKfNrg==, tarball: file:projects/model-server-chunter.tgz} version: 0.0.0 @@ -4790,7 +4803,7 @@ packages: version: 0.0.0 '@rush-temp/prod@file:projects/prod.tgz': - resolution: {integrity: sha512-m903gPliLrwApgEDgmJCrV74n9agm3V0SYbi3pYOmiVhcY6MPCRk8FprcHnYIW/VAqbzL/Bn8BYnLF8O9IQBLQ==, tarball: file:projects/prod.tgz} + resolution: {integrity: sha512-VeRmwZegE4UJxGZfbKFP55egCMYIBuW6fCawXf1NHcXc93vnE6m9sax3s/O++FU3bMIhusbA0d74ZRRCCozxTw==, tarball: file:projects/prod.tgz} version: 0.0.0 '@rush-temp/products-assets@file:projects/products-assets.tgz': @@ -4921,6 +4934,14 @@ packages: resolution: {integrity: sha512-FQkSKyOpAPE2lnQ6wDRR1ar17olXsmHTWD1vW+ajxSNMuayv4mEVFftAFVfj6b1WvqyuJMiWR8TDv3CRWW5bug==, tarball: file:projects/server-calendar.tgz} version: 0.0.0 + '@rush-temp/server-card-resources@file:projects/server-card-resources.tgz': + resolution: {integrity: sha512-sJdtOVlhTFawBXtSTzcx+Vs8NALsiqBfwAz9cqUBj45vobiSF97D987LPBgjhCARk2+qx8lZyUPPTUJkJdaLOQ==, tarball: file:projects/server-card-resources.tgz} + version: 0.0.0 + + '@rush-temp/server-card@file:projects/server-card.tgz': + resolution: {integrity: sha512-ATIgXsB+SGQDQHyZqzQ8ooD/yAjqyimZzjMVZLMFJvRQenPLZEwdW0D+ikWila7ixB115IvKtGhrM8y7mvnMog==, tarball: file:projects/server-card.tgz} + version: 0.0.0 + '@rush-temp/server-chunter-resources@file:projects/server-chunter-resources.tgz': resolution: {integrity: sha512-kiR/o8nysn7cgV4YGZNzxBpqzpoTqXGPyF7fXO3MJ0aZPa46AWQPushZMQTnR9O7wFs3RUuHR7Bc6VsjlzqDqA==, tarball: file:projects/server-chunter-resources.tgz} version: 0.0.0 @@ -5058,7 +5079,7 @@ packages: version: 0.0.0 '@rush-temp/server-pipeline@file:projects/server-pipeline.tgz': - resolution: {integrity: sha512-AEDx9sHjL/Dh1KCJ0DiICkS4JZ24HrqPlz4Wp09xmI9d3q35DpCS2oP8+qUjSF1qX5kZSIu0GrDshztCFYQScQ==, tarball: file:projects/server-pipeline.tgz} + resolution: {integrity: sha512-fmLSX42maXiVGBW3TM2hB1y5UG+weaJSBpInOVUMf/5Y59N3s0rACYuHR+wuzcmIdIRiXKMN7ypET7mz4sxT2g==, tarball: file:projects/server-pipeline.tgz} version: 0.0.0 '@rush-temp/server-preference@file:projects/server-preference.tgz': @@ -5174,7 +5195,7 @@ packages: version: 0.0.0 '@rush-temp/setting-resources@file:projects/setting-resources.tgz': - resolution: {integrity: sha512-f1+pi6AyYD3Vr5UbZfqt4sOwCRC3ZL5x3EQBDUqD+XKx/XbVfCMF3fp7E1Jw+tA3v/Rp+b7w+DBUQnxa4nVRDQ==, tarball: file:projects/setting-resources.tgz} + resolution: {integrity: sha512-Zo+LyWbC/Inw72MfcPx+PBUsFa2bPxSktMYBuSrU6FC11wduoFx+Q7Sf8hGF3rfPvZ8bnpcVbNO77Mh3Ncin6w==, tarball: file:projects/setting-resources.tgz} version: 0.0.0 '@rush-temp/setting@file:projects/setting.tgz': @@ -5322,7 +5343,7 @@ packages: version: 0.0.0 '@rush-temp/tool@file:projects/tool.tgz': - resolution: {integrity: sha512-dMjmwZoox3cdyn4o7EY2NL8Kst4si0xI+HT9YSnaQd7A4cBwapn/oXi163xq2f9mOhf2oekXpt2iT1hK8JoQQQ==, tarball: file:projects/tool.tgz} + resolution: {integrity: sha512-1/Aodec9LySBThOZAeA3XJfP83lSVTVRFdlb8uNTORq1sHJxCADx9BliCh2dTzdhydW46wcAxMPeArhopkcN1Q==, tarball: file:projects/tool.tgz} version: 0.0.0 '@rush-temp/tracker-assets@file:projects/tracker-assets.tgz': @@ -19666,6 +19687,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@rush-temp/model-server-card@file:projects/model-server-card.tgz': + dependencies: + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(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@8.56.0)(typescript@5.7.3) + 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.7.3 + transitivePeerDependencies: + - supports-color + '@rush-temp/model-server-chunter@file:projects/model-server-chunter.tgz': dependencies: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3) @@ -22721,6 +22756,56 @@ snapshots: - supports-color - ts-node + '@rush-temp/server-card-resources@file:projects/server-card-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))': + 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.3.3))(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(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@8.56.0)(typescript@5.7.3) + 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(@types/node@20.11.19)(typescript@5.3.3)) + prettier: 3.2.5 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + + '@rush-temp/server-card@file:projects/server-card.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))': + 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.3.3))(eslint@8.56.0)(typescript@5.7.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(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@8.56.0)(typescript@5.7.3) + 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(@types/node@20.11.19)(typescript@5.3.3)) + prettier: 3.2.5 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - esbuild + - node-notifier + - supports-color + - ts-node + '@rush-temp/server-chunter-resources@file:projects/server-chunter-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))': dependencies: '@types/jest': 29.5.12 diff --git a/dev/docker-compose.yaml b/dev/docker-compose.yaml index 06592146b5..bb7e47299e 100644 --- a/dev/docker-compose.yaml +++ b/dev/docker-compose.yaml @@ -80,7 +80,7 @@ services: # Pass only one region to disallow selection for new workspaces.Ø - REGION_INFO=|Mongo;cockroach|CockroachDB # - REGION_INFO=cockroach|CockroachDB - - TRANSACTOR_URL=ws://host.docker.internal:3333,ws://host.docker.internal:3331;;pg,ws://host.docker.internal:3332;;cockroach, + - TRANSACTOR_URL=ws://host.docker.internal:3333,ws://host.docker.internal:3332;;cockroach, - SES_URL= - STORAGE_CONFIG=${STORAGE_CONFIG} - FRONT_URL=http://host.docker.internal:8087 @@ -91,8 +91,6 @@ services: - ACCOUNTS_URL=http://host.docker.internal:3000 - BRANDING_PATH=/var/cfg/branding.json # - DISABLE_SIGNUP=true - # - INIT_SCRIPT_URL=https://raw.githubusercontent.com/hcengineering/init/main/script.yaml - # - INIT_WORKSPACE=onboarding restart: unless-stopped stats: image: hardcoreeng/stats @@ -126,9 +124,9 @@ services: - ACCOUNTS_URL=http://host.docker.internal:3000 - BRANDING_PATH=/var/cfg/branding.json # - PARALLEL=2 - - INIT_WORKSPACE=test - BACKUP_STORAGE=${BACKUP_STORAGE_CONFIG} - BACKUP_BUCKET=${BACKUP_BUCKET_NAME} + # - INIT_WORKSPACE=staging-dev restart: unless-stopped workspace_cockroach: image: hardcoreeng/workspace @@ -153,9 +151,9 @@ services: - ACCOUNTS_URL=http://host.docker.internal:3000 - BRANDING_PATH=/var/cfg/branding.json # - PARALLEL=2 - # - INIT_WORKSPACE=onboarding - BACKUP_STORAGE=${BACKUP_STORAGE_CONFIG} - BACKUP_BUCKET=${BACKUP_BUCKET_NAME} + # - INIT_WORKSPACE=staging-dev restart: unless-stopped collaborator: image: hardcoreeng/collaborator diff --git a/dev/prod/package.json b/dev/prod/package.json index 36f1d360c1..aa685c2f8a 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -110,16 +110,6 @@ "@hcengineering/inventory": "^0.6.11", "@hcengineering/inventory-assets": "^0.6.11", "@hcengineering/inventory-resources": "^0.6.0", - "@hcengineering/server-attachment": "^0.6.1", - "@hcengineering/server-attachment-resources": "^0.6.0", - "@hcengineering/server-collaboration": "^0.6.0", - "@hcengineering/server-collaboration-resources": "^0.6.0", - "@hcengineering/server-contact": "^0.6.1", - "@hcengineering/server-contact-resources": "^0.6.0", - "@hcengineering/server-notification": "^0.6.1", - "@hcengineering/server-notification-resources": "^0.6.0", - "@hcengineering/server-setting": "^0.6.0", - "@hcengineering/server-setting-resources": "^0.6.0", "@hcengineering/templates": "^0.6.11", "@hcengineering/templates-assets": "^0.6.11", "@hcengineering/templates-resources": "^0.6.0", @@ -133,30 +123,10 @@ "@hcengineering/tags-assets": "^0.6.0", "@hcengineering/tags": "^0.6.16", "@hcengineering/tags-resources": "^0.6.0", - "@hcengineering/server-chunter": "^0.6.0", - "@hcengineering/server-chunter-resources": "^0.6.0", - "@hcengineering/server-inventory": "^0.6.1", - "@hcengineering/server-inventory-resources": "^0.6.0", - "@hcengineering/server-lead": "^0.6.0", - "@hcengineering/server-lead-resources": "^0.6.0", - "@hcengineering/server-recruit": "^0.6.0", - "@hcengineering/server-recruit-resources": "^0.6.0", - "@hcengineering/server-tags": "^0.6.0", - "@hcengineering/server-tags-resources": "^0.6.0", - "@hcengineering/server-task": "^0.6.0", - "@hcengineering/server-task-resources": "^0.6.0", "@hcengineering/calendar": "^0.6.24", "@hcengineering/calendar-assets": "^0.6.22", "@hcengineering/calendar-resources": "^0.6.0", - "@hcengineering/server-calendar": "^0.6.0", - "@hcengineering/server-calendar-resources": "^0.6.0", - "@hcengineering/server-gmail": "^0.6.0", - "@hcengineering/server-gmail-resources": "^0.6.0", - "@hcengineering/server-telegram": "^0.6.0", - "@hcengineering/server-telegram-resources": "^0.6.0", "@hcengineering/presentation": "^0.6.3", - "@hcengineering/server-tracker": "^0.6.0", - "@hcengineering/server-tracker-resources": "^0.6.0", "@hcengineering/tracker": "^0.6.24", "@hcengineering/tracker-assets": "^0.6.0", "@hcengineering/tracker-resources": "^0.6.0", @@ -169,20 +139,12 @@ "@hcengineering/hr": "^0.6.19", "@hcengineering/hr-assets": "^0.6.19", "@hcengineering/hr-resources": "^0.6.0", - "@hcengineering/server-hr": "^0.6.0", - "@hcengineering/server-hr-resources": "^0.6.0", "@hcengineering/bitrix": "^0.6.52", "@hcengineering/bitrix-assets": "^0.6.0", "@hcengineering/bitrix-resources": "^0.6.0", "@hcengineering/request": "^0.6.14", "@hcengineering/request-assets": "^0.6.0", "@hcengineering/request-resources": "^0.6.0", - "@hcengineering/server-request": "^0.6.0", - "@hcengineering/server-request-resources": "^0.6.0", - "@hcengineering/server-view": "^0.6.0", - "@hcengineering/server-view-resources": "^0.6.0", - "@hcengineering/server-activity": "^0.6.0", - "@hcengineering/server-activity-resources": "^0.6.0", "@hcengineering/drive": "^0.6.0", "@hcengineering/drive-assets": "^0.6.0", "@hcengineering/drive-resources": "^0.6.0", diff --git a/dev/tool/package.json b/dev/tool/package.json index d9c1b9d481..e62c42b455 100644 --- a/dev/tool/package.json +++ b/dev/tool/package.json @@ -100,6 +100,8 @@ "@hcengineering/server-storage": "^0.6.0", "@hcengineering/server-calendar": "^0.6.0", "@hcengineering/server-calendar-resources": "^0.6.0", + "@hcengineering/server-card": "^0.6.0", + "@hcengineering/server-card-resources": "^0.6.0", "@hcengineering/server-chunter": "^0.6.0", "@hcengineering/server-chunter-resources": "^0.6.0", "@hcengineering/server-contact": "^0.6.1", diff --git a/dev/tool/src/__start.ts b/dev/tool/src/__start.ts index a0c33c3d39..031a099d3c 100644 --- a/dev/tool/src/__start.ts +++ b/dev/tool/src/__start.ts @@ -23,6 +23,7 @@ import { devTool } from '.' import { addLocation } from '@hcengineering/platform' import { serverActivityId } from '@hcengineering/server-activity' import { serverAttachmentId } from '@hcengineering/server-attachment' +import { serverCardId } from '@hcengineering/server-card' import { serverCalendarId } from '@hcengineering/server-calendar' import { serverChunterId } from '@hcengineering/server-chunter' import { serverCollaborationId } from '@hcengineering/server-collaboration' @@ -59,6 +60,7 @@ addLocation(serverSettingId, () => import('@hcengineering/server-setting-resourc addLocation(serverTaskId, () => import('@hcengineering/server-task-resources')) addLocation(serverTrackerId, () => import('@hcengineering/server-tracker-resources')) addLocation(serverTagsId, () => import('@hcengineering/server-tags-resources')) +addLocation(serverCardId, () => import('@hcengineering/server-card-resources')) addLocation(serverCalendarId, () => import('@hcengineering/server-calendar-resources')) addLocation(serverGmailId, () => import('@hcengineering/server-gmail-resources')) addLocation(serverTelegramId, () => import('@hcengineering/server-telegram-resources')) diff --git a/dev/tool/src/db.ts b/dev/tool/src/db.ts index 206ca5972e..5f9b9dfcfc 100644 --- a/dev/tool/src/db.ts +++ b/dev/tool/src/db.ts @@ -334,7 +334,7 @@ export async function moveAccountDbFromMongoToPG ( } if (workspacesCount % 100 === 0) { - ctx.info(`Migrated ${workspacesCount} invites...`) + ctx.info(`Migrated ${workspacesCount} workspaces...`) } } ctx.info(`Migrated ${workspacesCount} workspaces with ${membersCount} member assignments`) diff --git a/dev/tool/src/index.ts b/dev/tool/src/index.ts index 931f66e3b5..8dc317582f 100644 --- a/dev/tool/src/index.ts +++ b/dev/tool/src/index.ts @@ -46,6 +46,7 @@ import { AccountRole, MeasureMetricsContext, metricsToString, + type PersonId, type Data, type Tx, type Version, @@ -304,7 +305,7 @@ export function devTool ( const measureCtx = new MeasureMetricsContext('create-workspace', {}) const brandingObj = cmd.branding !== undefined || cmd.init !== undefined ? { key: cmd.branding, initWorkspace: cmd.init } : null - const socialId = await db.socialId.findOne({ key: socialString }) + const socialId = await db.socialId.findOne({ key: socialString as PersonId }) if (socialId == null) { throw new Error(`Social id ${socialString} not found`) } diff --git a/models/all/package.json b/models/all/package.json index 1333fcf4ab..9069c256d1 100644 --- a/models/all/package.json +++ b/models/all/package.json @@ -87,6 +87,7 @@ "@hcengineering/model-bitrix": "^0.6.0", "@hcengineering/model-request": "^0.6.0", "@hcengineering/model-support": "^0.6.0", + "@hcengineering/model-server-card": "^0.6.0", "@hcengineering/model-server-request": "^0.6.0", "@hcengineering/model-server-view": "^0.6.0", "@hcengineering/model-server-activity": "^0.6.0", diff --git a/models/all/src/index.ts b/models/all/src/index.ts index 84af4267c5..e80c6707d2 100644 --- a/models/all/src/index.ts +++ b/models/all/src/index.ts @@ -37,6 +37,7 @@ import { requestId, createModel as requestModel } from '@hcengineering/model-req import { aiBotId, createModel as aiBotModel } from '@hcengineering/model-ai-bot' import { serverActivityId, createModel as serverActivityModel } from '@hcengineering/model-server-activity' import { serverAttachmentId, createModel as serverAttachmentModel } from '@hcengineering/model-server-attachment' +import { serverCardId, createModel as serverCardModel } from '@hcengineering/model-server-card' import { serverCalendarId, createModel as serverCalendarModel } from '@hcengineering/model-server-calendar' import { serverChunterId, createModel as serverChunterModel } from '@hcengineering/model-server-chunter' import { @@ -146,7 +147,8 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[ view.class.Action, contact.class.ChannelProvider, setting.class.IntegrationType, - setting.class.WorkspaceSettingCategory + setting.class.WorkspaceSettingCategory, + setting.class.SettingsCategory ] const builders: BuilderConfig[] = [ @@ -366,7 +368,7 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[ { label: card.string.Cards, description: card.string.ConfigDescription, - enabled: false, + enabled: true, beta: true, icon: card.icon.Card, classFilter: defaultFilter @@ -440,6 +442,7 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[ [serverTagsModel, serverTagsId], [serverTaskModel, serverTaskId], [serverTrackerModel, serverTrackerId], + [serverCardModel, serverCardId], [serverCalendarModel, serverCalendarId], [serverRecruitModel, serverRecruitId], [serverGmailModel, serverGmailId], diff --git a/models/card/package.json b/models/card/package.json index bf728b4196..2e5e34f2cf 100644 --- a/models/card/package.json +++ b/models/card/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@hcengineering/activity": "^0.6.0", + "@hcengineering/contact": "^0.6.24", "@hcengineering/core": "^0.6.32", "@hcengineering/model": "^0.6.11", "@hcengineering/chunter": "^0.6.20", diff --git a/models/card/src/index.ts b/models/card/src/index.ts index 77359bc242..e36e4f342d 100644 --- a/models/card/src/index.ts +++ b/models/card/src/index.ts @@ -14,8 +14,11 @@ import activity from '@hcengineering/activity' import { CardEvents, cardId, type Card, type MasterTag, type Tag } from '@hcengineering/card' import chunter from '@hcengineering/chunter' +import contact from '@hcengineering/contact' import core, { AccountRole, + DOMAIN_MODEL, + IndexKind, type CollectionSize, type Domain, type MarkupBlobRef, @@ -24,12 +27,12 @@ import core, { } from '@hcengineering/core' import { Collection, + Index, Model, Prop, TypeCollaborativeDoc, TypeRef, TypeString, - UX, type Builder } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' @@ -38,8 +41,9 @@ import presentation from '@hcengineering/model-presentation' import setting from '@hcengineering/model-setting' import view, { createAction } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' -import { getEmbeddedLabel } from '@hcengineering/platform' +import { getEmbeddedLabel, type IntlString } from '@hcengineering/platform' import time, { type ToDo } from '@hcengineering/time' +import { type AnyComponent } from '@hcengineering/ui' import card from './plugin' export { cardId } from '@hcengineering/card' @@ -53,12 +57,12 @@ export class TMasterTag extends TClass implements MasterTag {} export class TTag extends TMixin implements Tag {} @Model(card.class.Card, core.class.Doc, DOMAIN_CARD) -@UX(card.string.Card) export class TCard extends TDoc implements Card { @Prop(TypeRef(card.class.MasterTag), card.string.MasterTag) declare _class: Ref @Prop(TypeString(), core.string.Name) + @Index(IndexKind.FullText) title!: string @Prop(TypeCollaborativeDoc(), card.string.Content) @@ -75,8 +79,15 @@ export class TCard extends TDoc implements Card { todos?: CollectionSize } +@Model(card.class.MasterTagEditorSection, core.class.Doc, DOMAIN_MODEL) +export class MasterTagEditorSection extends TDoc implements MasterTagEditorSection { + id!: string + label!: IntlString + component!: AnyComponent +} + export function createModel (builder: Builder): void { - builder.createModel(TMasterTag, TTag, TCard) + builder.createModel(TMasterTag, TTag, TCard, MasterTagEditorSection) builder.createDoc( workbench.class.Application, @@ -113,20 +124,6 @@ export function createModel (builder: Builder): void { card.viewlet.CardTable ) - builder.createDoc( - setting.class.WorkspaceSettingCategory, - core.space.Model, - { - name: 'masterTags', - label: card.string.Tags, - icon: card.icon.Tags, - role: AccountRole.User, - component: card.component.MasterTags, - order: 4400 - }, - card.ids.MasterTags - ) - builder.mixin(card.class.Card, core.class.Class, view.mixin.ObjectPresenter, { presenter: card.component.CardPresenter }) @@ -268,11 +265,55 @@ export function createModel (builder: Builder): void { } }) + builder.createDoc( + setting.class.WorkspaceSettingCategory, + core.space.Model, + { + name: 'tagrelation', + label: card.string.TagRelations, + icon: setting.icon.Relations, + props: { _classes: [card.class.Card, contact.class.Contact], exclude: [] }, + component: setting.component.RelationSetting, + group: 'settings-editor', + role: AccountRole.Maintainer, + order: 4501 + }, + card.ids.TagRelations + ) + + builder.createDoc( + setting.class.SettingsCategory, + core.space.Model, + { + name: 'masterTags', + label: card.string.MasterTags, + icon: card.icon.Card, + component: card.component.ManageMasterTagsContent, + extraComponents: { + navigation: card.component.ManageMasterTags, + tools: card.component.ManageMasterTagsTools + }, + group: 'settings-editor', + role: AccountRole.User, + order: 5000, + expandable: true + }, + card.ids.ManageMasterTags + ) + builder.mixin(card.class.Card, core.class.Class, view.mixin.ClassFilters, { filters: [], ignoreKeys: ['parent'] }) + builder.createDoc(core.class.FullTextSearchContext, core.space.Model, { + toClass: card.class.Card, + fullTextSummary: true, + forceIndex: true, + childProcessingAllowed: true, + propagate: [] + }) + builder.createDoc( presentation.class.ObjectSearchCategory, core.space.Model, @@ -283,10 +324,42 @@ export function createModel (builder: Builder): void { query: card.completion.CardQuery, context: ['search', 'mention', 'spotlight'], classToSearch: card.class.Card, + includeChilds: true, priority: 500 }, card.completion.CardCategory ) + + builder.createDoc(card.class.MasterTagEditorSection, core.space.Model, { + id: 'general', + label: setting.string.General, + component: card.component.GeneralSection + }) + + builder.createDoc(card.class.MasterTagEditorSection, core.space.Model, { + id: 'properties', + label: setting.string.Properties, + component: card.component.ProperitiesSection + }) + + builder.createDoc(card.class.MasterTagEditorSection, core.space.Model, { + id: 'tags', + label: card.string.Tags, + component: card.component.TagsSection + }) + + builder.createDoc(card.class.MasterTagEditorSection, core.space.Model, { + id: 'childs', + label: card.string.MasterTags, + masterOnly: true, + component: card.component.ChildsSection + }) + + builder.createDoc(card.class.MasterTagEditorSection, core.space.Model, { + id: 'relations', + label: core.string.Relations, + component: card.component.RelationsSection + }) } export default card diff --git a/models/card/src/plugin.ts b/models/card/src/plugin.ts index c13200793e..ef1ce2aa73 100644 --- a/models/card/src/plugin.ts +++ b/models/card/src/plugin.ts @@ -34,7 +34,9 @@ export default mergeIds(cardId, card, { DeleteMasterTag: '' as Ref }, ids: { - MasterTags: '' as Ref + MasterTags: '' as Ref, + ManageMasterTags: '' as Ref, + TagRelations: '' as Ref }, completion: { CardQuery: '' as Resource, diff --git a/models/server-card/.eslintrc.js b/models/server-card/.eslintrc.js new file mode 100644 index 0000000000..c1cf82cba0 --- /dev/null +++ b/models/server-card/.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/server-card/.npmignore b/models/server-card/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/server-card/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/server-card/config/rig.json b/models/server-card/config/rig.json new file mode 100644 index 0000000000..2f6be36605 --- /dev/null +++ b/models/server-card/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/server-card/package.json b/models/server-card/package.json new file mode 100644 index 0000000000..4963a01656 --- /dev/null +++ b/models/server-card/package.json @@ -0,0 +1,38 @@ +{ + "name": "@hcengineering/model-server-card", + "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/core": "^0.6.32", + "@hcengineering/model": "^0.6.11", + "@hcengineering/platform": "^0.6.11", + "@hcengineering/card": "^0.6.0", + "@hcengineering/server-card": "^0.6.0", + "@hcengineering/server-core": "^0.6.1" + } +} diff --git a/models/server-card/src/index.ts b/models/server-card/src/index.ts new file mode 100644 index 0000000000..f26ef63727 --- /dev/null +++ b/models/server-card/src/index.ts @@ -0,0 +1,39 @@ +// +// Copyright © 2025 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/core' +import serverCore from '@hcengineering/server-core' +import serverCard from '@hcengineering/server-card' +import card from '@hcengineering/card' + +export { serverCardId } from '@hcengineering/server-card' + +export function createModel (builder: Builder): void { + builder.createDoc(serverCore.class.Trigger, core.space.Model, { + trigger: serverCard.trigger.OnAttribute, + isAsync: true, + txMatch: { + _class: core.class.TxCreateDoc, + objectClass: core.class.Attribute + } + }) + + builder.mixin(card.class.Card, core.class.Class, serverCore.mixin.SearchPresenter, { + searchIcon: card.icon.Card, + title: [['title']] + }) +} diff --git a/models/server-card/tsconfig.json b/models/server-card/tsconfig.json new file mode 100644 index 0000000000..9765b6086d --- /dev/null +++ b/models/server-card/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/packages/account-client/src/client.ts b/packages/account-client/src/client.ts index 563cf03064..7595b7c74a 100644 --- a/packages/account-client/src/client.ts +++ b/packages/account-client/src/client.ts @@ -17,7 +17,8 @@ import { BackupStatus, Data, type Person, - PersonUuid, + type PersonUuid, + type PersonInfo, SocialId, Version, type WorkspaceInfoWithStatus, @@ -73,6 +74,7 @@ export interface AccountClient { signUp: (email: string, password: string, first: string, last: string) => Promise login: (email: string, password: string) => Promise getPerson: () => Promise + getPersonInfo: (account: PersonUuid) => Promise getSocialIds: () => Promise getWorkspaceMembers: () => Promise updateWorkspaceRole: (account: string, role: AccountRole) => Promise @@ -399,6 +401,15 @@ class AccountClientImpl implements AccountClient { return await this.rpc(request) } + async getPersonInfo (account: PersonUuid): Promise { + const request = { + method: 'getPersonInfo' as const, + params: [account] + } + + return await this.rpc(request) + } + async getSocialIds (): Promise { const request = { method: 'getSocialIds' as const, diff --git a/packages/core/src/classes.ts b/packages/core/src/classes.ts index 6db32427f8..08ad008ad6 100644 --- a/packages/core/src/classes.ts +++ b/packages/core/src/classes.ts @@ -538,6 +538,10 @@ export interface Person { city?: string } +export interface PersonInfo extends BasePerson { + socialIds: PersonId[] +} + /** * @public */ diff --git a/packages/importer/src/huly/unified.ts b/packages/importer/src/huly/unified.ts index a176073dde..6091dac6ac 100644 --- a/packages/importer/src/huly/unified.ts +++ b/packages/importer/src/huly/unified.ts @@ -16,11 +16,13 @@ import { type Attachment } from '@hcengineering/attachment' import contact, { Employee, type Person } from '@hcengineering/contact' import { + buildSocialIdString, type Class, type Doc, generateId, PersonId, type Ref, + SocialIdType, type Space, type TxOperations } from '@hcengineering/core' @@ -330,24 +332,26 @@ interface AttachmentMetadata { } export class UnifiedFormatImporter { + private readonly importerEmailPlaceholder = 'newuser@huly.io' + private readonly importerNamePlaceholder = 'New User' private readonly pathById = new Map, string>() private readonly refMetaByPath = new Map() private readonly fileMetaByPath = new Map() private readonly ctrlDocTemplateIdByPath = new Map>() private personsByName = new Map>() - // private accountsByEmail = new Map>() - // private employeesByName = new Map>() + private employeesByName = new Map>() constructor ( private readonly client: TxOperations, private readonly fileUploader: FileUploader, - private readonly logger: Logger + private readonly logger: Logger, + private readonly importerSocialId?: PersonId, + private readonly importerPerson?: Ref ) {} private async initCaches (): Promise { await this.cachePersonsByNames() - await this.cacheAccountsByEmails() await this.cacheEmployeesByName() } @@ -588,6 +592,10 @@ export class UnifiedFormatImporter { if (name === undefined) { return undefined } + + if (name === this.importerNamePlaceholder && this.importerPerson != null) { + return this.importerPerson + } const person = this.personsByName.get(name) if (person === undefined) { throw new Error(`Person not found: ${name}`) @@ -595,24 +603,20 @@ export class UnifiedFormatImporter { return person } - private findAccountByEmail (email: string): PersonId { - // TODO: FIXME - throw new Error('Not implemented') - // const account = this.accountsByEmail.get(email) - // if (account === undefined) { - // throw new Error(`Account not found: ${email}`) - // } - // return account + private getSocialIdByEmail (email: string): PersonId { + if (email === this.importerEmailPlaceholder && this.importerSocialId != null) { + return this.importerSocialId + } + + return buildSocialIdString({ type: SocialIdType.EMAIL, value: email }) } private findEmployeeByName (name: string): Ref { - // TODO: FIXME - throw new Error('Not implemented') - // const employee = this.employeesByName.get(name) - // if (employee === undefined) { - // throw new Error(`Employee not found: ${name}`) - // } - // return employee + const employee = this.employeesByName.get(name) + if (employee === undefined) { + throw new Error(`Employee not found: ${name}`) + } + return employee } private async processDocumentsRecursively ( @@ -752,7 +756,7 @@ export class UnifiedFormatImporter { } return { text: comment.text, - author: this.findAccountByEmail(comment.author), + author: this.getSocialIdByEmail(comment.author), attachments } }) @@ -789,9 +793,9 @@ export class UnifiedFormatImporter { defaultIssueStatus: projectHeader.defaultIssueStatus !== undefined ? { name: projectHeader.defaultIssueStatus } : undefined, owners: - projectHeader.owners !== undefined ? projectHeader.owners.map((email) => this.findAccountByEmail(email)) : [], + projectHeader.owners !== undefined ? projectHeader.owners.map((email) => this.getSocialIdByEmail(email)) : [], members: - projectHeader.members !== undefined ? projectHeader.members.map((email) => this.findAccountByEmail(email)) : [], + projectHeader.members !== undefined ? projectHeader.members.map((email) => this.getSocialIdByEmail(email)) : [], docs: [] } } @@ -805,9 +809,9 @@ export class UnifiedFormatImporter { archived: spaceHeader.archived ?? false, description: spaceHeader.description, emoji: spaceHeader.emoji, - owners: spaceHeader.owners !== undefined ? spaceHeader.owners.map((email) => this.findAccountByEmail(email)) : [], + owners: spaceHeader.owners !== undefined ? spaceHeader.owners.map((email) => this.getSocialIdByEmail(email)) : [], members: - spaceHeader.members !== undefined ? spaceHeader.members.map((email) => this.findAccountByEmail(email)) : [], + spaceHeader.members !== undefined ? spaceHeader.members.map((email) => this.getSocialIdByEmail(email)) : [], docs: [] } } @@ -819,11 +823,11 @@ export class UnifiedFormatImporter { private: spaceHeader.private ?? false, archived: spaceHeader.archived ?? false, description: spaceHeader.description, - owners: spaceHeader.owners?.map((email) => this.findAccountByEmail(email)) ?? [], - members: spaceHeader.members?.map((email) => this.findAccountByEmail(email)) ?? [], - qualified: spaceHeader.qualified !== undefined ? this.findAccountByEmail(spaceHeader.qualified) : undefined, - manager: spaceHeader.manager !== undefined ? this.findAccountByEmail(spaceHeader.manager) : undefined, - qara: spaceHeader.qara !== undefined ? this.findAccountByEmail(spaceHeader.qara) : undefined, + owners: spaceHeader.owners?.map((email) => this.getSocialIdByEmail(email)) ?? [], + members: spaceHeader.members?.map((email) => this.getSocialIdByEmail(email)) ?? [], + qualified: spaceHeader.qualified !== undefined ? this.getSocialIdByEmail(spaceHeader.qualified) : undefined, + manager: spaceHeader.manager !== undefined ? this.getSocialIdByEmail(spaceHeader.manager) : undefined, + qara: spaceHeader.qara !== undefined ? this.getSocialIdByEmail(spaceHeader.qara) : undefined, docs: [] } } @@ -950,30 +954,18 @@ export class UnifiedFormatImporter { }, new Map()) } - private async cacheAccountsByEmails (): Promise { - // TODO: FIXME - throw new Error('Not implemented') - // const accounts = await this.client.findAll(contact.class.PersonAccount, {}) - // this.accountsByEmail = accounts.reduce((map, account) => { - // map.set(account.email, account._id) - // return map - // }, new Map()) - } - private async cacheEmployeesByName (): Promise { - // TODO: FIXME - throw new Error('Not implemented') - // this.employeesByName = (await this.client.findAll(contact.mixin.Employee, {})) - // .map((employee) => { - // return { - // _id: employee._id, - // name: employee.name.split(',').reverse().join(' ') - // } - // }) - // .reduce((refByName, employee) => { - // refByName.set(employee.name, employee._id) - // return refByName - // }, new Map()) + this.employeesByName = (await this.client.findAll(contact.mixin.Employee, {})) + .map((employee) => { + return { + _id: employee._id, + name: employee.name.split(',').reverse().join(' ') + } + }) + .reduce((refByName, employee) => { + refByName.set(employee.name, employee._id) + return refByName + }, new Map()) } private async collectFileMetadata (folderPath: string): Promise { diff --git a/packages/presentation/src/search.ts b/packages/presentation/src/search.ts index 01ab3f83ce..965f9d244f 100644 --- a/packages/presentation/src/search.ts +++ b/packages/presentation/src/search.ts @@ -32,18 +32,6 @@ export interface SearchItem { category: ObjectSearchCategory } -function findCategoryByClass ( - categories: ObjectSearchCategory[], - _class: Ref> -): ObjectSearchCategory | undefined { - for (const category of categories) { - if (category.classToSearch === _class) { - return category - } - } - return undefined -} - function packSearchResultsForListView (sections: SearchSection[]): SearchItem[] { let results: SearchItem[] = [] for (const section of sections) { @@ -63,35 +51,37 @@ function packSearchResultsForListView (sections: SearchSection[]): SearchItem[] async function searchCategory ( client: TxOperations, - cl: Ref>, + category: ObjectSearchCategory, query: string, - categories: ObjectSearchCategory[], limit?: number ): Promise { + if (category.classToSearch === undefined) return + const classes = + category.includeChilds === true + ? client.getHierarchy().getDescendants(category.classToSearch) + : [category.classToSearch] const r = await client.searchFulltext( { query: `${query}*`, - classes: [cl] + classes }, { limit: limit ?? 5 } ) - const category = findCategoryByClass(categories, cl) - return category !== undefined ? { category, items: r.docs } : undefined + return { category, items: r.docs } } async function doFulltextSearch ( client: TxOperations, - classes: Array>>, - query: string, categories: ObjectSearchCategory[], + query: string, limit?: number ): Promise { const sections: SearchSection[] = [] const promises: Array> = [] - for (const cl of classes) { - promises.push(searchCategory(client, cl, query, categories, limit)) + for (const cat of categories) { + promises.push(searchCategory(client, cat, query, limit)) } const resolvedSections = await Promise.all(promises) @@ -140,6 +130,6 @@ export async function searchFor ( } } - const sections = await doFulltextSearch(client, classesToSearch, query, categories, limit) + const sections = await doFulltextSearch(client, cats, query, limit) return { items: packSearchResultsForListView(sections), query } } diff --git a/packages/presentation/src/types.ts b/packages/presentation/src/types.ts index 9e9a09b5f2..0dbcd69ac3 100644 --- a/packages/presentation/src/types.ts +++ b/packages/presentation/src/types.ts @@ -72,6 +72,7 @@ export interface ObjectSearchCategory extends Doc { // Query for documents with pattern query: Resource classToSearch?: Ref> + includeChilds?: boolean priority?: number } diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index d219db9530..4f8cd2c5c0 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -15,6 +15,7 @@ import { Analytics } from '@hcengineering/analytics' import core, { + Association, BulkUpdateEvent, Class, Client, @@ -30,6 +31,7 @@ import core, { Mixin, ModelDb, Ref, + Relation, ReverseLookups, SearchOptions, SearchQuery, @@ -659,6 +661,7 @@ export class LiveQuery implements WithTx, Client { } } await this.handleDocUpdateLookup(q, tx) + await this.handleDocUpdateRelation(q, tx) } } return {} @@ -724,6 +727,50 @@ export class LiveQuery implements WithTx, Client { return } await this.handleDocUpdateLookup(q, tx) + await this.handleDocUpdateRelation(q, tx) + } + + private isPossibleAssociationTx (tx: TxUpdateDoc | TxMixin, association: Association): boolean { + const h = this.getHierarchy() + const byClass = + h.isDerived(tx.objectClass, association.classA) || + h.isDerived(tx.objectClass, association.classB) || + h.isDerived(association.classA, tx.objectClass) || + h.isDerived(association.classB, tx.objectClass) + if (byClass) { + return true + } + if (tx._class === core.class.TxMixin) { + const mixinTx = tx as TxMixin + return h.isDerived(mixinTx.mixin, association.classA) || h.isDerived(mixinTx.mixin, association.classB) + } + return false + } + + private async handleDocUpdateRelation (q: Query, tx: TxUpdateDoc | TxMixin): Promise { + if (q.options?.associations === undefined) return + for (const assoc of q.options.associations) { + const association = this.getModel().findObject(assoc[0]) + if (association === undefined) continue + if (this.isPossibleAssociationTx(tx, association)) { + if (q.result instanceof Promise) { + q.result = await q.result + } + const docs = q.result.getDocs() + for (const doc of docs) { + const docToUpdate = doc.$associations?.[association._id].find((it) => it._id === tx.objectId) + if (docToUpdate !== undefined) { + if (tx._class === core.class.TxMixin) { + TxProcessor.updateMixin4Doc(docToUpdate, tx as TxMixin) + } else { + TxProcessor.updateDoc2Doc(docToUpdate, tx as TxUpdateDoc) + } + q.result.updateDoc(doc, false) + this.queriesToUpdate.set(q.id, q) + } + } + } + } } private async handleDocUpdateLookup (q: Query, tx: TxUpdateDoc | TxMixin): Promise { @@ -971,6 +1018,7 @@ export class LiveQuery implements WithTx, Client { } await this.handleDocAddLookup(q, doc) + await this.handleDocAddRelation(q, doc) } } return {} @@ -1039,6 +1087,35 @@ export class LiveQuery implements WithTx, Client { } } + private async handleDocAddRelation (q: Query, doc: Doc): Promise { + if (q.options?.associations === undefined) return + if (doc._class !== core.class.Relation) return + const relation = doc as Relation + const assoc = q.options.associations.find((p) => p[0] === relation.association) + if (assoc !== undefined) { + if (q.result instanceof Promise) { + q.result = await q.result + } + const direct = assoc[1] === 1 + const res = q.result.findDoc(direct ? relation.docA : relation.docB) + if (res === undefined) return + const association = this.getModel().findObject(assoc[0]) + if (association === undefined) return + const docToPush = await this.findOne(!direct ? association.classB : association.classA, { + _id: direct ? relation.docB : relation.docA + }) + if (docToPush === undefined) return + const arr = res?.$associations?.[relation.association] ?? [] + arr.push(docToPush) + if (res?.$associations === undefined) { + res.$associations = {} + } + res.$associations[relation.association] = arr + q.result.updateDoc(res, false) + this.queriesToUpdate.set(q.id, q) + } + } + private async handleDocAddLookup (q: Query, doc: Doc): Promise { if (q.options?.lookup === undefined) return const lookup = q.options.lookup @@ -1120,16 +1197,16 @@ export class LiveQuery implements WithTx, Client { if (q.result instanceof Promise) { q.result = await q.result } - if ( - q.options?.limit !== undefined && - q.options.limit === q.result.length && - h.isDerived(q._class, tx.objectClass) - ) { - await this.refresh(q) - return - } const index = q.result.getDocs().find((p) => p._id === tx.objectId && h.isDerived(p._class, tx.objectClass)) if (index !== undefined) { + if ( + q.options?.limit !== undefined && + q.options.limit === q.result.length && + h.isDerived(q._class, tx.objectClass) + ) { + await this.refresh(q) + return + } q.result.delete(index._id) this.refs.updateDocuments(q, [index], true) @@ -1139,6 +1216,13 @@ export class LiveQuery implements WithTx, Client { await this.callback(q, true) } await this.handleDocRemoveLookup(q, tx) + await this.handleDocRemoveRelation(q, tx) + } + + private async handleDocRemoveRelation (q: Query, tx: TxRemoveDoc): Promise { + if (q.options?.associations === undefined) return + if (tx.objectClass !== core.class.Relation) return + await this.refresh(q) } private async handleDocRemoveLookup (q: Query, tx: TxRemoveDoc): Promise { diff --git a/packages/query/src/results.ts b/packages/query/src/results.ts index f9b2dbfe44..bc10576de8 100644 --- a/packages/query/src/results.ts +++ b/packages/query/src/results.ts @@ -1,5 +1,6 @@ import { resultSort, + WithLookup, type Class, type Doc, type Hierarchy, @@ -9,9 +10,9 @@ import { } from '@hcengineering/core' export class ResultArray { - private docs: Map, Doc> + private docs: Map, WithLookup> - private readonly clones = new Map, Doc>>() + private readonly clones = new Map, WithLookup>>() get length (): number { return this.docs.size @@ -28,11 +29,11 @@ export class ResultArray { this.clones.clear() } - getDocs (): Doc[] { + getDocs (): WithLookup[] { return Array.from(this.docs.values()) } - findDoc (_id: Ref): Doc | undefined { + findDoc (_id: Ref): WithLookup | undefined { return this.docs.get(_id) } @@ -61,14 +62,14 @@ export class ResultArray { return doc } - updateDoc (doc: Doc, mainClone = true): void { + updateDoc (doc: WithLookup, mainClone = true): void { this.docs.set(doc._id, mainClone ? this.hierarchy.clone(doc) : doc) for (const [, v] of this.clones.entries()) { v.set(doc._id, this.hierarchy.clone(doc)) } } - push (doc: Doc): void { + push (doc: WithLookup): void { this.docs.set(doc._id, this.hierarchy.clone(doc)) for (const [, v] of this.clones.entries()) { v.set(doc._id, this.hierarchy.clone(doc)) @@ -76,7 +77,7 @@ export class ResultArray { // this.changes.add(doc._id) } - pop (): Doc | undefined { + pop (): WithLookup | undefined { const lastElement = Array.from(this.docs)[this.docs.size - 1] if (lastElement !== undefined) { this.docs.delete(lastElement[0]) diff --git a/packages/ui/src/components/Breadcrumbs.svelte b/packages/ui/src/components/Breadcrumbs.svelte index 4f7cc3c84b..c49d0ca9a3 100644 --- a/packages/ui/src/components/Breadcrumbs.svelte +++ b/packages/ui/src/components/Breadcrumbs.svelte @@ -13,12 +13,12 @@ // limitations under the License. --> + +
+ +
diff --git a/packages/ui/src/components/NestedMenu.svelte b/packages/ui/src/components/NestedMenu.svelte new file mode 100644 index 0000000000..c2e0464e23 --- /dev/null +++ b/packages/ui/src/components/NestedMenu.svelte @@ -0,0 +1,119 @@ + + + +
dispatch('changeContent')}> +