mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-11 04:07:43 +02:00
v0.6.276
Merge remote-tracking branch 'origin/develop' Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Vendored
+27
-1
@@ -60,6 +60,7 @@
|
||||
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
|
||||
"runtimeVersion": "20",
|
||||
"showAsyncStacks": true,
|
||||
"outputCapture": "std",
|
||||
"sourceMaps": true,
|
||||
"cwd": "${workspaceRoot}/pods/server",
|
||||
"protocol": "inspector"
|
||||
@@ -75,6 +76,7 @@
|
||||
"TRANSACTOR_URL": "ws://localhost:3333",
|
||||
"ACCOUNT_PORT": "3000",
|
||||
"FRONT_URL": "http://localhost:8080",
|
||||
"outputCapture": "std",
|
||||
"SES_URL": "http://localhost:8091",
|
||||
"MINIO_ACCESS_KEY": "minioadmin",
|
||||
"MINIO_SECRET_KEY": "minioadmin",
|
||||
@@ -186,12 +188,13 @@
|
||||
"name": "Debug tool upgrade",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": ["src/__start.ts", "upgrade"],
|
||||
"args": ["src/__start.ts", "upgrade-workspace", "platform"],
|
||||
"env": {
|
||||
"SERVER_SECRET": "secret",
|
||||
"MINIO_ACCESS_KEY": "minioadmin",
|
||||
"MINIO_SECRET_KEY": "minioadmin",
|
||||
"MINIO_ENDPOINT": "localhost",
|
||||
"TRANSACTOR_URL": "ws://localhost:3333",
|
||||
"MONGO_URL": "mongodb://localhost:27017",
|
||||
"ACCOUNTS_URL": "http://localhost:3000",
|
||||
"TELEGRAM_DATABASE": "telegram-service",
|
||||
@@ -386,6 +389,29 @@
|
||||
"showAsyncStacks": true,
|
||||
"outputCapture": "std",
|
||||
"cwd": "${workspaceRoot}/services/analytics-collector/pod-analytics-collector"
|
||||
},
|
||||
{
|
||||
"name": "Debug AI bot",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": ["src/index.ts"],
|
||||
"env": {
|
||||
"ACCOUNTS_URL": "http://localhost:3000",
|
||||
"MONGO_URL": "mongodb://localhost:27017",
|
||||
"PORT": "4008",
|
||||
"SERVER_SECRET": "secret",
|
||||
"SUPPORT_WORKSPACE": "support",
|
||||
"FIRST_NAME": "Jolie",
|
||||
"LAST_NAME": "AI",
|
||||
"PASSWORD": "password",
|
||||
"AVATAR_PATH": "./assets/avatar.png",
|
||||
"AVATAR_CONTENT_TYPE": ".png"
|
||||
},
|
||||
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
|
||||
"sourceMaps": true,
|
||||
"cwd": "${workspaceRoot}/services/ai-bot/pod-ai-bot",
|
||||
"protocol": "inspector",
|
||||
"outputCapture": "std"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
"summary": "Build docker with platform",
|
||||
"description": "use to build all docker containers required for platform",
|
||||
"safeForSimultaneousRushProcesses": true,
|
||||
"shellCommand": "rush docker:build -p 20 --to @hcengineering/pod-server --to @hcengineering/pod-front --to @hcengineering/prod --to @hcengineering/pod-account --to @hcengineering/pod-collaborator --to @hcengineering/tool --to @hcengineering/pod-print --to @hcengineering/pod-sign --to @hcengineering/pod-analytics-collector --to @hcengineering/rekoni-service"
|
||||
"shellCommand": "rush docker:build -p 20 --to @hcengineering/pod-server --to @hcengineering/pod-front --to @hcengineering/prod --to @hcengineering/pod-account --to @hcengineering/pod-collaborator --to @hcengineering/tool --to @hcengineering/pod-print --to @hcengineering/pod-sign --to @hcengineering/pod-analytics-collector --to @hcengineering/rekoni-service --to @hcengineering/pod-ai-bot"
|
||||
},
|
||||
{
|
||||
"commandKind": "global",
|
||||
|
||||
Generated
+222
-14
@@ -71,6 +71,9 @@ dependencies:
|
||||
'@rush-temp/activity-resources':
|
||||
specifier: file:./projects/activity-resources.tgz
|
||||
version: file:projects/activity-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/ai-bot':
|
||||
specifier: file:./projects/ai-bot.tgz
|
||||
version: file:projects/ai-bot.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/analytics':
|
||||
specifier: file:./projects/analytics.tgz
|
||||
version: file:projects/analytics.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
@@ -407,6 +410,9 @@ dependencies:
|
||||
'@rush-temp/model-server-activity':
|
||||
specifier: file:./projects/model-server-activity.tgz
|
||||
version: file:projects/model-server-activity.tgz
|
||||
'@rush-temp/model-server-ai-bot':
|
||||
specifier: file:./projects/model-server-ai-bot.tgz
|
||||
version: file:projects/model-server-ai-bot.tgz
|
||||
'@rush-temp/model-server-attachment':
|
||||
specifier: file:./projects/model-server-attachment.tgz
|
||||
version: file:projects/model-server-attachment.tgz
|
||||
@@ -572,6 +578,9 @@ dependencies:
|
||||
'@rush-temp/pod-account':
|
||||
specifier: file:./projects/pod-account.tgz
|
||||
version: file:projects/pod-account.tgz
|
||||
'@rush-temp/pod-ai-bot':
|
||||
specifier: file:./projects/pod-ai-bot.tgz
|
||||
version: file:projects/pod-ai-bot.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
'@rush-temp/pod-analytics-collector':
|
||||
specifier: file:./projects/pod-analytics-collector.tgz
|
||||
version: file:projects/pod-analytics-collector.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
@@ -701,6 +710,12 @@ dependencies:
|
||||
'@rush-temp/server-activity-resources':
|
||||
specifier: file:./projects/server-activity-resources.tgz
|
||||
version: file:projects/server-activity-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/server-ai-bot':
|
||||
specifier: file:./projects/server-ai-bot.tgz
|
||||
version: file:projects/server-ai-bot.tgz(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/server-ai-bot-resources':
|
||||
specifier: file:./projects/server-ai-bot-resources.tgz
|
||||
version: file:projects/server-ai-bot-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/server-analytics-collector':
|
||||
specifier: file:./projects/server-analytics-collector.tgz
|
||||
version: file:projects/server-analytics-collector.tgz(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
@@ -1271,6 +1286,9 @@ dependencies:
|
||||
'@types/qs':
|
||||
specifier: ~6.9.7
|
||||
version: 6.9.11
|
||||
'@types/querystringify':
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2
|
||||
'@types/request':
|
||||
specifier: ~2.48.8
|
||||
version: 2.48.12
|
||||
@@ -1694,6 +1712,9 @@ dependencies:
|
||||
qs:
|
||||
specifier: ~6.11.0
|
||||
version: 6.11.2
|
||||
querystringify:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
react:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0
|
||||
@@ -9307,6 +9328,10 @@ packages:
|
||||
resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==}
|
||||
dev: false
|
||||
|
||||
/@types/querystringify@2.0.2:
|
||||
resolution: {integrity: sha512-7d6OQK6pJ//zE32XLK3vI6GHYhBDcYooaRco9cKFGNu59GVatL5+u7rkiAViq44DxDTd/7QQNBWSDHfJGBz/Pw==}
|
||||
dev: false
|
||||
|
||||
/@types/range-parser@1.2.7:
|
||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||
dev: false
|
||||
@@ -23758,7 +23783,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/account-service.tgz:
|
||||
resolution: {integrity: sha512-m2wnBUxpiATGM4uSuNprCebldYmLYweixWs/lkbmn2oxzV797WaTrigIQEEPowYOydBskozS7uc/PgBj9WhkCw==, tarball: file:projects/account-service.tgz}
|
||||
resolution: {integrity: sha512-ezhFLrsQ8CjpPUIvobegFaStE0c6PJyHqd4V8731uyNwVe+Vhm+Wx5Qoa/VOVqdCWOixjZdP9sBWILsRU9nKkA==, tarball: file:projects/account-service.tgz}
|
||||
name: '@rush-temp/account-service'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
@@ -23961,6 +23986,37 @@ packages:
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/ai-bot.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-TH/kDh1LKw+pJRxLZZIjR7da6BQslR9S9Uy9HHXDtvtu5es55OmjRZEWPUnkBjKRmY6hTPBmaO4veq7RiaNz7g==, tarball: file:projects/ai-bot.tgz}
|
||||
id: file:projects/ai-bot.tgz
|
||||
name: '@rush-temp/ai-bot'
|
||||
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.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint: 8.56.0
|
||||
eslint-config-prettier: 8.10.0(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.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)
|
||||
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.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/analytics-collector-assets.tgz(esbuild@0.20.1)(svelte@4.2.12)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-ThEhCV2dJchrcM0mfUjNFdD0/qOzl3qC7glianWUl4Qsj03IrYyjbxvdsV7Fy/49UhQ+YUt46X39kgIWVBnWiw==, tarball: file:projects/analytics-collector-assets.tgz}
|
||||
id: file:projects/analytics-collector-assets.tgz
|
||||
@@ -24236,7 +24292,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/auth-providers.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-ixfEzxmzLbrHghRymDcvdyz35q9DsDnA1qqheztJNa2zLH5102sfEMEooVLShU3cD+uf/KhNbcTyea1on8GlfA==, tarball: file:projects/auth-providers.tgz}
|
||||
resolution: {integrity: sha512-5ii9QDKZ+v5awKhzsUOf7Y83PSCUzX6BKFZjY21w8oy+pJRZPTVbKYJhQC4i1AuvahXCObkMbCc3ljs0L+vgIw==, tarball: file:projects/auth-providers.tgz}
|
||||
id: file:projects/auth-providers.tgz
|
||||
name: '@rush-temp/auth-providers'
|
||||
version: 0.0.0
|
||||
@@ -24249,6 +24305,7 @@ packages:
|
||||
'@types/node-fetch': 2.6.11
|
||||
'@types/passport-github2': 1.2.9
|
||||
'@types/passport-google-oauth20': 2.0.14
|
||||
'@types/querystringify': 2.0.2
|
||||
'@types/ws': 8.5.11
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
@@ -24268,6 +24325,7 @@ packages:
|
||||
passport-google-oauth20: 2.0.0
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.1(prettier@3.2.5)(svelte@4.2.11)
|
||||
querystringify: 2.2.0
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
@@ -25340,7 +25398,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-Zqlhi9UprYvF9L0ANw8sSkxTuqMYWTDmIUV6wYDTHd+NMt8NKshXy9J39mll8dW0h93TeY538RePwutrdvM4kA==, tarball: file:projects/desktop.tgz}
|
||||
resolution: {integrity: sha512-j8onQxy51K29b/9q8g+lOG8e8dOFO2WpQQTdtnhP2vy2EcvIuSgckenQpg++0r1AtJ1G7FC7hr5QYNsrTPWkBA==, tarball: file:projects/desktop.tgz}
|
||||
id: file:projects/desktop.tgz
|
||||
name: '@rush-temp/desktop'
|
||||
version: 0.0.0
|
||||
@@ -26601,7 +26659,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/lead-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-YFe9zCBoR5pPRxsoG3Oc9qVVHEWGDlmQrw27HY+3P0SMBXz8xWVjgM6SrL2458y83t/Xsj30krK1zEZkWORfpQ==, tarball: file:projects/lead-resources.tgz}
|
||||
resolution: {integrity: sha512-DIL0rCz2r3nKYgE2fOrEdVSwLGq1Zz2MjsU1HvDxnIs4IE1Q4s8oNMBtvtunERIQ2fNnJHcE0XXijawtYilrjQ==, tarball: file:projects/lead-resources.tgz}
|
||||
id: file:projects/lead-resources.tgz
|
||||
name: '@rush-temp/lead-resources'
|
||||
version: 0.0.0
|
||||
@@ -26820,7 +26878,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/love-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-+jxDfVCF8l8WnKd4Xmaau521zbt9KBRubhiB6N8gXjePkAFSiFXdiQGPnB7VGyYLnImqDuCCnfQNJJpomb4TNQ==, tarball: file:projects/love-resources.tgz}
|
||||
resolution: {integrity: sha512-e49VrhVkk6U8nj/ZyKfYVj/gK/3rTSrVCicDM5Luxw/f/8pPEVf9uEzmdAV11uiXuXxmj5t0BmHdG5eeVhiK6A==, tarball: file:projects/love-resources.tgz}
|
||||
id: file:projects/love-resources.tgz
|
||||
name: '@rush-temp/love-resources'
|
||||
version: 0.0.0
|
||||
@@ -26868,7 +26926,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/love.tgz(@types/node@20.11.19)(esbuild@0.20.1)(svelte@4.2.12)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-qWAfcld2pm2sf/2kZM1RLYGnhIJWRC42pBsrjQUmztuosCriG9qFa8fdymEsTp4TJaFG9zAqlci7/NKHN9ldvA==, tarball: file:projects/love.tgz}
|
||||
resolution: {integrity: sha512-IA1DOwfYE00ACQ47zgXq3yOcNghk1oU1nPcq15bqdjOxJeKaE5sa4w/yJ7WoGn1Dm5F0TmxKc67GGDxcTT6kDQ==, tarball: file:projects/love.tgz}
|
||||
id: file:projects/love.tgz
|
||||
name: '@rush-temp/love'
|
||||
version: 0.0.0
|
||||
@@ -27347,7 +27405,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/model-love.tgz:
|
||||
resolution: {integrity: sha512-iYxy2iQSrCHIlzZLKrDvP5yGrpJrVopD79gegg6iVsqnDbRqrTbsN2H69Xn1KeDbOJllKgVw5y8yVFO+AMq41Q==, tarball: file:projects/model-love.tgz}
|
||||
resolution: {integrity: sha512-vHa71QNYOwrIifwIvVUmNWd+qlSgxZ0ErEgrx9uBSnJCxff9iqRhtmrFlfJ27bvi/jiBWOro9XYt5liL7gOGhg==, tarball: file:projects/model-love.tgz}
|
||||
name: '@rush-temp/model-love'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
@@ -27550,6 +27608,24 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/model-server-ai-bot.tgz:
|
||||
resolution: {integrity: sha512-eo56EIdT6JLS0upi95IDRPBEXyASWLEpUdH9cfK2lLtpslJYlJkRPSqImEA5xk1fUUwexRPqVPW+bYFoIMsUxQ==, tarball: file:projects/model-server-ai-bot.tgz}
|
||||
name: '@rush-temp/model-server-ai-bot'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
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.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)
|
||||
prettier: 3.2.5
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/model-server-attachment.tgz:
|
||||
resolution: {integrity: sha512-F45oxBvR4Gh7Y70CqozTOyXQ/lWOkP/EDURRVxxETMWbtXej37/QCtWXlLJ2YNWmoG6ildVMOZlK/IaMSdU9mA==, tarball: file:projects/model-server-attachment.tgz}
|
||||
name: '@rush-temp/model-server-attachment'
|
||||
@@ -28588,7 +28664,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/onboard-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(file-loader@6.2.0)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2)(webpack@5.90.3):
|
||||
resolution: {integrity: sha512-3Gt9PEcA7T44mLBBC0KwwZQ6Qs7pXYbqQaagWFjfT+4MTvR9XVk4L+67U0yFYqpS/EeODSc+dJklk3QBY2O36g==, tarball: file:projects/onboard-resources.tgz}
|
||||
resolution: {integrity: sha512-xbIj2phiY1rWzXxo5gqyucDzJS7IKMWhgTS4qZ5V9Rh02mCECL2Fs6N5OiiHFJH66jllxThPdX7SIDNBVPcfmA==, tarball: file:projects/onboard-resources.tgz}
|
||||
id: file:projects/onboard-resources.tgz
|
||||
name: '@rush-temp/onboard-resources'
|
||||
version: 0.0.0
|
||||
@@ -28849,6 +28925,62 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/pod-ai-bot.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-5Upjw52FvxxuZY9eSN8N5FUKoNMhqME7DwEAp4TTQEKR/Rs+Fnxi7S5ZQ6G2G40RmZ0F0mWfXfWTcyhFlyio5Q==, tarball: file:projects/pod-ai-bot.tgz}
|
||||
id: file:projects/pod-ai-bot.tgz
|
||||
name: '@rush-temp/pod-ai-bot'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/cors': 2.8.17
|
||||
'@types/express': 4.17.21
|
||||
'@types/jest': 29.5.12
|
||||
'@types/node': 20.11.19
|
||||
'@types/node-fetch': 2.6.11
|
||||
'@types/ws': 8.5.11
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
cors: 2.8.5
|
||||
dotenv: 16.0.3
|
||||
esbuild: 0.20.1
|
||||
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.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-node: 11.1.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
express: 4.19.2
|
||||
fast-equals: 5.0.1
|
||||
form-data: 4.0.0
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
mongodb: 6.8.0
|
||||
node-fetch: 2.7.0
|
||||
prettier: 3.2.5
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
ts-node: 10.9.2(@types/node@20.11.19)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/credential-providers'
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@mongodb-js/zstd'
|
||||
- '@swc/core'
|
||||
- '@swc/wasm'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- bufferutil
|
||||
- encoding
|
||||
- gcp-metadata
|
||||
- kerberos
|
||||
- mongodb-client-encryption
|
||||
- node-notifier
|
||||
- snappy
|
||||
- socks
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
file:projects/pod-analytics-collector.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-Sx9mTOCsgDTcoC8h9VXeemVHerKLMDzdW4aJ08fdsF9UA35tLWmbDXw+fn3gPUNj2l+QT5ExEF9rV1Iez1FIbw==, tarball: file:projects/pod-analytics-collector.tgz}
|
||||
id: file:projects/pod-analytics-collector.tgz
|
||||
@@ -28930,7 +29062,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/pod-calendar.tgz(bufferutil@4.0.8)(ts-node@10.9.2)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-DOvMMTPpDOAuO8Vi8gEBTXBMQATYdZgtNWxvUyG0xbCArW9jEmKbrOVBV1ydZGOJqfqhennjv09+uWR/YUR+SQ==, tarball: file:projects/pod-calendar.tgz}
|
||||
resolution: {integrity: sha512-rnCLCkBGWm2o9YTk6AnoYlNCACtncXiYw+CUkhVFJmBNTE1l90C74Uci4ldJBpxEOyCHVBzJIjsp6sMbQwafkw==, tarball: file:projects/pod-calendar.tgz}
|
||||
id: file:projects/pod-calendar.tgz
|
||||
name: '@rush-temp/pod-calendar'
|
||||
version: 0.0.0
|
||||
@@ -29160,7 +29292,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/pod-gmail.tgz(bufferutil@4.0.8)(ts-node@10.9.2)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-ybpB+uVlKzWvEVZnrp6iPuDYR7OwWBEsHl3ivSmte8BhfH9Q5QfzBm/FrEUsyEBIN4KS/cGDUoNGv5Us5OVWVw==, tarball: file:projects/pod-gmail.tgz}
|
||||
resolution: {integrity: sha512-qeyt7Pl1TwEo/JojBg4R4LR3uWEdxOfqfz6tYB5kB27oEdE+jBJx0LGgsrDYoQSsv7A0LLnaFVfS+XT17EoKeQ==, tarball: file:projects/pod-gmail.tgz}
|
||||
id: file:projects/pod-gmail.tgz
|
||||
name: '@rush-temp/pod-gmail'
|
||||
version: 0.0.0
|
||||
@@ -29448,7 +29580,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/pod-telegram.tgz(bufferutil@4.0.8)(ts-node@10.9.2)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-mBbMXZhgRl0R9gvFN+uxfdFHgXdF9cFyC200rXnS4PgGkGVm9jRmE8lJQTxiOOJyX8rPDm8qlLhCrlKyof+pEQ==, tarball: file:projects/pod-telegram.tgz}
|
||||
resolution: {integrity: sha512-MF+eEeVhFR4XQj2YaAP6gjvm1tijtnRUMDrQt48vZBD8mwQA8B0drOVHCkOQ+NJOYqi1c3pRG/+kPKWqswbplQ==, tarball: file:projects/pod-telegram.tgz}
|
||||
id: file:projects/pod-telegram.tgz
|
||||
name: '@rush-temp/pod-telegram'
|
||||
version: 0.0.0
|
||||
@@ -30578,6 +30710,74 @@ packages:
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/server-ai-bot-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-YOa1XOLVz87AjouR9Qn4Wkiib/9nXkIiMIW7XVzCl+lVqfdjXDRn4kjxXj363Wh8bw5Ato7kpuj0M9C1Vsh+zw==, tarball: file:projects/server-ai-bot-resources.tgz}
|
||||
id: file:projects/server-ai-bot-resources.tgz
|
||||
name: '@rush-temp/server-ai-bot-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.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
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.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)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
mongodb: 6.8.0
|
||||
prettier: 3.2.5
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/credential-providers'
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@mongodb-js/zstd'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- gcp-metadata
|
||||
- kerberos
|
||||
- mongodb-client-encryption
|
||||
- node-notifier
|
||||
- snappy
|
||||
- socks
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/server-ai-bot.tgz(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-9rB0TFsDFJ2KgmJwTCJRQG/rh+NORXysidGZq8v77VEN7Sh/xQlB33k4XgHutF3U1Bd0KUdRC/pg9grlgezIdA==, tarball: file:projects/server-ai-bot.tgz}
|
||||
id: file:projects/server-ai-bot.tgz
|
||||
name: '@rush-temp/server-ai-bot'
|
||||
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.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
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.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)
|
||||
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.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/server-analytics-collector-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-cLqoyrE7bZmjUeQSenTvg0S2XdEUUulUTMYvYephOUR5orzG71xy3Z+HgV92YapcZMzi9RVdaataHwYhxTRDPw==, tarball: file:projects/server-analytics-collector-resources.tgz}
|
||||
id: file:projects/server-analytics-collector-resources.tgz
|
||||
@@ -31756,7 +31956,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/server-pipeline.tgz:
|
||||
resolution: {integrity: sha512-DpU8h5YS6u+d1uVTSyALfcGof3p2hXuSd8f1RyFI/YvNHxLHLrTu0AzquL8uhwxliB1bpNJtCWh1RWphdVJD4Q==, tarball: file:projects/server-pipeline.tgz}
|
||||
resolution: {integrity: sha512-VMd/X1M3HotOPN51cVDAHjKrHhNm8/5GMMiZ4WklnQVtDfmDHocXKsC+FgOLXpb9RHYhtsz0Arwi7pW7xIar5A==, tarball: file:projects/server-pipeline.tgz}
|
||||
name: '@rush-temp/server-pipeline'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
@@ -32167,7 +32367,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/server-telegram-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-jlZjP4X1pBtvaMNdCcrjmyAOJeVk/AQbQUwa0f28Oc4VU6OaktCMmG+0+GvnvMVAcpjUmb2fL3rnLxI2ckB2yQ==, tarball: file:projects/server-telegram-resources.tgz}
|
||||
resolution: {integrity: sha512-4Pob/P+5sdtU7LGgb1jJbqVms72MXOpAvOZ+GivgI3j9JvqvbOfHn87O1jVhrWa865xZrdGlV9+T9grap3W3xg==, tarball: file:projects/server-telegram-resources.tgz}
|
||||
id: file:projects/server-telegram-resources.tgz
|
||||
name: '@rush-temp/server-telegram-resources'
|
||||
version: 0.0.0
|
||||
@@ -32181,18 +32381,26 @@ packages:
|
||||
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)
|
||||
mongodb: 6.8.0
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.1(prettier@3.2.5)(svelte@4.2.11)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/credential-providers'
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@mongodb-js/zstd'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- gcp-metadata
|
||||
- kerberos
|
||||
- mongodb-client-encryption
|
||||
- node-notifier
|
||||
- snappy
|
||||
- socks
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
@@ -33244,7 +33452,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/telegram-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-TakwKag4NWDevTKXic9xdAmzPjjw9ezjHVHZYyYcweVBNgloGjjVfGqfBzWyrzcuGCFJRMddfygAHqvSUsuRiQ==, tarball: file:projects/telegram-resources.tgz}
|
||||
resolution: {integrity: sha512-a2P52BNrZcs4YavNcVmsBRpfa2o2rq787sDtT2xxNqMhYn74+D3G6ZGkJGbeGJSm3GD4ZS1ELKfdrf5MXvgSkg==, tarball: file:projects/telegram-resources.tgz}
|
||||
id: file:projects/telegram-resources.tgz
|
||||
name: '@rush-temp/telegram-resources'
|
||||
version: 0.0.0
|
||||
|
||||
@@ -92,6 +92,7 @@ import '@hcengineering/training-assets'
|
||||
import '@hcengineering/products-assets'
|
||||
import '@hcengineering/controlled-documents-assets'
|
||||
import '@hcengineering/analytics-collector-assets'
|
||||
import '@hcengineering/text-editor-assets'
|
||||
|
||||
import { coreId } from '@hcengineering/core'
|
||||
import presentation, { parsePreviewConfig, presentationId } from '@hcengineering/presentation'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// preload.js
|
||||
|
||||
import { BrandingMap, Config, IPCMainExposed, NotificationParams } from './types'
|
||||
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
|
||||
/**
|
||||
@@ -18,6 +17,31 @@ export function concatLink (host: string, path: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadServerConfig (url: string): Promise<any> {
|
||||
let retries = 5
|
||||
let res: Response | undefined
|
||||
|
||||
do {
|
||||
try {
|
||||
res = await fetch(url)
|
||||
break
|
||||
} catch (e) {
|
||||
retries--
|
||||
if (retries === 0) {
|
||||
throw new Error(`Failed to load server config: ${e}`)
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000 * (5 - retries)))
|
||||
}
|
||||
} while (retries > 0)
|
||||
|
||||
if (res === undefined) {
|
||||
// In theory should never get here
|
||||
throw new Error('Failed to load server config')
|
||||
}
|
||||
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
const openArg = (process.argv.find((it) => it.startsWith('--open=')) ?? '').split('--open=')[1]
|
||||
console.log('Open passed', openArg)
|
||||
let configPromise: Promise<Config> | undefined
|
||||
@@ -41,7 +65,7 @@ const expose: IPCMainExposed = {
|
||||
configPromise = new Promise((resolve, reject) => {
|
||||
ipcRenderer.invoke('get-main-config').then(
|
||||
async (mainConfig) => {
|
||||
const serverConfig = await (await fetch(concatLink(mainConfig.FRONT_URL, mainConfig.CONFIG_URL))).json()
|
||||
const serverConfig = await loadServerConfig(concatLink(mainConfig.FRONT_URL, mainConfig.CONFIG_URL))
|
||||
const combinedConfig = {
|
||||
...serverConfig,
|
||||
...mainConfig,
|
||||
|
||||
+18
-1
@@ -213,7 +213,24 @@ services:
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 300M
|
||||
memory: 300M
|
||||
aiBot:
|
||||
image: hardcoreeng/ai-bot
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SERVER_SECRET=secret
|
||||
- MONGO_URL=mongodb://mongodb:27017
|
||||
- ACCOUNTS_URL=http://account:3000
|
||||
- SUPPORT_WORKSPACE=support
|
||||
- FIRST_NAME=Jolie
|
||||
- LAST_NAME=AI
|
||||
- PASSWORD=password
|
||||
- AVATAR_PATH=./avatar.png
|
||||
- AVATAR_CONTENT_TYPE=.png
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 300M
|
||||
volumes:
|
||||
db:
|
||||
files:
|
||||
|
||||
@@ -135,13 +135,14 @@ export interface Config {
|
||||
GITHUB_URL: string
|
||||
SENTRY_DSN?: string
|
||||
LOVE_ENDPOINT?: string
|
||||
LIVEKIT_WS?: string,
|
||||
SIGN_URL?: string,
|
||||
PRINT_URL?: string,
|
||||
POSTHOG_API_KEY?: string,
|
||||
LIVEKIT_WS?: string
|
||||
SIGN_URL?: string
|
||||
PRINT_URL?: string
|
||||
POSTHOG_API_KEY?: string
|
||||
POSTHOG_HOST?: string
|
||||
ANALYTICS_COLLECTOR_URL?:string
|
||||
BRANDING_URL?: string
|
||||
TELEGRAM_BOT_URL?: string
|
||||
|
||||
// Could be defined for dev environment
|
||||
FRONT_URL?: string
|
||||
@@ -301,6 +302,7 @@ export async function configurePlatform() {
|
||||
setMetadata(presentation.metadata.FrontVersion, config.VERSION)
|
||||
}
|
||||
setMetadata(telegram.metadata.TelegramURL, config.TELEGRAM_URL ?? 'http://localhost:8086')
|
||||
setMetadata(telegram.metadata.BotUrl, config.TELEGRAM_BOT_URL)
|
||||
setMetadata(gmail.metadata.GmailURL, config.GMAIL_URL ?? 'http://localhost:8087')
|
||||
setMetadata(calendar.metadata.CalendarServiceURL, config.CALENDAR_URL ?? 'http://localhost:8095')
|
||||
setMetadata(notification.metadata.PushPublicKey, config.PUSH_PUBLIC_KEY)
|
||||
|
||||
@@ -133,6 +133,8 @@
|
||||
"@hcengineering/server-guest-resources": "^0.6.0",
|
||||
"@hcengineering/server-time": "^0.6.0",
|
||||
"@hcengineering/server-time-resources": "^0.6.0",
|
||||
"@hcengineering/server-ai-bot": "^0.6.0",
|
||||
"@hcengineering/server-ai-bot-resources": "^0.6.0",
|
||||
"@hcengineering/setting": "^0.6.17",
|
||||
"@hcengineering/tags": "^0.6.16",
|
||||
"@hcengineering/task": "^0.6.20",
|
||||
|
||||
@@ -44,6 +44,7 @@ import { serverTelegramId } from '@hcengineering/server-telegram'
|
||||
import { serverTimeId } from '@hcengineering/server-time'
|
||||
import { serverTrackerId } from '@hcengineering/server-tracker'
|
||||
import { serverViewId } from '@hcengineering/server-view'
|
||||
import { serverAiBotId } from '@hcengineering/server-ai-bot'
|
||||
|
||||
addLocation(serverActivityId, () => import('@hcengineering/server-activity-resources'))
|
||||
addLocation(serverAttachmentId, () => import('@hcengineering/server-attachment-resources'))
|
||||
@@ -68,6 +69,7 @@ addLocation(serverDocumentId, () => import('@hcengineering/server-document-resou
|
||||
addLocation(serverTimeId, () => import('@hcengineering/server-time-resources'))
|
||||
addLocation(serverGuestId, () => import('@hcengineering/server-guest-resources'))
|
||||
addLocation(serverDriveId, () => import('@hcengineering/server-drive-resources'))
|
||||
addLocation(serverAiBotId, () => import('@hcengineering/server-ai-bot-resources'))
|
||||
|
||||
function prepareTools (): {
|
||||
mongodbUri: string
|
||||
|
||||
@@ -1242,7 +1242,7 @@ async function updateId (
|
||||
stages: {},
|
||||
removed: false
|
||||
})
|
||||
await txop.update(docIndexState, { removed: true })
|
||||
await txop.update(docIndexState, { removed: true, needIndex: true })
|
||||
}
|
||||
|
||||
if (domain !== DOMAIN_MODEL) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
tryMigrate
|
||||
} from '@hcengineering/model'
|
||||
import { htmlToMarkup } from '@hcengineering/text'
|
||||
import contact from '@hcengineering/contact'
|
||||
|
||||
import activity from './plugin'
|
||||
import { activityId, DOMAIN_ACTIVITY } from './index'
|
||||
@@ -197,6 +198,16 @@ export const activityOperation: MigrateOperation = {
|
||||
({ attachedToClass }) => attachedToClass
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'migrate-employee-space-v1',
|
||||
func: async () => {
|
||||
await client.update<ActivityMessage>(
|
||||
DOMAIN_ACTIVITY,
|
||||
{ space: 'contact:space:Employee' as Ref<Space> },
|
||||
{ space: contact.space.Contacts }
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
},
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"@hcengineering/model-server-products": "^0.1.0",
|
||||
"@hcengineering/model-server-training": "^0.1.0",
|
||||
"@hcengineering/model-server-controlled-documents": "^0.1.0",
|
||||
"@hcengineering/model-analytics-collector": "^0.6.0"
|
||||
"@hcengineering/model-analytics-collector": "^0.6.0",
|
||||
"@hcengineering/model-server-ai-bot": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ import { serverTelegramId, createModel as serverTelegramModel } from '@hcenginee
|
||||
import { serverTemplatesId, createModel as serverTemplatesModel } from '@hcengineering/model-server-templates'
|
||||
import { serverTrackerId, createModel as serverTrackerModel } from '@hcengineering/model-server-tracker'
|
||||
import { serverViewId, createModel as serverViewModel } from '@hcengineering/model-server-view'
|
||||
import { serverAiBotId, createModel as serverAiBotModel } from '@hcengineering/model-server-ai-bot'
|
||||
import setting, { settingId, createModel as settingModel } from '@hcengineering/model-setting'
|
||||
import { driveId, createModel as driveModel } from '@hcengineering/model-drive'
|
||||
import { supportId, createModel as supportModel } from '@hcengineering/model-support'
|
||||
@@ -424,7 +425,8 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[
|
||||
[serverDriveModel, serverDriveId],
|
||||
[serverProductsModel, serverProductsId],
|
||||
[serverTrainingModel, serverTrainingId],
|
||||
[serverDocumentsModel, serverDocumentsId]
|
||||
[serverDocumentsModel, serverDocumentsId],
|
||||
[serverAiBotModel, serverAiBotId]
|
||||
]
|
||||
|
||||
for (const [b, id, config] of builders) {
|
||||
|
||||
+43
-106
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
||||
import activity, { type ActivityMessage, type ActivityMessageControl } from '@hcengineering/activity'
|
||||
import {
|
||||
type Channel,
|
||||
chunterId,
|
||||
@@ -62,6 +62,7 @@ import { type DocNotifyContext } from '@hcengineering/notification'
|
||||
|
||||
import chunter from './plugin'
|
||||
import { defineActions } from './actions'
|
||||
import { defineNotifications } from './notifications'
|
||||
|
||||
export { chunterId } from '@hcengineering/chunter'
|
||||
export { chunterOperation } from './migration'
|
||||
@@ -197,37 +198,14 @@ export function createModel (builder: Builder): void {
|
||||
titleProvider: chunter.function.ChannelTitleProvider
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||
fields: ['members']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||
fields: ['members']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.ObjectPresenter, {
|
||||
presenter: chunter.component.DmPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, notification.mixin.NotificationPreview, {
|
||||
presenter: chunter.component.ChannelPreview
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.ObjectPresenter, {
|
||||
presenter: chunter.component.ChannelPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.ChatMessage, core.class.Class, notification.mixin.NotificationContextPresenter, {
|
||||
labelPresenter: chunter.component.ChatMessageNotificationLabel
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, {
|
||||
messageMatch: {
|
||||
_class: chunter.class.ThreadMessage
|
||||
},
|
||||
presenter: chunter.component.ThreadNotificationPresenter
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.SpaceHeader, {
|
||||
header: chunter.component.DmHeader
|
||||
})
|
||||
@@ -284,78 +262,6 @@ export function createModel (builder: Builder): void {
|
||||
filters: []
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ApplicationLabelChunter,
|
||||
icon: chunter.icon.Chunter
|
||||
},
|
||||
chunter.ids.ChunterNotificationGroup
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.DM,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ChatMessage,
|
||||
attachedToClass: chunter.class.DirectMessage,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{sender} has sent you a message: {doc} {message}',
|
||||
htmlTemplate: '<p><b>{sender}</b> has sent you a message {doc}</p> {message}',
|
||||
subjectTemplate: 'You have new direct message in {doc}'
|
||||
}
|
||||
},
|
||||
chunter.ids.DMNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.Message,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ChatMessage,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{sender} has sent a message in {doc}: {message}',
|
||||
htmlTemplate: '<p><b>{sender}</b> has sent a message in {doc}</p> {message}',
|
||||
subjectTemplate: 'You have new message in {doc}'
|
||||
}
|
||||
},
|
||||
chunter.ids.ChannelNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ThreadMessage,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ThreadMessage,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{body}',
|
||||
htmlTemplate: '<p>{body}</p>',
|
||||
subjectTemplate: '{title}'
|
||||
}
|
||||
},
|
||||
chunter.ids.ThreadNotification
|
||||
)
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessagesFilter, core.space.Model, {
|
||||
label: chunter.string.Comments,
|
||||
position: 60,
|
||||
@@ -419,11 +325,11 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, chunter.mixin.ObjectChatPanel, {
|
||||
ignoreKeys: ['archived', 'collaborators', 'lastMessage', 'pinned', 'topic', 'description']
|
||||
ignoreKeys: ['archived', 'collaborators', 'lastMessage', 'pinned', 'topic', 'description', 'members', 'owners']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, chunter.mixin.ObjectChatPanel, {
|
||||
ignoreKeys: ['archived', 'collaborators', 'lastMessage', 'pinned', 'topic', 'description']
|
||||
ignoreKeys: ['archived', 'collaborators', 'lastMessage', 'pinned', 'topic', 'description', 'members', 'owners']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.ChatMessage, core.class.Class, activity.mixin.ActivityMessagePreview, {
|
||||
@@ -448,19 +354,50 @@ export function createModel (builder: Builder): void {
|
||||
strict: true
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.InboxNotificationProvider,
|
||||
ignoredTypes: [],
|
||||
enabledTypes: [chunter.ids.DMNotification, chunter.ids.ChannelNotification, chunter.ids.ThreadNotification]
|
||||
builder.createDoc<ActivityMessageControl<ChunterSpace>>(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: chunter.class.Channel,
|
||||
skip: [
|
||||
{ _class: core.class.TxMixin },
|
||||
{ _class: core.class.TxCreateDoc, objectClass: { $ne: chunter.class.Channel } },
|
||||
{ _class: core.class.TxRemoveDoc }
|
||||
],
|
||||
allowedFields: ['members']
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.PushNotificationProvider,
|
||||
ignoredTypes: [],
|
||||
enabledTypes: [chunter.ids.DMNotification, chunter.ids.ChannelNotification, chunter.ids.ThreadNotification]
|
||||
builder.createDoc<ActivityMessageControl<ChunterSpace>>(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: chunter.class.DirectMessage,
|
||||
skip: [{ _class: core.class.TxMixin }, { _class: core.class.TxCreateDoc }, { _class: core.class.TxRemoveDoc }],
|
||||
allowedFields: ['members']
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.DocUpdateMessageViewlet, core.space.Model, {
|
||||
objectClass: chunter.class.Channel,
|
||||
action: 'create',
|
||||
component: chunter.activity.ChannelCreatedMessage
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.DocUpdateMessageViewlet, core.space.Model, {
|
||||
objectClass: chunter.class.Channel,
|
||||
action: 'update',
|
||||
config: {
|
||||
members: {
|
||||
presenter: chunter.activity.MembersChangedMessage
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.DocUpdateMessageViewlet, core.space.Model, {
|
||||
objectClass: chunter.class.DirectMessage,
|
||||
action: 'update',
|
||||
config: {
|
||||
members: {
|
||||
presenter: chunter.activity.MembersChangedMessage
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
defineActions(builder)
|
||||
defineNotifications(builder)
|
||||
}
|
||||
|
||||
export default chunter
|
||||
|
||||
@@ -38,20 +38,21 @@ import { DOMAIN_NOTIFICATION } from '@hcengineering/model-notification'
|
||||
|
||||
import chunter from './plugin'
|
||||
import { DOMAIN_CHUNTER } from './index'
|
||||
import { type DocUpdateMessage } from '@hcengineering/activity'
|
||||
|
||||
export const DOMAIN_COMMENT = 'comment' as Domain
|
||||
|
||||
export async function createDocNotifyContexts (
|
||||
client: MigrationUpgradeClient,
|
||||
tx: TxOperations,
|
||||
attachedTo: Ref<Doc>,
|
||||
attachedToClass: Ref<Class<Doc>>
|
||||
objectId: Ref<Doc>,
|
||||
objectClass: Ref<Class<Doc>>,
|
||||
objectSpace: Ref<Space>
|
||||
): Promise<void> {
|
||||
const users = await client.findAll(core.class.Account, {})
|
||||
const docNotifyContexts = await client.findAll(notification.class.DocNotifyContext, {
|
||||
user: { $in: users.map((it) => it._id) },
|
||||
attachedTo,
|
||||
attachedToClass
|
||||
objectId
|
||||
})
|
||||
for (const user of users) {
|
||||
if (user._id === core.account.System) {
|
||||
@@ -62,8 +63,10 @@ export async function createDocNotifyContexts (
|
||||
if (docNotifyContext === undefined) {
|
||||
await tx.createDoc(notification.class.DocNotifyContext, core.space.Space, {
|
||||
user: user._id,
|
||||
attachedTo,
|
||||
attachedToClass
|
||||
objectId,
|
||||
objectClass,
|
||||
objectSpace,
|
||||
isPinned: false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -93,7 +96,7 @@ export async function createGeneral (client: MigrationUpgradeClient, tx: TxOpera
|
||||
topic: 'General Channel',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: await getAllEmployeeAccounts(tx),
|
||||
members: await getAllPersonAccounts(tx),
|
||||
autoJoin: true
|
||||
},
|
||||
chunter.space.General
|
||||
@@ -101,10 +104,10 @@ export async function createGeneral (client: MigrationUpgradeClient, tx: TxOpera
|
||||
}
|
||||
}
|
||||
|
||||
await createDocNotifyContexts(client, tx, chunter.space.General, chunter.class.Channel)
|
||||
await createDocNotifyContexts(client, tx, chunter.space.General, chunter.class.Channel, core.space.Space)
|
||||
}
|
||||
|
||||
async function getAllEmployeeAccounts (tx: TxOperations): Promise<Ref<PersonAccount>[]> {
|
||||
async function getAllPersonAccounts (tx: TxOperations): Promise<Ref<PersonAccount>[]> {
|
||||
const employees = await tx.findAll(contactPlugin.mixin.Employee, { active: true })
|
||||
const accounts = await tx.findAll(contactPlugin.class.PersonAccount, {
|
||||
person: { $in: employees.map((it) => it._id) }
|
||||
@@ -113,7 +116,7 @@ async function getAllEmployeeAccounts (tx: TxOperations): Promise<Ref<PersonAcco
|
||||
}
|
||||
|
||||
async function joinEmployees (current: Space, tx: TxOperations): Promise<void> {
|
||||
const accs = await getAllEmployeeAccounts(tx)
|
||||
const accs = await getAllPersonAccounts(tx)
|
||||
const newMembers: Ref<Account>[] = [...current.members]
|
||||
for (const acc of accs) {
|
||||
if (!newMembers.includes(acc)) {
|
||||
@@ -149,7 +152,7 @@ export async function createRandom (client: MigrationUpgradeClient, tx: TxOperat
|
||||
topic: 'Random Talks',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: await getAllEmployeeAccounts(tx),
|
||||
members: await getAllPersonAccounts(tx),
|
||||
autoJoin: true
|
||||
},
|
||||
chunter.space.Random
|
||||
@@ -157,7 +160,7 @@ export async function createRandom (client: MigrationUpgradeClient, tx: TxOperat
|
||||
}
|
||||
}
|
||||
|
||||
await createDocNotifyContexts(client, tx, chunter.space.Random, chunter.class.Channel)
|
||||
await createDocNotifyContexts(client, tx, chunter.space.Random, chunter.class.Channel, core.space.Space)
|
||||
}
|
||||
|
||||
async function convertCommentsToChatMessages (client: MigrationClient): Promise<void> {
|
||||
@@ -195,6 +198,47 @@ async function removeOldClasses (client: MigrationClient): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function removeWrongActivity (client: MigrationClient): Promise<void> {
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
action: 'update',
|
||||
'attributeUpdates.attrKey': { $ne: 'members' }
|
||||
})
|
||||
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
action: 'create',
|
||||
objectClass: { $ne: chunter.class.Channel }
|
||||
})
|
||||
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
action: 'remove'
|
||||
})
|
||||
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.DirectMessage,
|
||||
action: 'update',
|
||||
'attributeUpdates.attrKey': { $ne: 'members' }
|
||||
})
|
||||
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.DirectMessage,
|
||||
action: 'create'
|
||||
})
|
||||
|
||||
await client.deleteMany<DocUpdateMessage>(DOMAIN_ACTIVITY, {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
attachedToClass: chunter.class.DirectMessage,
|
||||
action: 'remove'
|
||||
})
|
||||
}
|
||||
|
||||
export const chunterOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await tryMigrate(client, chunterId, [
|
||||
@@ -233,6 +277,12 @@ export const chunterOperation: MigrateOperation = {
|
||||
func: async (client) => {
|
||||
await removeOldClasses(client)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'remove-wrong-activity-v1',
|
||||
func: async (client) => {
|
||||
await removeWrongActivity(client)
|
||||
}
|
||||
}
|
||||
])
|
||||
},
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// 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 notification from '@hcengineering/model-notification'
|
||||
import core from '@hcengineering/model-core'
|
||||
import activity from '@hcengineering/activity'
|
||||
|
||||
import chunter from './plugin'
|
||||
|
||||
export function defineNotifications (builder: Builder): void {
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||
fields: ['members']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.Channel, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||
fields: ['members']
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.DirectMessage, core.class.Class, notification.mixin.NotificationPreview, {
|
||||
presenter: chunter.component.ChannelPreview
|
||||
})
|
||||
|
||||
builder.mixin(chunter.class.ChatMessage, core.class.Class, notification.mixin.NotificationContextPresenter, {
|
||||
labelPresenter: chunter.component.ChatMessageNotificationLabel
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, {
|
||||
messageMatch: {
|
||||
_class: chunter.class.ThreadMessage
|
||||
},
|
||||
presenter: chunter.component.ThreadNotificationPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ApplicationLabelChunter,
|
||||
icon: chunter.icon.Chunter
|
||||
},
|
||||
chunter.ids.ChunterNotificationGroup
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.DM,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ChatMessage,
|
||||
attachedToClass: chunter.class.DirectMessage,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{sender} has sent you a message: {doc} {message}',
|
||||
htmlTemplate: '<p><b>{sender}</b> has sent you a message {doc}</p> {message}',
|
||||
subjectTemplate: 'You have new direct message in {doc}'
|
||||
}
|
||||
},
|
||||
chunter.ids.DMNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ChannelMessages,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ChatMessage,
|
||||
attachedToClass: chunter.class.Channel,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{sender} has sent a message in {doc}: {message}',
|
||||
htmlTemplate: '<p><b>{sender}</b> has sent a message in {doc}</p> {message}',
|
||||
subjectTemplate: 'You have new message in {doc}'
|
||||
}
|
||||
},
|
||||
chunter.ids.ChannelNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.JoinChannel,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxUpdateDoc],
|
||||
objectClass: chunter.class.Channel,
|
||||
defaultEnabled: false,
|
||||
field: 'members',
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: 'You have been added to #{doc}',
|
||||
htmlTemplate: '<p>You have been added to <b>#{doc}</b></p>',
|
||||
subjectTemplate: 'You have been added to #{doc}'
|
||||
}
|
||||
},
|
||||
chunter.ids.JoinChannelNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ThreadMessage,
|
||||
generated: false,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: chunter.class.ThreadMessage,
|
||||
defaultEnabled: false,
|
||||
group: chunter.ids.ChunterNotificationGroup,
|
||||
templates: {
|
||||
textTemplate: '{body}',
|
||||
htmlTemplate: '<p>{body}</p>',
|
||||
subjectTemplate: '{title}'
|
||||
}
|
||||
},
|
||||
chunter.ids.ThreadNotification
|
||||
)
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.InboxNotificationProvider,
|
||||
ignoredTypes: [],
|
||||
enabledTypes: [
|
||||
chunter.ids.DMNotification,
|
||||
chunter.ids.ChannelNotification,
|
||||
chunter.ids.ThreadNotification,
|
||||
chunter.ids.JoinChannelNotification
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.PushNotificationProvider,
|
||||
ignoredTypes: [],
|
||||
enabledTypes: [
|
||||
chunter.ids.DMNotification,
|
||||
chunter.ids.ChannelNotification,
|
||||
chunter.ids.ThreadNotification,
|
||||
chunter.ids.JoinChannelNotification
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, {
|
||||
messageMatch: {
|
||||
_class: activity.class.DocUpdateMessage,
|
||||
objectClass: chunter.class.Channel,
|
||||
action: 'update',
|
||||
'attributeUpdates.attrKey': 'members'
|
||||
},
|
||||
presenter: chunter.component.JoinChannelNotificationPresenter
|
||||
})
|
||||
}
|
||||
@@ -30,7 +30,8 @@ export default mergeIds(chunterId, chunter, {
|
||||
ChannelsPanel: '' as AnyComponent,
|
||||
Chat: '' as AnyComponent,
|
||||
ChatMessageNotificationLabel: '' as AnyComponent,
|
||||
ThreadNotificationPresenter: '' as AnyComponent
|
||||
ThreadNotificationPresenter: '' as AnyComponent,
|
||||
JoinChannelNotificationPresenter: '' as AnyComponent
|
||||
},
|
||||
action: {
|
||||
MarkCommentUnread: '' as Ref<Action>,
|
||||
@@ -51,6 +52,10 @@ export default mergeIds(chunterId, chunter, {
|
||||
category: {
|
||||
Chunter: '' as Ref<ActionCategory>
|
||||
},
|
||||
activity: {
|
||||
ChannelCreatedMessage: '' as AnyComponent,
|
||||
MembersChangedMessage: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
ApplicationLabelChunter: '' as IntlString,
|
||||
MentionedIn: '' as IntlString,
|
||||
@@ -71,7 +76,9 @@ export default mergeIds(chunterId, chunter, {
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString,
|
||||
Reacted: '' as IntlString,
|
||||
RepliedToThread: '' as IntlString
|
||||
RepliedToThread: '' as IntlString,
|
||||
ChannelMessages: '' as IntlString,
|
||||
JoinChannel: '' as IntlString
|
||||
},
|
||||
viewlet: {
|
||||
Chat: '' as Ref<ViewletDescriptor>,
|
||||
|
||||
+11
-13
@@ -29,7 +29,8 @@ import {
|
||||
type Organization,
|
||||
type Person,
|
||||
type PersonAccount,
|
||||
type Status
|
||||
type Status,
|
||||
type PersonSpace
|
||||
} from '@hcengineering/contact'
|
||||
import {
|
||||
AccountRole,
|
||||
@@ -64,7 +65,7 @@ import {
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import core, { TAccount, TAttachedDoc, TDoc } from '@hcengineering/model-core'
|
||||
import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@hcengineering/model-core'
|
||||
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
||||
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
@@ -219,6 +220,12 @@ export class TContactsTab extends TDoc implements ContactsTab {
|
||||
index!: number
|
||||
}
|
||||
|
||||
@Model(contact.class.PersonSpace, core.class.Space)
|
||||
export class TPersonSpace extends TSpace implements PersonSpace {
|
||||
@Prop(TypeRef(contact.class.Person), contact.string.Person)
|
||||
person!: Ref<Person>
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(
|
||||
TAvatarProvider,
|
||||
@@ -231,7 +238,8 @@ export function createModel (builder: Builder): void {
|
||||
TChannel,
|
||||
TStatus,
|
||||
TMember,
|
||||
TContactsTab
|
||||
TContactsTab,
|
||||
TPersonSpace
|
||||
)
|
||||
|
||||
builder.mixin(contact.class.Contact, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
@@ -246,16 +254,6 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.mixin(contact.class.Organization, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: contact.class.Contact,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Channel, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.mixin(contact.class.Person, core.class.Class, view.mixin.ObjectIcon, {
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
//
|
||||
|
||||
import { DOMAIN_TX, TxOperations, type Class, type Doc, type Domain, type Ref, type Space } from '@hcengineering/core'
|
||||
import {
|
||||
type Class,
|
||||
type Doc,
|
||||
type Domain,
|
||||
DOMAIN_TX,
|
||||
generateId,
|
||||
type Ref,
|
||||
type Space,
|
||||
TxOperations
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrateUpdate,
|
||||
type MigrationClient,
|
||||
type MigrationDocumentQuery,
|
||||
type MigrationUpgradeClient,
|
||||
type ModelLogger
|
||||
type ModelLogger,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
} from '@hcengineering/model'
|
||||
import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||
import core from '@hcengineering/model-core'
|
||||
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
import { DOMAIN_VIEW } from '@hcengineering/model-view'
|
||||
import { AvatarType, type Contact, type Person, type PersonSpace } from '@hcengineering/contact'
|
||||
|
||||
import { AvatarType, type Contact } from '@hcengineering/contact'
|
||||
import contact, { DOMAIN_CONTACT, contactId } from './index'
|
||||
import contact, { contactId, DOMAIN_CONTACT } from './index'
|
||||
|
||||
async function createEmployeeEmail (client: TxOperations): Promise<void> {
|
||||
const employees = await client.findAll(contact.mixin.Employee, {})
|
||||
@@ -100,23 +109,55 @@ async function migrateAvatars (client: MigrationClient): Promise<void> {
|
||||
)
|
||||
}
|
||||
|
||||
async function createPersonSpaces (client: MigrationClient): Promise<void> {
|
||||
const spaces = await client.find<PersonSpace>(DOMAIN_SPACE, { _class: contact.class.PersonSpace })
|
||||
|
||||
if (spaces.length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const accounts = await client.model.findAll(contact.class.PersonAccount, {})
|
||||
const employees = await client.find(DOMAIN_CONTACT, { [contact.mixin.Employee]: { $exists: true } })
|
||||
|
||||
const newSpaces = new Map<Ref<Person>, PersonSpace>()
|
||||
const now = Date.now()
|
||||
|
||||
for (const account of accounts) {
|
||||
const employee = employees.find(({ _id }) => _id === account.person)
|
||||
if (employee === undefined) continue
|
||||
|
||||
const space = newSpaces.get(account.person)
|
||||
|
||||
if (space !== undefined) {
|
||||
space.members.push(account._id)
|
||||
} else {
|
||||
newSpaces.set(account.person, {
|
||||
_id: generateId(),
|
||||
_class: contact.class.PersonSpace,
|
||||
space: core.space.Space,
|
||||
name: 'Personal space',
|
||||
description: '',
|
||||
private: true,
|
||||
archived: false,
|
||||
members: [account._id],
|
||||
person: account.person,
|
||||
modifiedBy: core.account.System,
|
||||
createdBy: core.account.System,
|
||||
modifiedOn: now,
|
||||
createdOn: now
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
await client.create(DOMAIN_SPACE, Array.from(newSpaces.values()))
|
||||
}
|
||||
|
||||
export const contactOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient, logger: ModelLogger): Promise<void> {
|
||||
await tryMigrate(client, contactId, [
|
||||
{
|
||||
state: 'employees',
|
||||
func: async (client) => {
|
||||
await client.update(
|
||||
DOMAIN_TX,
|
||||
{
|
||||
objectClass: 'contact:class:EmployeeAccount'
|
||||
},
|
||||
{
|
||||
$rename: { 'attributes.employee': 'attributes.person' },
|
||||
$set: { objectClass: contact.class.PersonAccount }
|
||||
}
|
||||
)
|
||||
|
||||
await client.update(
|
||||
DOMAIN_TX,
|
||||
{
|
||||
@@ -251,6 +292,10 @@ export const contactOperation: MigrateOperation = {
|
||||
{ $rename: { avatarKind: 'avatarType' } }
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'create-person-spaces-v1',
|
||||
func: createPersonSpaces
|
||||
}
|
||||
])
|
||||
},
|
||||
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
type EnumOf,
|
||||
type FieldIndexConfig,
|
||||
type FullTextSearchContext,
|
||||
type IndexStageState,
|
||||
type IndexingConfiguration,
|
||||
type Interface,
|
||||
type MigrationState,
|
||||
@@ -329,27 +328,24 @@ export class TDocIndexState extends TDoc implements DocIndexState {
|
||||
attributes!: Record<string, any>
|
||||
|
||||
@Prop(TypeBoolean(), getEmbeddedLabel('Removed'))
|
||||
// @Index(IndexKind.Indexed)
|
||||
@Hidden()
|
||||
removed!: boolean
|
||||
|
||||
@Prop(TypeBoolean(), getEmbeddedLabel('NeedIndexing'))
|
||||
@Hidden()
|
||||
needIndex!: boolean
|
||||
|
||||
// States for different stages
|
||||
@Prop(TypeRecord(), getEmbeddedLabel('Stages'))
|
||||
// @Index(IndexKind.Indexed)
|
||||
@Hidden()
|
||||
stages!: Record<string, boolean | string>
|
||||
stages!: Record<string, boolean>
|
||||
|
||||
@Prop(TypeString(), getEmbeddedLabel('Generation'))
|
||||
@Hidden()
|
||||
generationId?: string
|
||||
}
|
||||
|
||||
@Model(core.class.IndexStageState, core.class.Doc, DOMAIN_DOC_INDEX_STATE)
|
||||
export class TIndexStageState extends TDoc implements IndexStageState {
|
||||
stageId!: string
|
||||
attributes!: Record<string, any>
|
||||
}
|
||||
|
||||
@MMixin(core.mixin.FullTextSearchContext, core.class.Class)
|
||||
export class TFullTextSearchContext extends TClass implements FullTextSearchContext {}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ import {
|
||||
TEnumOf,
|
||||
TFullTextSearchContext,
|
||||
TIndexConfiguration,
|
||||
TIndexStageState,
|
||||
TInterface,
|
||||
TMigrationState,
|
||||
TMixin,
|
||||
@@ -94,9 +93,9 @@ import { TUserStatus } from './transient'
|
||||
import {
|
||||
TTx,
|
||||
TTxApplyIf,
|
||||
TTxCUD,
|
||||
TTxCollectionCUD,
|
||||
TTxCreateDoc,
|
||||
TTxCUD,
|
||||
TTxMixin,
|
||||
TTxRemoveDoc,
|
||||
TTxUpdateDoc,
|
||||
@@ -164,7 +163,6 @@ export function createModel (builder: Builder): void {
|
||||
TTypeAny,
|
||||
TTypeRelatedDocument,
|
||||
TDocIndexState,
|
||||
TIndexStageState,
|
||||
TFullTextSearchContext,
|
||||
TConfiguration,
|
||||
TConfigurationElement,
|
||||
@@ -284,8 +282,9 @@ export function createModel (builder: Builder): void {
|
||||
builder.createDoc(core.class.DomainIndexConfiguration, core.space.Model, {
|
||||
domain: DOMAIN_DOC_INDEX_STATE,
|
||||
indexes: [
|
||||
{ keys: { removed: 1 }, filter: { removed: true } },
|
||||
{ keys: { _class: 1 }, filter: { _class: core.class.DocIndexState } }
|
||||
{
|
||||
keys: { needIndex: 1 }
|
||||
}
|
||||
],
|
||||
disabled: [
|
||||
{ attachedToClass: 1 },
|
||||
@@ -297,8 +296,7 @@ export function createModel (builder: Builder): void {
|
||||
{ createdBy: 1 },
|
||||
{ createdBy: -1 },
|
||||
{ createdOn: -1 }
|
||||
],
|
||||
skip: ['stages.']
|
||||
]
|
||||
})
|
||||
|
||||
builder.mixin(core.class.Space, core.class.Class, core.mixin.FullTextSearchContext, {
|
||||
|
||||
@@ -155,7 +155,8 @@ export const coreOperation: MigrateOperation = {
|
||||
{ objectClass: { $nin: allIndexed } },
|
||||
{
|
||||
$set: {
|
||||
removed: true
|
||||
removed: true,
|
||||
needIndex: true
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -182,6 +183,12 @@ export const coreOperation: MigrateOperation = {
|
||||
{
|
||||
state: 'old-statuses-transactions',
|
||||
func: migrateStatusTransactions
|
||||
},
|
||||
{
|
||||
state: 'add-need-index',
|
||||
func: async (client: MigrationClient) => {
|
||||
await client.update(DOMAIN_DOC_INDEX_STATE, {}, { $set: { needIndex: true } })
|
||||
}
|
||||
}
|
||||
])
|
||||
},
|
||||
|
||||
@@ -268,7 +268,7 @@ export function createModel (builder: Builder): void {
|
||||
defaultEnabled: true,
|
||||
canDisable: true,
|
||||
depends: notification.providers.InboxNotificationProvider,
|
||||
order: 30
|
||||
order: 300
|
||||
},
|
||||
gmail.providers.EmailNotificationProvider
|
||||
)
|
||||
|
||||
@@ -47,16 +47,6 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.mixin(lead.mixin.Customer, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: lead.class.Lead,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.mixin(lead.class.Funnel, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
|
||||
@@ -87,6 +87,8 @@ export class TParticipantInfo extends TDoc implements ParticipantInfo {
|
||||
|
||||
x!: number
|
||||
y!: number
|
||||
|
||||
sessionId!: string | null
|
||||
}
|
||||
|
||||
@Model(love.class.JoinRequest, core.class.Doc, DOMAIN_TRANSIENT)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"dependencies": {
|
||||
"@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",
|
||||
@@ -39,10 +40,10 @@
|
||||
"@hcengineering/model-workbench": "^0.6.1",
|
||||
"@hcengineering/notification": "^0.6.23",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/preference": "^0.6.13",
|
||||
"@hcengineering/setting": "^0.6.17",
|
||||
"@hcengineering/ui": "^0.6.15",
|
||||
"@hcengineering/view": "^0.6.13",
|
||||
"@hcengineering/workbench": "^0.6.16",
|
||||
"@hcengineering/preference": "^0.6.13"
|
||||
"@hcengineering/workbench": "^0.6.16"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
UX,
|
||||
type Builder
|
||||
} from '@hcengineering/model'
|
||||
import { type PersonSpace } from '@hcengineering/contact'
|
||||
import core, { TClass, TDoc } from '@hcengineering/model-core'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import view, { createAction, template } from '@hcengineering/model-view'
|
||||
@@ -79,7 +80,7 @@ import {
|
||||
type PushSubscription,
|
||||
type PushSubscriptionKeys
|
||||
} from '@hcengineering/notification'
|
||||
import { type Asset, type IntlString } from '@hcengineering/platform'
|
||||
import { type Asset, type IntlString, type Resource } from '@hcengineering/platform'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { type AnyComponent, type Location } from '@hcengineering/ui/src/types'
|
||||
|
||||
@@ -195,13 +196,18 @@ export class TDocNotifyContext extends TDoc implements DocNotifyContext {
|
||||
@Index(IndexKind.Indexed)
|
||||
user!: Ref<Account>
|
||||
|
||||
@Prop(TypeRef(core.class.Doc), core.string.AttachedTo)
|
||||
@Prop(TypeRef(core.class.Doc), core.string.Object)
|
||||
@Index(IndexKind.Indexed)
|
||||
attachedTo!: Ref<Doc>
|
||||
objectId!: Ref<Doc>
|
||||
|
||||
@Prop(TypeRef(core.class.Class), core.string.AttachedToClass)
|
||||
@Prop(TypeRef(core.class.Class), core.string.Class)
|
||||
@Index(IndexKind.Indexed)
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
|
||||
@Prop(TypeRef(core.class.Space), core.string.Space)
|
||||
objectSpace!: Ref<Space>
|
||||
|
||||
declare space: Ref<PersonSpace>
|
||||
|
||||
@Prop(TypeDate(), core.string.Date)
|
||||
lastViewedTimestamp?: Timestamp
|
||||
@@ -210,7 +216,7 @@ export class TDocNotifyContext extends TDoc implements DocNotifyContext {
|
||||
lastUpdateTimestamp?: Timestamp
|
||||
|
||||
@Prop(TypeBoolean(), notification.string.Pinned)
|
||||
isPinned?: boolean
|
||||
isPinned!: boolean
|
||||
}
|
||||
|
||||
@Model(notification.class.InboxNotification, core.class.Doc, DOMAIN_NOTIFICATION)
|
||||
@@ -228,7 +234,9 @@ export class TInboxNotification extends TDoc implements InboxNotification {
|
||||
isViewed!: boolean
|
||||
|
||||
@Prop(TypeBoolean(), core.string.Boolean)
|
||||
archived?: boolean
|
||||
archived!: boolean
|
||||
|
||||
declare space: Ref<PersonSpace>
|
||||
|
||||
title?: IntlString
|
||||
body?: IntlString
|
||||
@@ -295,6 +303,8 @@ export class TNotificationProvider extends TDoc implements NotificationProvider
|
||||
depends?: Ref<NotificationProvider>
|
||||
ignoreAll?: boolean
|
||||
canDisable!: boolean
|
||||
presenter?: AnyComponent
|
||||
isAvailableFn?: Resource<() => boolean>
|
||||
}
|
||||
|
||||
@Model(notification.class.NotificationProviderDefaults, core.class.Doc)
|
||||
@@ -723,7 +733,7 @@ export function createModel (builder: Builder): void {
|
||||
description: notification.string.InboxNotificationsDescription,
|
||||
defaultEnabled: true,
|
||||
canDisable: false,
|
||||
order: 10
|
||||
order: 100
|
||||
},
|
||||
notification.providers.InboxNotificationProvider
|
||||
)
|
||||
@@ -738,7 +748,7 @@ export function createModel (builder: Builder): void {
|
||||
depends: notification.providers.InboxNotificationProvider,
|
||||
defaultEnabled: true,
|
||||
canDisable: true,
|
||||
order: 20
|
||||
order: 200
|
||||
},
|
||||
notification.providers.PushNotificationProvider
|
||||
)
|
||||
@@ -754,7 +764,7 @@ export function createModel (builder: Builder): void {
|
||||
defaultEnabled: true,
|
||||
canDisable: true,
|
||||
ignoreAll: true,
|
||||
order: 25
|
||||
order: 250
|
||||
},
|
||||
notification.providers.SoundNotificationProvider
|
||||
)
|
||||
|
||||
@@ -25,11 +25,14 @@ import notification, {
|
||||
notificationId,
|
||||
NotificationStatus,
|
||||
type BrowserNotification,
|
||||
type DocNotifyContext
|
||||
type DocNotifyContext,
|
||||
type InboxNotification
|
||||
} from '@hcengineering/notification'
|
||||
import { DOMAIN_PREFERENCE } from '@hcengineering/preference'
|
||||
import contact, { type PersonSpace } from '@hcengineering/contact'
|
||||
|
||||
import { DOMAIN_DOC_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_USER_NOTIFY } from './index'
|
||||
import { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
|
||||
export async function removeNotifications (
|
||||
client: MigrationClient,
|
||||
@@ -73,6 +76,115 @@ export async function removeNotifications (
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateNotificationsSpace (client: MigrationClient): Promise<void> {
|
||||
const personSpaces = await client.find<PersonSpace>(DOMAIN_SPACE, { _class: contact.class.PersonSpace }, {})
|
||||
|
||||
await client.update(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{
|
||||
_class: notification.class.DocNotifyContext,
|
||||
objectSpace: { $exists: false }
|
||||
},
|
||||
{ $rename: { space: 'objectSpace' } }
|
||||
)
|
||||
|
||||
for (const space of personSpaces) {
|
||||
await client.update(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{
|
||||
_class: notification.class.DocNotifyContext,
|
||||
user: { $in: space.members }
|
||||
},
|
||||
{ space: space._id }
|
||||
)
|
||||
await client.update(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{
|
||||
_class: notification.class.ActivityInboxNotification,
|
||||
user: { $in: space.members }
|
||||
},
|
||||
{ space: space._id }
|
||||
)
|
||||
await client.update(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{
|
||||
_class: notification.class.CommonInboxNotification,
|
||||
user: { $in: space.members }
|
||||
},
|
||||
{ space: space._id }
|
||||
)
|
||||
await client.update(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{
|
||||
_class: notification.class.MentionInboxNotification,
|
||||
user: { $in: space.members }
|
||||
},
|
||||
{ space: space._id }
|
||||
)
|
||||
}
|
||||
|
||||
await client.deleteMany(DOMAIN_DOC_NOTIFY, { space: { $nin: personSpaces.map(({ _id }) => _id) } })
|
||||
await client.deleteMany(DOMAIN_NOTIFICATION, {
|
||||
_class: notification.class.ActivityInboxNotification,
|
||||
space: { $nin: personSpaces.map(({ _id }) => _id) }
|
||||
})
|
||||
await client.deleteMany(DOMAIN_NOTIFICATION, {
|
||||
_class: notification.class.CommonInboxNotification,
|
||||
space: { $nin: personSpaces.map(({ _id }) => _id) }
|
||||
})
|
||||
await client.deleteMany(DOMAIN_NOTIFICATION, {
|
||||
_class: notification.class.MentionInboxNotification,
|
||||
space: { $nin: personSpaces.map(({ _id }) => _id) }
|
||||
})
|
||||
|
||||
while (true) {
|
||||
const contexts = await client.find<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{
|
||||
_class: notification.class.DocNotifyContext,
|
||||
attachedTo: { $exists: true }
|
||||
},
|
||||
{ limit: 500 }
|
||||
)
|
||||
|
||||
if (contexts.length === 0) {
|
||||
break
|
||||
}
|
||||
|
||||
const classesOfSpace = new Set<Ref<Class<Doc>>>()
|
||||
|
||||
for (const context of contexts) {
|
||||
const _class = (context as any).attachedToClass
|
||||
if (client.hierarchy.isDerived(_class, core.class.Space)) {
|
||||
classesOfSpace.add(_class)
|
||||
}
|
||||
}
|
||||
if (classesOfSpace.size > 0) {
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ objectClass: { $in: Array.from(classesOfSpace) } },
|
||||
{ objectSpace: core.space.Space }
|
||||
)
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ objectClass: { $in: Array.from(classesOfSpace) } },
|
||||
{ $rename: { attachedTo: 'objectId', attachedToClass: 'objectClass' } }
|
||||
)
|
||||
}
|
||||
await client.update(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{
|
||||
_class: notification.class.DocNotifyContext,
|
||||
_id: { $in: contexts.map(({ _id }) => _id) }
|
||||
},
|
||||
{ $rename: { attachedTo: 'objectId', attachedToClass: 'objectClass' } }
|
||||
)
|
||||
}
|
||||
|
||||
await client.deleteMany(DOMAIN_NOTIFICATION, { _class: notification.class.BrowserNotification })
|
||||
await client.deleteMany(DOMAIN_USER_NOTIFY, { _class: notification.class.BrowserNotification })
|
||||
}
|
||||
|
||||
export async function migrateSettings (client: MigrationClient): Promise<void> {
|
||||
await client.update(
|
||||
DOMAIN_PREFERENCE,
|
||||
@@ -166,8 +278,53 @@ export const notificationOperation: MigrateOperation = {
|
||||
DOMAIN_USER_NOTIFY
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'fill-notification-archived-field-v1',
|
||||
func: async (client) => {
|
||||
await client.update<InboxNotification>(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{ _class: notification.class.ActivityInboxNotification, archived: { $exists: false } },
|
||||
{ archived: false }
|
||||
)
|
||||
await client.update<InboxNotification>(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{ _class: notification.class.CommonInboxNotification, archived: { $exists: false } },
|
||||
{ archived: false }
|
||||
)
|
||||
await client.update<InboxNotification>(
|
||||
DOMAIN_NOTIFICATION,
|
||||
{ _class: notification.class.MentionInboxNotification, archived: { $exists: false } },
|
||||
{ archived: false }
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'fill-contexts-pinned-field-v1',
|
||||
func: async (client) => {
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ _class: notification.class.DocNotifyContext, isPinned: { $exists: false } },
|
||||
{ isPinned: false }
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'migrate-notifications-space-v1',
|
||||
func: migrateNotificationsSpace
|
||||
},
|
||||
{
|
||||
state: 'migrate-employee-space-v1',
|
||||
func: async () => {
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ _class: notification.class.DocNotifyContext, objectSpace: 'contact:space:Employee' as Ref<Space> },
|
||||
{ objectSpace: contact.space.Contacts }
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
await client.deleteMany<BrowserNotification>(DOMAIN_USER_NOTIFY, {
|
||||
_class: notification.class.BrowserNotification,
|
||||
status: NotificationStatus.Notified
|
||||
|
||||
@@ -54,26 +54,6 @@ export function createModel (builder: Builder): void {
|
||||
builder.mixin(recruit.class.Review, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
builder.mixin(recruit.mixin.Candidate, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: recruit.class.Vacancy,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: recruit.class.Applicant,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: recruit.class.Vacancy,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
|
||||
@@ -28,6 +28,10 @@ export function createModel (builder: Builder): void {
|
||||
presenter: serverActivity.function.ReactionNotificationContentProvider
|
||||
})
|
||||
|
||||
builder.mixin(activity.class.DocUpdateMessage, core.class.Class, serverNotification.mixin.TextPresenter, {
|
||||
presenter: serverActivity.function.DocUpdateMessageTextPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverActivity.trigger.OnReactionChanged,
|
||||
txMatch: {
|
||||
@@ -38,7 +42,8 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverActivity.trigger.ActivityMessagesHandler
|
||||
trigger: serverActivity.trigger.ActivityMessagesHandler,
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/model/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig",
|
||||
"rigProfile": "model"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@hcengineering/model-server-ai-bot",
|
||||
"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",
|
||||
"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",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/activity": "^0.6.0",
|
||||
"@hcengineering/ai-bot": "^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-activity": "^0.6.0",
|
||||
"@hcengineering/model-chunter": "^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-view": "^0.6.0",
|
||||
"@hcengineering/notification": "^0.6.23",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/server-ai-bot": "^0.6.0",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
"@hcengineering/view": "^0.6.13"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// 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, Mixin, Model, Prop, TypeRef, TypeString } from '@hcengineering/model'
|
||||
import core, { type Account, type Class, type Doc, type Domain, type Ref, type Space } from '@hcengineering/core'
|
||||
import serverCore from '@hcengineering/server-core'
|
||||
import serverAiBot from '@hcengineering/server-ai-bot'
|
||||
import { TDoc } from '@hcengineering/model-core'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import aiBot, {
|
||||
type AIBotEvent,
|
||||
type AIBotTransferEvent,
|
||||
type AIBotResponseEvent,
|
||||
type TransferredMessage
|
||||
} from '@hcengineering/ai-bot'
|
||||
import chunter, { type ChatMessage } from '@hcengineering/chunter'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { TChatMessage } from '@hcengineering/model-chunter'
|
||||
|
||||
export { serverAiBotId } from '@hcengineering/server-ai-bot'
|
||||
|
||||
export const DOMAIN_AI_BOT = 'ai_bot' as Domain
|
||||
|
||||
@Model(aiBot.class.AIBotEvent, core.class.Doc, DOMAIN_AI_BOT)
|
||||
export class TAIBotEvent extends TDoc implements AIBotEvent {
|
||||
@Prop(TypeRef(chunter.class.ChatMessage), core.string.Class)
|
||||
messageClass!: Ref<Class<ChatMessage>>
|
||||
|
||||
@Prop(TypeString(), getEmbeddedLabel('Collection'))
|
||||
collection!: string
|
||||
|
||||
@Prop(TypeString(), getEmbeddedLabel('Message'))
|
||||
message!: string
|
||||
}
|
||||
|
||||
@Model(aiBot.class.AIBotResponseEvent, core.class.Doc)
|
||||
export class TAIBotResponseEvent extends TAIBotEvent implements AIBotResponseEvent {
|
||||
@Prop(TypeRef(core.class.Doc), core.string.Object)
|
||||
objectId!: Ref<Doc>
|
||||
|
||||
@Prop(TypeRef(core.class.Class), core.string.Class)
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
|
||||
@Prop(TypeRef(core.class.Space), core.string.Space)
|
||||
objectSpace!: Ref<Space>
|
||||
|
||||
@Prop(TypeRef(core.class.Account), core.string.Account)
|
||||
user!: Ref<Account>
|
||||
}
|
||||
|
||||
@Model(aiBot.class.AIBotTransferEvent, aiBot.class.AIBotEvent)
|
||||
export class TAIBotTransferEvent extends TAIBotEvent implements AIBotTransferEvent {
|
||||
toEmail!: string
|
||||
toWorkspace!: string
|
||||
fromWorkspace!: string
|
||||
messageId!: Ref<ChatMessage>
|
||||
parentMessageId?: Ref<ChatMessage>
|
||||
}
|
||||
|
||||
@Mixin(aiBot.mixin.TransferredMessage, chunter.class.ChatMessage)
|
||||
export class TTransferredMessage extends TChatMessage implements TransferredMessage {
|
||||
messageId!: Ref<ChatMessage>
|
||||
parentMessageId?: Ref<ChatMessage>
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TAIBotEvent, TAIBotTransferEvent, TAIBotResponseEvent, TTransferredMessage)
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverAiBot.trigger.OnMessageSend,
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverAiBot.trigger.OnMention,
|
||||
txMatch: {
|
||||
_class: core.class.TxCreateDoc,
|
||||
objectClass: notification.class.MentionInboxNotification
|
||||
},
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverAiBot.trigger.OnMessageNotified,
|
||||
txMatch: {
|
||||
_class: core.class.TxCreateDoc,
|
||||
objectClass: notification.class.ActivityInboxNotification
|
||||
},
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverAiBot.trigger.OnUserStatus,
|
||||
txMatch: {
|
||||
objectClass: core.class.UserStatus
|
||||
},
|
||||
isAsync: true
|
||||
})
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -54,14 +54,6 @@ export function createModel (builder: Builder): void {
|
||||
trigger: serverChunter.trigger.ChunterTrigger
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverChunter.trigger.OnChannelMembersChanged,
|
||||
txMatch: {
|
||||
_class: core.class.TxUpdateDoc,
|
||||
objectClass: chunter.class.Channel
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverChunter.trigger.OnUserStatus,
|
||||
txMatch: {
|
||||
@@ -70,6 +62,15 @@ export function createModel (builder: Builder): void {
|
||||
isAsync: true
|
||||
})
|
||||
|
||||
builder.mixin(
|
||||
chunter.ids.JoinChannelNotification,
|
||||
notification.class.NotificationType,
|
||||
serverNotification.mixin.TypeMatch,
|
||||
{
|
||||
func: serverChunter.function.JoinChannelTypeMatch
|
||||
}
|
||||
)
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverChunter.trigger.OnContextUpdate,
|
||||
txMatch: {
|
||||
|
||||
@@ -37,6 +37,11 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
)
|
||||
|
||||
builder.createDoc(serverNotification.class.NotificationProviderResources, core.space.Model, {
|
||||
provider: telegram.providers.TelegramNotificationProvider,
|
||||
fn: serverTelegram.function.SendTelegramNotifications
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverTelegram.trigger.OnMessageCreate,
|
||||
txMatch: {
|
||||
|
||||
@@ -41,8 +41,9 @@ import type {
|
||||
} from '@hcengineering/telegram'
|
||||
import templates from '@hcengineering/templates'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
import telegram from './plugin'
|
||||
import notification from '@hcengineering/model-notification'
|
||||
import { defineNotifications } from './notification'
|
||||
|
||||
export { telegramId } from '@hcengineering/telegram'
|
||||
export { telegramOperation } from './migration'
|
||||
@@ -178,38 +179,6 @@ export function createModel (builder: Builder): void {
|
||||
telegram.ids.TelegramMessageSharedActivityViewlet
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
{
|
||||
label: telegram.string.Telegram,
|
||||
icon: contact.icon.Telegram
|
||||
},
|
||||
telegram.ids.NotificationGroup
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: telegram.string.NewMessage,
|
||||
generated: false,
|
||||
allowedForAuthor: true,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: telegram.class.Message,
|
||||
group: telegram.ids.NotificationGroup,
|
||||
defaultEnabled: false
|
||||
},
|
||||
telegram.ids.NewMessageNotification
|
||||
)
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.InboxNotificationProvider,
|
||||
ignoredTypes: [],
|
||||
enabledTypes: [telegram.ids.NewMessageNotification]
|
||||
})
|
||||
|
||||
builder.mixin(telegram.class.Message, core.class.Class, core.mixin.FullTextSearchContext, {
|
||||
parentPropagate: false,
|
||||
childProcessingAllowed: true
|
||||
@@ -227,4 +196,6 @@ export function createModel (builder: Builder): void {
|
||||
{ createdOn: -1 }
|
||||
]
|
||||
})
|
||||
|
||||
defineNotifications(builder)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// 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 notification from '@hcengineering/model-notification'
|
||||
import core from '@hcengineering/model-core'
|
||||
import contact from '@hcengineering/model-contact'
|
||||
|
||||
import telegram from './plugin'
|
||||
|
||||
export function defineNotifications (builder: Builder): void {
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
{
|
||||
label: telegram.string.Telegram,
|
||||
icon: contact.icon.Telegram
|
||||
},
|
||||
telegram.ids.NotificationGroup
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: telegram.string.Telegram,
|
||||
icon: contact.icon.Telegram,
|
||||
depends: notification.providers.InboxNotificationProvider,
|
||||
defaultEnabled: false,
|
||||
canDisable: true,
|
||||
description: telegram.string.TelegramNotificationDescription,
|
||||
presenter: telegram.component.NotificationProviderPresenter,
|
||||
order: 400,
|
||||
isAvailableFn: telegram.function.IsTelegramNotificationsAvailable
|
||||
},
|
||||
telegram.providers.TelegramNotificationProvider
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
label: telegram.string.NewMessage,
|
||||
generated: false,
|
||||
allowedForAuthor: true,
|
||||
hidden: false,
|
||||
txClasses: [core.class.TxCreateDoc],
|
||||
objectClass: telegram.class.Message,
|
||||
group: telegram.ids.NotificationGroup,
|
||||
defaultEnabled: false
|
||||
},
|
||||
telegram.ids.NewMessageNotification
|
||||
)
|
||||
|
||||
builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, {
|
||||
provider: notification.providers.InboxNotificationProvider,
|
||||
ignoredTypes: [notification.ids.CollaboratoAddNotification],
|
||||
enabledTypes: [telegram.ids.NewMessageNotification]
|
||||
})
|
||||
}
|
||||
@@ -36,7 +36,8 @@ export default mergeIds(telegramId, telegram, {
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString,
|
||||
NewMessage: '' as IntlString,
|
||||
NewIncomingMessage: '' as IntlString
|
||||
NewIncomingMessage: '' as IntlString,
|
||||
TelegramNotificationDescription: '' as IntlString
|
||||
},
|
||||
ids: {
|
||||
NotificationGroup: '' as Ref<NotificationGroup>,
|
||||
@@ -45,9 +46,13 @@ export default mergeIds(telegramId, telegram, {
|
||||
},
|
||||
function: {
|
||||
GetCurrentEmployeeTG: '' as Resource<TemplateFieldFunc>,
|
||||
GetIntegrationOwnerTG: '' as Resource<TemplateFieldFunc>
|
||||
GetIntegrationOwnerTG: '' as Resource<TemplateFieldFunc>,
|
||||
IsTelegramNotificationsAvailable: '' as Resource<() => boolean>
|
||||
},
|
||||
activity: {
|
||||
TelegramMessageCreated: '' as AnyComponent
|
||||
},
|
||||
component: {
|
||||
NotificationProviderPresenter: '' as AnyComponent
|
||||
}
|
||||
})
|
||||
|
||||
@@ -449,46 +449,6 @@ export function createModel (builder: Builder): void {
|
||||
decode: tracker.function.GetIssueIdByIdentifier
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: tracker.class.Issue,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: tracker.class.Milestone,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: tracker.class.Component,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityMessageControl, core.space.Model, {
|
||||
objectClass: tracker.class.IssueTemplate,
|
||||
skip: [
|
||||
{
|
||||
_class: core.class.TxCollectionCUD,
|
||||
collection: 'comments'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: tracker.class.Issue,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
|
||||
@@ -510,7 +510,9 @@ export interface DocIndexState extends Doc {
|
||||
generationId?: string
|
||||
|
||||
// States for stages
|
||||
stages: Record<string, boolean | string>
|
||||
stages: Record<string, boolean>
|
||||
|
||||
needIndex: boolean
|
||||
|
||||
removed: boolean
|
||||
|
||||
@@ -522,14 +524,6 @@ export interface DocIndexState extends Doc {
|
||||
shortSummary?: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface IndexStageState extends Doc {
|
||||
stageId: string
|
||||
attributes: Record<string, any>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
|
||||
@@ -32,7 +32,6 @@ import type {
|
||||
EnumOf,
|
||||
FullTextSearchContext,
|
||||
Hyperlink,
|
||||
IndexStageState,
|
||||
IndexingConfiguration,
|
||||
Interface,
|
||||
Markup,
|
||||
@@ -135,7 +134,6 @@ export default plugin(coreId, {
|
||||
UserStatus: '' as Ref<Class<UserStatus>>,
|
||||
TypeRelatedDocument: '' as Ref<Class<Type<RelatedDocument>>>,
|
||||
DocIndexState: '' as Ref<Class<DocIndexState>>,
|
||||
IndexStageState: '' as Ref<Class<IndexStageState>>,
|
||||
DomainIndexConfiguration: '' as Ref<Class<DomainIndexConfiguration>>,
|
||||
|
||||
Configuration: '' as Ref<Class<Configuration>>,
|
||||
|
||||
@@ -116,6 +116,20 @@ export class MeasureMetricsContext implements MeasureContext {
|
||||
}
|
||||
}
|
||||
|
||||
withSync<T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
op: (ctx: MeasureContext) => T,
|
||||
fullParams?: ParamsType | (() => FullParamsType)
|
||||
): T {
|
||||
const c = this.newChild(name, params, fullParams, this.logger)
|
||||
try {
|
||||
return op(c)
|
||||
} finally {
|
||||
c.end()
|
||||
}
|
||||
}
|
||||
|
||||
async withLog<T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
|
||||
@@ -63,6 +63,13 @@ export interface MeasureContext {
|
||||
fullParams?: FullParamsType | (() => FullParamsType)
|
||||
) => Promise<T>
|
||||
|
||||
withSync: <T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
op: (ctx: MeasureContext) => T,
|
||||
fullParams?: FullParamsType | (() => FullParamsType)
|
||||
) => T
|
||||
|
||||
withLog: <T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
|
||||
@@ -337,13 +337,18 @@ export class ModelDb extends MemDb {
|
||||
}
|
||||
|
||||
protected async txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<TxResult> {
|
||||
const doc = this.getObject(tx.objectId) as any
|
||||
TxProcessor.updateDoc2Doc(doc, tx)
|
||||
return tx.retrieve === true ? { object: doc } : {}
|
||||
try {
|
||||
const doc = this.getObject(tx.objectId) as any
|
||||
TxProcessor.updateDoc2Doc(doc, tx)
|
||||
return tx.retrieve === true ? { object: doc } : {}
|
||||
} catch (err: any) {}
|
||||
return {}
|
||||
}
|
||||
|
||||
protected async txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<TxResult> {
|
||||
this.delDoc(tx.objectId)
|
||||
try {
|
||||
this.delDoc(tx.objectId)
|
||||
} catch (err: any) {}
|
||||
return {}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,8 @@ export default plugin(presentationId, {
|
||||
Endpoint: '' as Metadata<string>,
|
||||
FrontUrl: '' as Asset,
|
||||
PreviewConfig: '' as Metadata<PreviewConfig | undefined>,
|
||||
ClientHook: '' as Metadata<ClientHook>
|
||||
ClientHook: '' as Metadata<ClientHook>,
|
||||
SessionId: '' as Metadata<string>
|
||||
},
|
||||
status: {
|
||||
FileTooLarge: '' as StatusCode
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
--primary-button-hovered: #3575DE;
|
||||
--primary-button-pressed: #1C52AB;
|
||||
--primary-button-focused: #205DC2;
|
||||
--secondary-button-color: rgba(0, 0, 0, .8);
|
||||
--secondary-button-default: #D3E1F8;
|
||||
--secondary-button-hovered: #BDD2F5;
|
||||
--secondary-button-pressed: #A7C3F1;
|
||||
|
||||
@@ -241,6 +241,7 @@
|
||||
}
|
||||
}
|
||||
&.secondary {
|
||||
color: var(--secondary-button-color);
|
||||
background-color: var(--secondary-button-default);
|
||||
&:hover { background-color: var(--secondary-button-hovered); }
|
||||
&:active,
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
}
|
||||
}
|
||||
&.primary {
|
||||
color: var(--secondary-button-color);
|
||||
background-color: var(--secondary-button-default);
|
||||
&:hover {
|
||||
background-color: var(--secondary-button-hovered);
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
|
||||
import CodeInput from './CodeInput.svelte'
|
||||
|
||||
export let fields: { id: string, name: string, optional: boolean }[] = []
|
||||
export let size: 'small' | 'medium' = 'small'
|
||||
export let kind: 'primary' | 'secondary' = 'primary'
|
||||
export let padding: string | null = null
|
||||
export let minHeight: string | null = null
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const formData: Record<string, string> = Object.fromEntries(fields.map(({ name }) => [name, '']))
|
||||
|
||||
let formElement: HTMLFormElement | undefined
|
||||
|
||||
function trim (field: string): void {
|
||||
formData[field] = formData[field].trim()
|
||||
}
|
||||
|
||||
async function validateCode (): Promise<void> {
|
||||
const code = Object.values(formData).join('')
|
||||
|
||||
dispatch('submit', code)
|
||||
}
|
||||
|
||||
function onInput (e: Event): void {
|
||||
if (e.target == null) return
|
||||
const target = e.target as HTMLInputElement
|
||||
const { value } = target
|
||||
if (value == null || value === '') return
|
||||
const index = fields.findIndex(({ id }) => id === target.id)
|
||||
if (index === -1) return
|
||||
if (Object.values(formData).every((v) => v !== '')) {
|
||||
void validateCode()
|
||||
return
|
||||
}
|
||||
const nextField = fields[index + 1]
|
||||
if (nextField === undefined) return
|
||||
const nextInput = formElement?.querySelector(`input[name="${nextField.name}"]`) as HTMLInputElement
|
||||
if (nextInput != null) {
|
||||
nextInput.focus()
|
||||
}
|
||||
}
|
||||
|
||||
function onKeydown (e: KeyboardEvent): void {
|
||||
const key = e.key.toLowerCase()
|
||||
const target = e.target as HTMLInputElement
|
||||
if (key !== 'backspace' && key !== 'delete') return
|
||||
const index = fields.findIndex(({ id }) => id === target.id)
|
||||
if (index === -1) return
|
||||
const { value } = target
|
||||
target.value = ''
|
||||
formData[fields[index].name] = ''
|
||||
if (value === '') {
|
||||
const prevField = fields[index - 1]
|
||||
if (prevField === undefined) return
|
||||
const prevInput = formElement?.querySelector(`input[name="${prevField.name}"]`) as HTMLInputElement
|
||||
if (prevInput != null) {
|
||||
prevInput.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onPaste (e: ClipboardEvent): void {
|
||||
e.preventDefault()
|
||||
if (e.clipboardData == null) return
|
||||
const text = e.clipboardData.getData('text')
|
||||
const digits = text.split('').filter((it) => it !== ' ')
|
||||
if (digits.length !== fields.length) return
|
||||
let focusName: string | undefined = undefined
|
||||
for (const field of fields) {
|
||||
const digit = digits.shift()
|
||||
if (digit === undefined) break
|
||||
formData[field.name] = digit
|
||||
focusName = field.name
|
||||
}
|
||||
if (focusName !== undefined && focusName !== '' && formElement) {
|
||||
const input = formElement.querySelector(`input[name="${focusName}"]`) as HTMLInputElement | undefined
|
||||
input?.focus()
|
||||
}
|
||||
if (Object.values(formData).every((v) => v !== '')) {
|
||||
void validateCode()
|
||||
}
|
||||
}
|
||||
|
||||
$: if (formElement != null) {
|
||||
formElement.addEventListener('input', onInput)
|
||||
formElement.addEventListener('keydown', onKeydown)
|
||||
formElement.addEventListener('paste', onPaste)
|
||||
const firstInput = formElement.querySelector(`input[name="${fields[0].name}"]`) as HTMLInputElement | undefined
|
||||
firstInput?.focus()
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (formElement !== undefined) {
|
||||
formElement.removeEventListener('input', onInput)
|
||||
formElement.removeEventListener('keydown', onKeydown)
|
||||
formElement.removeEventListener('paste', onPaste)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<form bind:this={formElement} class="container" style:padding style:min-height={minHeight}>
|
||||
<div class="form">
|
||||
{#each fields as field, index (field.name)}
|
||||
{#if index === fields.length / 2}
|
||||
<div class="separator" />
|
||||
{/if}
|
||||
<div class={'form-row'}>
|
||||
<CodeInput
|
||||
id={field.id}
|
||||
name={field.name}
|
||||
{size}
|
||||
{kind}
|
||||
bind:value={formData[field.name]}
|
||||
on:blur={() => {
|
||||
trim(field.name)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
.separator {
|
||||
display: block;
|
||||
width: 0.75rem;
|
||||
height: 1px;
|
||||
background-color: var(--theme-button-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.form {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -18,9 +18,10 @@
|
||||
export let id: string | undefined = undefined
|
||||
export let name: string | undefined = undefined
|
||||
export let size: 'small' | 'medium' = 'small'
|
||||
export let kind: 'primary' | 'secondary' = 'primary'
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="container {kind}">
|
||||
<input
|
||||
class={size}
|
||||
type="text"
|
||||
@@ -45,14 +46,20 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
|
||||
background-color: var(--theme-button-default);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
caret-color: var(--theme-caret-color);
|
||||
|
||||
&.primary {
|
||||
caret-color: var(--theme-content-color);
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
caret-color: var(--theme-caret-color);
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
background-color: var(--theme-button-focused);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
background-color: var(--theme-button-focused);
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
export let colorsSchema: 'default' | 'lumia' = 'default'
|
||||
export let updateOnMouse = true
|
||||
export let lazy = false
|
||||
export let minHeight: string | null = null
|
||||
export let highlightIndex: number | undefined = undefined
|
||||
const getKey: (index: number) => string = (index) => index.toString()
|
||||
|
||||
@@ -76,35 +77,37 @@
|
||||
>
|
||||
{#each Array(count) as _, row (getKey(row))}
|
||||
{#if lazy}
|
||||
<Lazy>
|
||||
<ListViewItem
|
||||
bind:element={refs[row]}
|
||||
{colorsSchema}
|
||||
{addClass}
|
||||
{row}
|
||||
{kind}
|
||||
isHighlighted={row === highlightIndex}
|
||||
selected={row === selection}
|
||||
on:click={() => dispatch('click', row)}
|
||||
on:mouseover={mouseAttractor(() => {
|
||||
if (updateOnMouse) {
|
||||
onRow(row)
|
||||
}
|
||||
})}
|
||||
on:mouseenter={mouseAttractor(() => {
|
||||
if (updateOnMouse) {
|
||||
onRow(row)
|
||||
}
|
||||
})}
|
||||
>
|
||||
<svelte:fragment slot="category" let:item={itemIndex}>
|
||||
<slot name="category" item={itemIndex} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="item" let:item={itemIndex}>
|
||||
<slot name="item" item={itemIndex} />
|
||||
</svelte:fragment>
|
||||
</ListViewItem>
|
||||
</Lazy>
|
||||
<div style="min-height: {minHeight}">
|
||||
<Lazy>
|
||||
<ListViewItem
|
||||
bind:element={refs[row]}
|
||||
{colorsSchema}
|
||||
{addClass}
|
||||
{row}
|
||||
{kind}
|
||||
isHighlighted={row === highlightIndex}
|
||||
selected={row === selection}
|
||||
on:click={() => dispatch('click', row)}
|
||||
on:mouseover={mouseAttractor(() => {
|
||||
if (updateOnMouse) {
|
||||
onRow(row)
|
||||
}
|
||||
})}
|
||||
on:mouseenter={mouseAttractor(() => {
|
||||
if (updateOnMouse) {
|
||||
onRow(row)
|
||||
}
|
||||
})}
|
||||
>
|
||||
<svelte:fragment slot="category" let:item={itemIndex}>
|
||||
<slot name="category" item={itemIndex} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="item" let:item={itemIndex}>
|
||||
<slot name="item" item={itemIndex} />
|
||||
</svelte:fragment>
|
||||
</ListViewItem>
|
||||
</Lazy>
|
||||
</div>
|
||||
{:else}
|
||||
<ListViewItem
|
||||
bind:element={refs[row]}
|
||||
|
||||
@@ -265,6 +265,7 @@ export { default as SimpleTimePopup } from './components/calendar/SimpleTimePopu
|
||||
export { default as NumberInput } from './components/NumberInput.svelte'
|
||||
export { default as Lazy } from './components/Lazy.svelte'
|
||||
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'
|
||||
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
"SaveForLater": "Save for later",
|
||||
"RemoveFromLater": "Remove from saved",
|
||||
"ReactionNotificationTitle": "Reaction on {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "New {object}",
|
||||
"RemovedObject": "Removed {object}",
|
||||
"ChangedObject": "Changed {object}",
|
||||
"UnsetObject": "Unset {object}",
|
||||
"UpdatedObject": "Updated {object}"
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,11 @@
|
||||
"SaveForLater": "Guardar para mas tarde",
|
||||
"RemoveFromLater": "Remover de los Guardados",
|
||||
"ReactionNotificationTitle": "Reacción sobre {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "Nuevo {object}",
|
||||
"RemovedObject": "Eliminado {object}",
|
||||
"ChangedObject": "Cambiado {object}",
|
||||
"UnsetObject": "No establecido {object}",
|
||||
"UpdatedObject": "Actualizado {object}"
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@
|
||||
"SaveForLater": "Enregistrer pour plus tard",
|
||||
"RemoveFromLater": "Retirer des enregistrements",
|
||||
"ReactionNotificationTitle": "Réaction sur {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "Nouveau {object}",
|
||||
"RemovedObject": "Supprimé {object}",
|
||||
"ChangedObject": "Modifié {object}",
|
||||
"UnsetObject": "Non défini {object}",
|
||||
"UpdatedObject": "Mis à jour {object}"
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,11 @@
|
||||
"SaveForLater": "Guardar para mais tarde",
|
||||
"RemoveFromLater": "Remover dos Guardados",
|
||||
"ReactionNotificationTitle": "Reação em {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "Novo {object}",
|
||||
"RemovedObject": "Removido {object}",
|
||||
"ChangedObject": "Alterado {object}",
|
||||
"UnsetObject": "Não definido {object}",
|
||||
"UpdatedObject": "Atualizado {object}"
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@
|
||||
"SaveForLater": "Cохранить",
|
||||
"RemoveFromLater": "Удалить из сохраненных",
|
||||
"ReactionNotificationTitle": "Реакция на {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "Новый(ые) {object}",
|
||||
"RemovedObject": "Удален(ы) {object}",
|
||||
"ChangedObject": "Изменил(а) {object}",
|
||||
"UnsetObject": "Сбросил(а) {object}",
|
||||
"UpdatedObject": "Обновил(а) {object}"
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@
|
||||
"SaveForLater": "稍后保存",
|
||||
"RemoveFromLater": "从保存中移除",
|
||||
"ReactionNotificationTitle": "反應於 {title}",
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}"
|
||||
"ReactionNotificationBody": "{senderName}: {reaction}",
|
||||
"NewObject": "新 {object}",
|
||||
"RemovedObject": "移除 {object}",
|
||||
"ChangedObject": "更改 {object}",
|
||||
"UnsetObject": "取消设置 {object}",
|
||||
"UpdatedObject": "更新 {object}"
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,20 +16,22 @@
|
||||
import { Component } from '@hcengineering/ui'
|
||||
import { AttributeModel } from '@hcengineering/view'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { DocAttributeUpdates, DocUpdateMessageViewlet } from '@hcengineering/activity'
|
||||
import { DocAttributeUpdates, DocUpdateMessage, DocUpdateMessageViewlet } from '@hcengineering/activity'
|
||||
import { Doc, Ref, Space } from '@hcengineering/core'
|
||||
|
||||
import activity from '../../plugin'
|
||||
|
||||
import AddedAttributesPresenter from './attributes/AddedAttributesPresenter.svelte'
|
||||
import RemovedAttributesPresenter from './attributes/RemovedAttributesPresenter.svelte'
|
||||
import SetAttributesPresenter from './attributes/SetAttributesPresenter.svelte'
|
||||
import { Ref, Space } from '@hcengineering/core'
|
||||
|
||||
export let viewlet: DocUpdateMessageViewlet | undefined
|
||||
export let attributeUpdates: DocAttributeUpdates
|
||||
export let attributeModel: AttributeModel
|
||||
export let preview = false
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let object: Doc | undefined
|
||||
export let message: DocUpdateMessage
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
@@ -41,7 +43,7 @@
|
||||
</script>
|
||||
|
||||
{#if presenter}
|
||||
<Component is={presenter} props={{ value: attributeUpdates, space }} />
|
||||
<Component is={presenter} props={{ value: attributeUpdates, space, object, message }} />
|
||||
{:else}
|
||||
{#if attributeUpdates.added.length}
|
||||
<AddedAttributesPresenter {viewlet} {attributeModel} values={attributeUpdates.added} {preview} />
|
||||
|
||||
+16
-6
@@ -58,30 +58,40 @@
|
||||
{@const removeMessages = valueMessages.filter(({ action }) => action === 'remove')}
|
||||
{@const createMessages = valueMessages.filter(({ action }) => action === 'create')}
|
||||
|
||||
{@const createMessagesLen = createMessages.length}
|
||||
{@const removeMessagesLen = removeMessages.length}
|
||||
|
||||
{#each createMessages as valueMessage, index}
|
||||
<DocUpdateMessageObjectValue
|
||||
message={valueMessage}
|
||||
objectClass={valueMessage.objectClass}
|
||||
objectId={valueMessage.objectId}
|
||||
action={valueMessage.action}
|
||||
{viewlet}
|
||||
withIcon={index === 0}
|
||||
hasSeparator={createMessages.length > 1 && index !== createMessages.length - 1}
|
||||
hasSeparator={createMessagesLen > 1 && index !== createMessagesLen - 1}
|
||||
{preview}
|
||||
/>
|
||||
{/each}
|
||||
{#each removeMessages as valueMessage, index}
|
||||
<DocUpdateMessageObjectValue
|
||||
message={valueMessage}
|
||||
objectClass={valueMessage.objectClass}
|
||||
objectId={valueMessage.objectId}
|
||||
action={valueMessage.action}
|
||||
{viewlet}
|
||||
withIcon={index === 0}
|
||||
hasSeparator={removeMessages.length > 1 && index !== removeMessages.length - 1}
|
||||
hasSeparator={removeMessagesLen > 1 && index !== removeMessagesLen - 1}
|
||||
{preview}
|
||||
/>
|
||||
{/each}
|
||||
{:else}
|
||||
{@const len = valueMessages.length}
|
||||
{#each valueMessages as valueMessage, index}
|
||||
<DocUpdateMessageObjectValue
|
||||
message={valueMessage}
|
||||
objectClass={valueMessage.objectClass}
|
||||
objectId={valueMessage.objectId}
|
||||
action={valueMessage.action}
|
||||
{viewlet}
|
||||
hasSeparator={valueMessages.length > 1 && index !== valueMessages.length - 1}
|
||||
hasSeparator={len > 1 && index !== len - 1}
|
||||
{preview}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
+15
-12
@@ -13,14 +13,16 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { buildRemovedDoc, checkIsObjectRemoved, DocNavLink, getDocLinkTitle } from '@hcengineering/view-resources'
|
||||
import { Component, Icon, IconAdd, IconDelete } from '@hcengineering/ui'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import view from '@hcengineering/view'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { DisplayDocUpdateMessage, DocUpdateMessageViewlet } from '@hcengineering/activity'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Component, Icon, IconAdd, IconDelete } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { buildRemovedDoc, checkIsObjectRemoved, DocNavLink, getDocLinkTitle } from '@hcengineering/view-resources'
|
||||
|
||||
export let message: DisplayDocUpdateMessage
|
||||
export let objectClass: DisplayDocUpdateMessage['objectClass']
|
||||
export let objectId: DisplayDocUpdateMessage['objectId']
|
||||
export let action: DisplayDocUpdateMessage['action']
|
||||
export let viewlet: DocUpdateMessageViewlet | undefined
|
||||
export let withIcon: boolean = false
|
||||
export let hasSeparator: boolean = false
|
||||
@@ -32,8 +34,8 @@
|
||||
|
||||
let object: Doc | undefined = undefined
|
||||
|
||||
$: objectPanel = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPanel)
|
||||
$: objectPresenter = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPresenter)
|
||||
$: objectPanel = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPanel)
|
||||
$: objectPresenter = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPresenter)
|
||||
|
||||
async function getValue (object: Doc): Promise<string | undefined> {
|
||||
if (viewlet?.valueAttr) {
|
||||
@@ -48,6 +50,7 @@
|
||||
|
||||
if (isRemoved) {
|
||||
object = await buildRemovedDoc(client, _id, _class)
|
||||
objectQuery.unsubscribe()
|
||||
} else {
|
||||
objectQuery.query(_class, { _id }, (res) => {
|
||||
object = res[0]
|
||||
@@ -55,14 +58,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: void loadObject(message.objectId, message.objectClass)
|
||||
$: void loadObject(objectId, objectClass)
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
{#if withIcon && message.action === 'create'}
|
||||
{#if withIcon && action === 'create'}
|
||||
<Icon icon={IconAdd} size="x-small" />
|
||||
{/if}
|
||||
{#if withIcon && message.action === 'remove'}
|
||||
{#if withIcon && action === 'remove'}
|
||||
<Icon icon={IconDelete} size="x-small" />
|
||||
{/if}
|
||||
|
||||
@@ -80,7 +83,7 @@
|
||||
<DocNavLink
|
||||
{object}
|
||||
colorInherit
|
||||
disabled={message.action === 'remove'}
|
||||
disabled={action === 'remove'}
|
||||
component={objectPanel?.component ?? view.component.EditDoc}
|
||||
shrink={0}
|
||||
>
|
||||
|
||||
+15
-8
@@ -26,7 +26,7 @@
|
||||
import { Account, AttachedDoc, Class, Collection, Doc, Ref, Space } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Component, ShowMore, Action } from '@hcengineering/ui'
|
||||
import { Action, Component, ShowMore } from '@hcengineering/ui'
|
||||
import { AttributeModel } from '@hcengineering/view'
|
||||
import { buildRemovedDoc, checkIsObjectRemoved } from '@hcengineering/view-resources'
|
||||
|
||||
@@ -144,17 +144,17 @@
|
||||
}
|
||||
|
||||
async function loadParentObject (
|
||||
message: DocUpdateMessage,
|
||||
parentMessage?: ActivityMessage,
|
||||
message: Pick<DocUpdateMessage, 'attachedTo' | 'attachedToClass' | 'objectId' | 'space'>,
|
||||
parentMessage?: Pick<ActivityMessage, 'attachedTo' | 'space' | 'attachedToClass'>,
|
||||
doc?: Doc
|
||||
): Promise<void> {
|
||||
if (!parentMessage && message.objectId === message.attachedTo) {
|
||||
if (parentMessage === undefined && message.objectId === message.attachedTo) {
|
||||
return
|
||||
}
|
||||
|
||||
const _id = parentMessage ? parentMessage.attachedTo : message.attachedTo
|
||||
const _class = parentMessage ? parentMessage.attachedToClass : message.attachedToClass
|
||||
const space = parentMessage ? parentMessage.space : message.space
|
||||
const _id = parentMessage !== undefined ? parentMessage.attachedTo : message.attachedTo
|
||||
const _class = parentMessage !== undefined ? parentMessage.attachedToClass : message.attachedToClass
|
||||
const space = parentMessage !== undefined ? parentMessage.space : message.space
|
||||
|
||||
if (doc !== undefined && doc._id === _id) {
|
||||
parentObject = doc
|
||||
@@ -229,7 +229,14 @@
|
||||
/>
|
||||
</ShowMore>
|
||||
{:else if value.attributeUpdates && attributeModel}
|
||||
<DocUpdateMessageAttributes attributeUpdates={value.attributeUpdates} {attributeModel} {viewlet} {space} />
|
||||
<DocUpdateMessageAttributes
|
||||
attributeUpdates={value.attributeUpdates}
|
||||
{attributeModel}
|
||||
{viewlet}
|
||||
{space}
|
||||
{object}
|
||||
message={value}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</ActivityMessageTemplate>
|
||||
|
||||
+2
@@ -130,6 +130,8 @@
|
||||
{attributeModel}
|
||||
{space}
|
||||
{viewlet}
|
||||
{object}
|
||||
message={value}
|
||||
preview
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -67,6 +67,7 @@ export interface ActivityMessageControl<T extends Doc = Doc> extends Doc {
|
||||
|
||||
// Skip field activity operations.
|
||||
skipFields?: (keyof T)[]
|
||||
allowedFields?: (keyof T)[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,7 +309,12 @@ export default plugin(activityId, {
|
||||
Messages: '' as IntlString,
|
||||
Thread: '' as IntlString,
|
||||
ReactionNotificationTitle: '' as IntlString,
|
||||
ReactionNotificationBody: '' as IntlString
|
||||
ReactionNotificationBody: '' as IntlString,
|
||||
NewObject: '' as IntlString,
|
||||
RemovedObject: '' as IntlString,
|
||||
ChangedObject: '' as IntlString,
|
||||
UnsetObject: '' as IntlString,
|
||||
UpdatedObject: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
Activity: '' as AnyComponent,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@hcengineering/ai-bot",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*",
|
||||
"types/**/*",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"author": "Hardcore Engineering Inc",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.1.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/chunter": "^0.6.20",
|
||||
"@hcengineering/contact": "^0.6.24",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
"@hcengineering/view": "^0.6.13"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// 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 { Account, Class, Doc, type Mixin, Ref, Space } from '@hcengineering/core'
|
||||
import type { Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { ChatMessage } from '@hcengineering/chunter'
|
||||
|
||||
export const aiBotId = 'ai-bot' as Plugin
|
||||
|
||||
export const aiBotAccountEmail = 'huly.ai.bot@hc.engineering'
|
||||
|
||||
export interface AIBotEvent extends Doc {
|
||||
collection: string
|
||||
messageClass: Ref<Class<ChatMessage>>
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface AIBotResponseEvent extends AIBotEvent {
|
||||
objectId: Ref<Doc>
|
||||
objectClass: Ref<Class<Doc>>
|
||||
objectSpace: Ref<Space>
|
||||
user: Ref<Account>
|
||||
}
|
||||
|
||||
export interface AIBotTransferEvent extends AIBotEvent {
|
||||
toEmail: string
|
||||
toWorkspace: string
|
||||
fromWorkspace: string
|
||||
messageId: Ref<ChatMessage>
|
||||
parentMessageId?: Ref<ChatMessage>
|
||||
}
|
||||
|
||||
export interface TransferredMessage extends ChatMessage {
|
||||
messageId: Ref<ChatMessage>
|
||||
parentMessageId?: Ref<ChatMessage>
|
||||
}
|
||||
|
||||
const aiBot = plugin(aiBotId, {
|
||||
class: {
|
||||
AIBotEvent: '' as Ref<Class<AIBotEvent>>,
|
||||
AIBotTransferEvent: '' as Ref<Class<AIBotTransferEvent>>,
|
||||
AIBotResponseEvent: '' as Ref<Class<AIBotResponseEvent>>
|
||||
},
|
||||
mixin: {
|
||||
TransferredMessage: '' as Ref<Mixin<TransferredMessage>>
|
||||
},
|
||||
account: {
|
||||
AIBot: '' as Ref<Account>
|
||||
}
|
||||
})
|
||||
|
||||
export default aiBot
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "Once you've joined, you'll be able to read all messages and contribute to the discussion.",
|
||||
"NoMessagesInChannel": "Currently there are no messages",
|
||||
"SendMessagesInChannel": "Send the first message to start the conversation",
|
||||
"LatestMessages": "↓ Latest messages"
|
||||
"LatestMessages": "↓ Latest messages",
|
||||
"Joined": "Joined",
|
||||
"Left": "Left",
|
||||
"Added": "Added",
|
||||
"Removed": "Removed",
|
||||
"CreatedChannelOn": "Created this channel on {date}",
|
||||
"ChannelMessages": "Channel messages",
|
||||
"JoinChannel": "Join channel",
|
||||
"YouJoinedChannel": "You have been joined to channel"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "Una vez que se haya unido, podrá leer todos los mensajes y contribuir a la discusión.",
|
||||
"NoMessagesInChannel": "No hay mensajes en este canal todavía.",
|
||||
"SendMessagesInChannel": "Envíe mensajes en este canal para comenzar la conversación.",
|
||||
"LatestMessages": "↓ Últimos mensajes"
|
||||
"LatestMessages": "↓ Últimos mensajes",
|
||||
"Joined": "Unido",
|
||||
"Left": "Abandonado",
|
||||
"Added": "Añadido",
|
||||
"Removed": "Eliminado",
|
||||
"CreatedChannelOn": "Creó este canal el {date}",
|
||||
"ChannelMessages": "Mensajes del canal",
|
||||
"JoinChannel": "Unirse",
|
||||
"YouJoinedChannel": "Te has unido al canal"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "Une fois que vous avez rejoint, vous pourrez lire tous les messages et participer à la discussion.",
|
||||
"NoMessagesInChannel": "Il n'y a pas encore de messages dans ce canal.",
|
||||
"SendMessagesInChannel": "Envoyez des messages pour commencer la conversation.",
|
||||
"LatestMessages": "↓ Derniers messages"
|
||||
"LatestMessages": "↓ Derniers messages",
|
||||
"Joined": "Rejoint",
|
||||
"Left": "Quitté",
|
||||
"Added": "Ajouté",
|
||||
"Removed": "Supprimé",
|
||||
"CreatedChannelOn": "A créé ce canal le {date}",
|
||||
"ChannelMessages": "Messages du canal",
|
||||
"JoinChannel": "Rejoindre",
|
||||
"YouJoinedChannel": "Vous avez rejoint le canal"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "Depois de entrar, você poderá ler todas as mensagens e contribuir na discussão.",
|
||||
"NoMessagesInChannel": "Ainda não existem mensagens neste canal.",
|
||||
"SendMessagesInChannel": "Envie a sua primeira mensagem!",
|
||||
"LatestMessages": "↓ Últimas mensagens"
|
||||
"LatestMessages": "↓ Últimas mensagens",
|
||||
"Joined": "Entrou",
|
||||
"Left": "Saiu",
|
||||
"Added": "Adicionado(a)",
|
||||
"Removed": "Removido(a)",
|
||||
"CreatedChannelOn": "Criou este canal em {date}",
|
||||
"ChannelMessages": "Mensagens do canal",
|
||||
"JoinChannel": "Participar no canal",
|
||||
"YouJoinedChannel": "Entrou no canal"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "Присоединившись, вы сможете читать все сообщения и участвовать в обсуждении.",
|
||||
"NoMessagesInChannel": "В этом канале пока нет сообщений",
|
||||
"SendMessagesInChannel": "Отправьте первое сообщение, чтобы начать общение",
|
||||
"LatestMessages": "↓ Последние сообщения"
|
||||
"LatestMessages": "↓ Последние сообщения",
|
||||
"Joined": "Присоединился",
|
||||
"Left": "Покинул",
|
||||
"Added": "Добавил(а)",
|
||||
"Removed": "Исключил(а)",
|
||||
"CreatedChannelOn": "Создал этот канал {date}",
|
||||
"ChannelMessages": "Сообщения каналов",
|
||||
"JoinChannel": "Приссоединение к каналу",
|
||||
"YouJoinedChannel": "Вы присоединились к каналу"
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,14 @@
|
||||
"JoinChannelText": "加入后,你将能够阅读所有消息并参与讨论。",
|
||||
"NoMessagesInChannel": "此频道中没有消息。",
|
||||
"SendMessagesInChannel": "在此频道中发送消息。",
|
||||
"LatestMessages": "↓ 最新消息"
|
||||
"LatestMessages": "↓ 最新消息",
|
||||
"Joined": "已加入",
|
||||
"Left": "已离开",
|
||||
"Added": "已添加",
|
||||
"Removed": "已移除",
|
||||
"CreatedChannelOn": "于 {date} 创建此频道",
|
||||
"ChannelMessages": "频道消息",
|
||||
"JoinChannel": "加入频道",
|
||||
"YouJoinedChannel": "你已加入频道"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,8 @@ import { derived, get, type Readable, writable } from 'svelte/store'
|
||||
import activity, { type ActivityMessage, type ActivityReference } from '@hcengineering/activity'
|
||||
import attachment from '@hcengineering/attachment'
|
||||
import { combineActivityMessages, sortActivityMessages } from '@hcengineering/activity-resources'
|
||||
import { type ChatMessage } from '@hcengineering/chunter'
|
||||
import notification, { type DocNotifyContext } from '@hcengineering/notification'
|
||||
|
||||
import chunter from './plugin'
|
||||
|
||||
export type LoadMode = 'forward' | 'backward'
|
||||
|
||||
export interface MessageMetadata {
|
||||
@@ -241,7 +238,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
|
||||
if (loadAll) {
|
||||
this.isTailLoading.set(true)
|
||||
this.loadTail(undefined, combineActivityMessages)
|
||||
this.loadTail()
|
||||
} else if (isLoadingLatest) {
|
||||
const startIndex = Math.max(0, count - this.limit)
|
||||
this.isTailLoading.set(true)
|
||||
@@ -260,11 +257,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
this.isInitialLoadedStore.set(true)
|
||||
}
|
||||
|
||||
private loadTail (
|
||||
start?: Timestamp,
|
||||
afterLoad?: (msgs: ActivityMessage[]) => Promise<ActivityMessage[]>,
|
||||
query?: DocumentQuery<ActivityMessage>
|
||||
): void {
|
||||
private loadTail (start?: Timestamp, query?: DocumentQuery<ActivityMessage>): void {
|
||||
if (this.chatId === undefined) {
|
||||
this.isTailLoading.set(false)
|
||||
return
|
||||
@@ -283,12 +276,8 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
...(this.tailStart !== undefined ? { createdOn: { $gte: this.tailStart } } : {})
|
||||
},
|
||||
async (res) => {
|
||||
if (afterLoad !== undefined) {
|
||||
const result = await afterLoad(res.reverse())
|
||||
this.tailStore.set(result)
|
||||
} else {
|
||||
this.tailStore.set(res.reverse())
|
||||
}
|
||||
const result = await combineActivityMessages(res.reverse())
|
||||
this.tailStore.set(result)
|
||||
|
||||
this.isTailLoaded.set(true)
|
||||
this.isTailLoading.set(false)
|
||||
@@ -325,7 +314,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
const skipIds = this.getChunkSkipIds(loadAfter)
|
||||
|
||||
const messages = await client.findAll(
|
||||
chunter.class.ChatMessage,
|
||||
this.msgClass,
|
||||
{
|
||||
attachedTo: this.chatId,
|
||||
space: this.space,
|
||||
@@ -351,11 +340,11 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
return {
|
||||
from: from.createdOn ?? from.modifiedOn,
|
||||
to: to.createdOn ?? to.modifiedOn,
|
||||
data: isBackward ? messages.reverse() : messages
|
||||
data: isBackward ? await combineActivityMessages(messages.reverse()) : await combineActivityMessages(messages)
|
||||
}
|
||||
}
|
||||
|
||||
getChunkSkipIds (after: Timestamp, loadTail = false): Array<Ref<ChatMessage>> {
|
||||
getChunkSkipIds (after: Timestamp, loadTail = false): Array<Ref<ActivityMessage>> {
|
||||
const chunks = get(this.chunksStore)
|
||||
const metadata = get(this.metadataStore)
|
||||
const tail = get(this.tailStore)
|
||||
@@ -367,7 +356,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
.flat()
|
||||
.concat(loadTail ? [] : tailData)
|
||||
.filter(({ createdOn }) => createdOn === after)
|
||||
.map(({ _id }) => _id) as Array<Ref<ChatMessage>>
|
||||
.map(({ _id }) => _id)
|
||||
}
|
||||
|
||||
async loadNext (mode: LoadMode, loadAfter?: Timestamp, limit?: number): Promise<void> {
|
||||
@@ -467,7 +456,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
|
||||
|
||||
if (tailAfter !== undefined) {
|
||||
const skipIds = chunks[chunks.length - 1]?.data.map(({ _id }) => _id) ?? []
|
||||
this.loadTail(tailAfter, undefined, { _id: { $nin: skipIds } })
|
||||
this.loadTail(tailAfter, { _id: { $nin: skipIds } })
|
||||
this.isLoadingMoreStore.set(false)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Doc, getCurrentAccount, Ref } from '@hcengineering/core'
|
||||
import { Doc, getCurrentAccount, Ref } from '@hcengineering/core'
|
||||
import notification, { DocNotifyContext } from '@hcengineering/notification'
|
||||
import activity, { ActivityMessage, ActivityMessagesFilter, WithReferences } from '@hcengineering/activity'
|
||||
import { getClient, isSpace } from '@hcengineering/presentation'
|
||||
@@ -60,16 +60,11 @@
|
||||
let refsLoaded = false
|
||||
|
||||
$: isDocChannel = !hierarchy.isDerived(object._class, chunter.class.ChunterSpace)
|
||||
$: _class = isDocChannel ? activity.class.ActivityMessage : chunter.class.ChatMessage
|
||||
$: collection = isDocChannel ? 'comments' : 'messages'
|
||||
|
||||
$: void updateDataProvider(object._id, _class, selectedMessageId)
|
||||
$: void updateDataProvider(object._id, selectedMessageId)
|
||||
|
||||
async function updateDataProvider (
|
||||
attachedTo: Ref<Doc>,
|
||||
_class: Ref<Class<ActivityMessage>>,
|
||||
selectedMessageId?: Ref<ActivityMessage>
|
||||
): Promise<void> {
|
||||
async function updateDataProvider (attachedTo: Ref<Doc>, selectedMessageId?: Ref<ActivityMessage>): Promise<void> {
|
||||
if (dataProvider === undefined) {
|
||||
// For now loading all messages for documents with activity. Need to correct handle aggregation with pagination.
|
||||
// Perhaps we should load all activity messages once, and keep loading in chunks only for ChatMessages then merge them correctly with activity messages
|
||||
@@ -77,13 +72,21 @@
|
||||
const ctx =
|
||||
context ??
|
||||
(await client.findOne(notification.class.DocNotifyContext, {
|
||||
attachedTo: object._id,
|
||||
objectId: object._id,
|
||||
user: getCurrentAccount()._id
|
||||
}))
|
||||
const hasRefs = ((object as WithReferences<Doc>).references ?? 0) > 0
|
||||
refsLoaded = hasRefs
|
||||
const space = isSpace(object) ? object._id : object.space
|
||||
dataProvider = new ChannelDataProvider(ctx, space, attachedTo, _class, selectedMessageId, loadAll, hasRefs)
|
||||
dataProvider = new ChannelDataProvider(
|
||||
ctx,
|
||||
space,
|
||||
attachedTo,
|
||||
activity.class.ActivityMessage,
|
||||
selectedMessageId,
|
||||
loadAll,
|
||||
hasRefs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
/>
|
||||
</div>
|
||||
<Scroller>
|
||||
{#each persons as person, index}
|
||||
{#each persons as person, index (person._id)}
|
||||
<div class="item" class:withoutBorder={index === persons.length - 1}>
|
||||
<div class="item__content" class:disabled={disableRemoveFor.includes(person._id)}>
|
||||
<UserDetails {person} showStatus />
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
<Label label={chunter.string.JoinChannelText} />
|
||||
</span>
|
||||
<span class="mt-4"> </span>
|
||||
<ModernButton label={view.string.Join} kind="primary" on:click={join} />
|
||||
<ModernButton label={view.string.Join} kind={'primary'} dataId={'btnJoin'} on:click={join} />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -43,19 +43,19 @@
|
||||
$: pinnedQuery.query(
|
||||
activity.class.ActivityMessage,
|
||||
{ attachedTo: _id, isPinned: true, space: channelSpace },
|
||||
(res: ActivityMessage[]) => {
|
||||
pinnedMessagesCount = res.length
|
||||
(res) => {
|
||||
pinnedMessagesCount = res.total
|
||||
},
|
||||
{ projection: { _id: 1, space: 1, attachedTo: 1, isPinned: 1 } }
|
||||
{ total: true, limit: 1 }
|
||||
)
|
||||
|
||||
$: pinnedThreadsQuery.query(
|
||||
chunter.class.ThreadMessage,
|
||||
{ objectId: _id, isPinned: true, space: channelSpace },
|
||||
(res: ThreadMessage[]) => {
|
||||
pinnedThreadsCount = res.length
|
||||
(res) => {
|
||||
pinnedThreadsCount = res.total
|
||||
},
|
||||
{ projection: { _id: 1, space: 1, objectId: 1, isPinned: 1 } }
|
||||
{ total: true, limit: 1 }
|
||||
)
|
||||
|
||||
$: if (withRefs) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { DocUpdateMessage } from '@hcengineering/activity'
|
||||
import chunter, { Channel } from '@hcengineering/chunter'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
|
||||
import ChannelIcon from '../ChannelIcon.svelte'
|
||||
|
||||
export let message: DocUpdateMessage
|
||||
export let value: Channel | undefined
|
||||
|
||||
$: date = new Date(message.createdOn ?? message.modifiedOn).toLocaleString('default', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric'
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<span class="text flex-gap-1 overflow-label">
|
||||
<ChannelIcon {value} size="x-small" />
|
||||
<Label label={chunter.string.CreatedChannelOn} params={{ date }} />
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.text {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--global-secondary-TextColor);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,128 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { DocAttributeUpdates, DocUpdateMessage } from '@hcengineering/activity'
|
||||
import { Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { personAccountByIdStore, personByIdStore, PersonPresenter } from '@hcengineering/contact-resources'
|
||||
import { ChunterSpace } from '@hcengineering/chunter'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
import chunter from '../../plugin'
|
||||
import ChannelIcon from '../ChannelIcon.svelte'
|
||||
|
||||
export let message: DocUpdateMessage
|
||||
export let value: DocAttributeUpdates
|
||||
export let object: ChunterSpace | undefined
|
||||
|
||||
let addedPersons: Person[] = []
|
||||
let removedPersons: Person[] = []
|
||||
|
||||
$: removedPersons = getPersons(value.removed)
|
||||
$: addedPersons = getPersons(value.added.length > 0 ? value.added : value.set)
|
||||
|
||||
function getPersons (accounts: DocAttributeUpdates['removed' | 'added' | 'set']): Person[] {
|
||||
const persons = new Set<Ref<Person>>()
|
||||
|
||||
for (const accountRef of accounts) {
|
||||
const account = $personAccountByIdStore.get(accountRef as Ref<PersonAccount>)
|
||||
|
||||
if (account === undefined) continue
|
||||
if (persons.has(account.person)) continue
|
||||
|
||||
persons.add(account.person)
|
||||
}
|
||||
|
||||
return Array.from(persons)
|
||||
.map((personRef) => $personByIdStore.get(personRef))
|
||||
.filter((person): person is Person => person !== undefined)
|
||||
}
|
||||
|
||||
$: account = $personAccountByIdStore.get(message.createdBy as Ref<PersonAccount>)
|
||||
|
||||
$: isJoined =
|
||||
account !== undefined &&
|
||||
removedPersons.length === 0 &&
|
||||
addedPersons.length === 1 &&
|
||||
addedPersons[0]._id === account.person
|
||||
$: isLeave =
|
||||
account !== undefined &&
|
||||
removedPersons.length === 1 &&
|
||||
addedPersons.length === 0 &&
|
||||
removedPersons[0]._id === account.person
|
||||
$: differentActions = addedPersons.length > 0 && removedPersons.length > 0
|
||||
</script>
|
||||
|
||||
<span class="text overflow-label">
|
||||
{#if addedPersons.length > 0}
|
||||
<span class="inline-flex flex-gap-1">
|
||||
{#if isJoined}
|
||||
<span class="lower">
|
||||
<Label label={chunter.string.Joined} />
|
||||
</span>
|
||||
<span class="inline-flex"><ChannelIcon value={object} size="x-small" /> {object?.name}</span>
|
||||
{:else}
|
||||
<Label label={chunter.string.Added} />
|
||||
{#each addedPersons as person, index}
|
||||
<PersonPresenter value={person} shouldShowAvatar={false} colorInherit overflowLabel={false} />
|
||||
{#if index < addedPersons.length - 1}
|
||||
<span class="separator"> , </span>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
{#if differentActions}
|
||||
<Label label={view.string.And} />
|
||||
{/if}
|
||||
|
||||
{#if removedPersons.length > 0}
|
||||
<span class="inline-flex flex-gap-1">
|
||||
{#if isLeave}
|
||||
<span class="lower">
|
||||
<Label label={chunter.string.Left} />
|
||||
</span>
|
||||
<span class="inline-flex"><ChannelIcon value={object} size="x-small" /> {object?.name}</span>
|
||||
{:else}
|
||||
<span class:lower={differentActions}>
|
||||
<Label label={chunter.string.Removed} />
|
||||
</span>
|
||||
{#each removedPersons as person, index}
|
||||
<PersonPresenter value={person} shouldShowAvatar={false} colorInherit overflowLabel={false} />
|
||||
{#if index < removedPersons.length - 1}
|
||||
<span class="separator"> , </span>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
.inline-flex {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: var(--global-secondary-TextColor);
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin-left: -0.25rem;
|
||||
}
|
||||
</style>
|
||||
@@ -36,7 +36,7 @@
|
||||
$: threadId = context ? undefined : (_id as Ref<ActivityMessage>)
|
||||
|
||||
$: context &&
|
||||
objectQuery.query(context.attachedToClass, { _id: context.attachedTo }, (res) => {
|
||||
objectQuery.query(context.objectClass, { _id: context.objectId }, (res) => {
|
||||
;[object] = res
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import core, { getCurrentAccount } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import contact, { PersonAccount } from '@hcengineering/contact'
|
||||
|
||||
import Lock from '../../icons/Lock.svelte'
|
||||
import chunter from '../../../plugin'
|
||||
@@ -51,19 +52,28 @@
|
||||
$: canSave = !!channelName
|
||||
|
||||
async function save (): Promise<void> {
|
||||
const accountId = getCurrentAccount()._id
|
||||
const account = getCurrentAccount() as PersonAccount
|
||||
const space = await client.findOne(
|
||||
contact.class.PersonSpace,
|
||||
{ person: account.person },
|
||||
{ projection: { _id: 1 } }
|
||||
)
|
||||
if (!space) return
|
||||
const channelId = await client.createDoc(chunter.class.Channel, core.space.Space, {
|
||||
name: channelName,
|
||||
description: '',
|
||||
private: selectedVisibilityId === 'private',
|
||||
archived: false,
|
||||
members: [accountId],
|
||||
members: [account._id],
|
||||
topic: description
|
||||
})
|
||||
await client.createDoc(notification.class.DocNotifyContext, channelId, {
|
||||
user: accountId,
|
||||
attachedTo: channelId,
|
||||
attachedToClass: chunter.class.Channel
|
||||
|
||||
await client.createDoc(notification.class.DocNotifyContext, space._id, {
|
||||
user: account._id,
|
||||
objectId: channelId,
|
||||
objectClass: chunter.class.Channel,
|
||||
objectSpace: core.space.Space,
|
||||
isPinned: false
|
||||
})
|
||||
|
||||
openChannel(channelId, chunter.class.Channel)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const myAccId = getCurrentAccount()._id
|
||||
const myAcc = getCurrentAccount() as PersonAccount
|
||||
const query = createQuery()
|
||||
|
||||
let employeeIds: Ref<Employee>[] = []
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
async function createDirectMessage (): Promise<void> {
|
||||
const employeeAccounts = await client.findAll(contact.class.PersonAccount, { person: { $in: employeeIds } })
|
||||
const accIds = [myAccId, ...employeeAccounts.filter(({ _id }) => _id !== myAccId).map(({ _id }) => _id)].sort()
|
||||
const accIds = [myAcc._id, ...employeeAccounts.filter(({ _id }) => _id !== myAcc._id).map(({ _id }) => _id)].sort()
|
||||
|
||||
const existingDms = await client.findAll(chunter.class.DirectMessage, {})
|
||||
|
||||
@@ -75,9 +75,9 @@
|
||||
}))
|
||||
|
||||
const context = await client.findOne(notification.class.DocNotifyContext, {
|
||||
user: myAccId,
|
||||
attachedTo: dmId,
|
||||
attachedToClass: chunter.class.DirectMessage
|
||||
person: myAcc.person,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage
|
||||
})
|
||||
|
||||
if (context !== undefined) {
|
||||
@@ -86,10 +86,14 @@
|
||||
return
|
||||
}
|
||||
|
||||
await client.createDoc(notification.class.DocNotifyContext, dmId, {
|
||||
user: myAccId,
|
||||
attachedTo: dmId,
|
||||
attachedToClass: chunter.class.DirectMessage
|
||||
const space = await client.findOne(contact.class.PersonSpace, { person: myAcc.person }, { projection: { _id: 1 } })
|
||||
if (!space) return
|
||||
await client.createDoc(notification.class.DocNotifyContext, space._id, {
|
||||
user: myAcc._id,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage,
|
||||
objectSpace: core.space.Space,
|
||||
isPinned: false
|
||||
})
|
||||
|
||||
openChannel(dmId, chunter.class.DirectMessage)
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import activity from '@hcengineering/activity'
|
||||
import { Class, Doc, getCurrentAccount, groupByArray, reduceCalls, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import notification, { DocNotifyContext } from '@hcengineering/notification'
|
||||
import core, { Class, Doc, groupByArray, reduceCalls, Ref } from '@hcengineering/core'
|
||||
import { DocNotifyContext } from '@hcengineering/notification'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient, LiveQuery } from '@hcengineering/presentation'
|
||||
@@ -40,32 +40,23 @@
|
||||
const hierarchy = client.getHierarchy()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const contextByDocStore = inboxClient.contextByDoc
|
||||
|
||||
const contextsQuery = createQuery()
|
||||
const contextsStore = inboxClient.contexts
|
||||
const objectsQueryByClass = new Map<Ref<Class<Doc>>, { query: LiveQuery, limit: number }>()
|
||||
|
||||
let objectsByClass = new Map<Ref<Class<Doc>>, { docs: Doc[], total: number }>()
|
||||
let contexts: DocNotifyContext[] = []
|
||||
let objectsByClass = new Map<Ref<Class<Doc>>, { docs: Doc[], total: number }>()
|
||||
|
||||
let shouldPushObject = false
|
||||
|
||||
let sections: Section[] = []
|
||||
|
||||
$: contextsQuery.query(
|
||||
notification.class.DocNotifyContext,
|
||||
{
|
||||
...model.query,
|
||||
[`${chunter.mixin.ChannelInfo}.hidden`]: { $ne: true },
|
||||
user: getCurrentAccount()._id
|
||||
},
|
||||
(res: DocNotifyContext[]) => {
|
||||
contexts = res.filter(
|
||||
({ attachedToClass }) =>
|
||||
hierarchy.classHierarchyMixin(attachedToClass, activity.mixin.ActivityDoc) !== undefined
|
||||
)
|
||||
},
|
||||
{ sort: { createdOn: SortingOrder.Ascending } }
|
||||
)
|
||||
$: contexts = $contextsStore.filter(({ objectClass, isPinned }) => {
|
||||
if (model.isPinned !== isPinned) return false
|
||||
if (model._class !== undefined && model._class !== objectClass) return false
|
||||
if (model.skipClasses !== undefined && model.skipClasses.includes(objectClass)) return false
|
||||
if (hierarchy.classHierarchyMixin(objectClass, activity.mixin.ActivityDoc) === undefined) return false
|
||||
return true
|
||||
})
|
||||
|
||||
$: loadObjects(contexts)
|
||||
|
||||
@@ -81,20 +72,29 @@
|
||||
object !== undefined && getObjectGroup(object) === model.id && !$contextByDocStore.has(object._id)
|
||||
|
||||
function loadObjects (contexts: DocNotifyContext[]): void {
|
||||
const contextsByClass = groupByArray(contexts, ({ attachedToClass }) => attachedToClass)
|
||||
const contextsByClass = groupByArray(contexts, ({ objectClass }) => objectClass)
|
||||
|
||||
for (const [_class, ctx] of contextsByClass.entries()) {
|
||||
const ids = ctx.map(({ attachedTo }) => attachedTo)
|
||||
const isChunterSpace = hierarchy.isDerived(_class, chunter.class.ChunterSpace)
|
||||
const ids = ctx.map(({ objectId }) => objectId)
|
||||
const { query, limit } = objectsQueryByClass.get(_class) ?? {
|
||||
query: createQuery(),
|
||||
limit: hierarchy.isDerived(_class, chunter.class.ChunterSpace) ? -1 : model.maxSectionItems ?? 5
|
||||
limit: isChunterSpace ? -1 : model.maxSectionItems ?? 5
|
||||
}
|
||||
|
||||
objectsQueryByClass.set(_class, { query, limit: limit ?? model.maxSectionItems ?? 5 })
|
||||
|
||||
query.query(_class, { _id: { $in: limit !== -1 ? ids.slice(0, limit) : ids } }, (res: Doc[]) => {
|
||||
objectsByClass = objectsByClass.set(_class, { docs: res, total: ids.length })
|
||||
})
|
||||
query.query(
|
||||
_class,
|
||||
{
|
||||
_id: { $in: limit !== -1 ? ids.slice(0, limit) : ids },
|
||||
space: isChunterSpace ? core.space.Space : undefined
|
||||
},
|
||||
(res) => {
|
||||
objectsByClass = objectsByClass.set(_class, { docs: res, total: res.total })
|
||||
},
|
||||
{ total: true }
|
||||
)
|
||||
}
|
||||
|
||||
for (const [classRef, query] of objectsQueryByClass.entries()) {
|
||||
@@ -196,7 +196,7 @@
|
||||
if (_class === undefined) {
|
||||
return model.getActionsFn(contexts)
|
||||
} else {
|
||||
return model.getActionsFn(contexts.filter(({ attachedToClass }) => attachedToClass === _class))
|
||||
return model.getActionsFn(contexts.filter(({ objectClass }) => objectClass === _class))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
noDivider
|
||||
>
|
||||
{#each sortedItems as item (item.id)}
|
||||
{@const context = contexts.find(({ attachedTo }) => attachedTo === item.id)}
|
||||
{@const context = contexts.find(({ objectId }) => objectId === item.id)}
|
||||
<ChatNavItem {context} isSelected={objectId === item.id} {item} type={'type-object'} on:select />
|
||||
{/each}
|
||||
{#if canShowMore}
|
||||
@@ -130,7 +130,7 @@
|
||||
{/if}
|
||||
<svelte:fragment slot="visible" let:isOpen>
|
||||
{#if visibleItem !== undefined && !isOpen}
|
||||
{@const context = contexts.find(({ attachedTo }) => attachedTo === visibleItem?.id)}
|
||||
{@const context = contexts.find(({ objectId }) => objectId === visibleItem?.id)}
|
||||
<ChatNavItem {context} isSelected item={visibleItem} type={'type-object'} on:select />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { AccountRole, Doc, Ref, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { AccountRole, Doc, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { Scroller, SearchEdit, Label, ButtonIcon, IconAdd, showPopup, Menu } from '@hcengineering/ui'
|
||||
import { DocNotifyContext } from '@hcengineering/notification'
|
||||
import { SpecialNavModel } from '@hcengineering/workbench'
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
import { type Asset, type IntlString } from '@hcengineering/platform'
|
||||
import { type Account, type Doc, type DocumentQuery, type IdMap, type Ref, type UserStatus } from '@hcengineering/core'
|
||||
import { type Account, type Class, type Doc, type IdMap, type Ref, type UserStatus } from '@hcengineering/core'
|
||||
import { type DocNotifyContext } from '@hcengineering/notification'
|
||||
import { type AnySvelteComponent, type IconSize, type Action } from '@hcengineering/ui'
|
||||
import { type PersonAccount } from '@hcengineering/contact'
|
||||
@@ -29,11 +29,13 @@ export interface SortFnOptions {
|
||||
export interface ChatNavGroupModel {
|
||||
id: ChatGroup
|
||||
label?: IntlString
|
||||
query: DocumentQuery<DocNotifyContext>
|
||||
sortFn: (items: ChatNavItemModel[], options: SortFnOptions) => ChatNavItemModel[]
|
||||
wrap: boolean
|
||||
getActionsFn?: (contexts: DocNotifyContext[]) => Action[]
|
||||
maxSectionItems?: number
|
||||
isPinned: boolean
|
||||
_class?: Ref<Class<Doc>>
|
||||
skipClasses?: Array<Ref<Class<Doc>>>
|
||||
}
|
||||
|
||||
export interface ChatNavItemModel {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
import notification, { type DocNotifyContext } from '@hcengineering/notification'
|
||||
import {
|
||||
import core, {
|
||||
generateId,
|
||||
type Ref,
|
||||
SortingOrder,
|
||||
@@ -139,29 +139,23 @@ export const chatNavGroupModels: ChatNavGroupModel[] = [
|
||||
sortFn: sortAlphabetically,
|
||||
wrap: false,
|
||||
getActionsFn: getPinnedActions,
|
||||
query: {
|
||||
isPinned: true
|
||||
}
|
||||
isPinned: true
|
||||
},
|
||||
{
|
||||
id: 'channels',
|
||||
sortFn: sortAlphabetically,
|
||||
wrap: true,
|
||||
getActionsFn: getChannelsActions,
|
||||
query: {
|
||||
isPinned: { $ne: true },
|
||||
attachedToClass: { $in: [chunter.class.Channel] }
|
||||
}
|
||||
isPinned: false,
|
||||
_class: chunter.class.Channel
|
||||
},
|
||||
{
|
||||
id: 'direct',
|
||||
sortFn: sortDirects,
|
||||
wrap: true,
|
||||
getActionsFn: getDirectActions,
|
||||
query: {
|
||||
isPinned: { $ne: true },
|
||||
attachedToClass: { $in: [chunter.class.DirectMessage] }
|
||||
}
|
||||
isPinned: false,
|
||||
_class: chunter.class.DirectMessage
|
||||
},
|
||||
{
|
||||
id: 'activity',
|
||||
@@ -169,13 +163,8 @@ export const chatNavGroupModels: ChatNavGroupModel[] = [
|
||||
wrap: true,
|
||||
getActionsFn: getActivityActions,
|
||||
maxSectionItems: 5,
|
||||
query: {
|
||||
isPinned: { $ne: true },
|
||||
attachedToClass: {
|
||||
// Ignore external channels until support is provided for them
|
||||
$nin: [chunter.class.DirectMessage, chunter.class.Channel, contact.class.Channel]
|
||||
}
|
||||
}
|
||||
isPinned: false,
|
||||
skipClasses: [chunter.class.DirectMessage, chunter.class.Channel, contact.class.Channel]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -262,7 +251,7 @@ function sortDirects (items: ChatNavItemModel[], option: SortFnOptions): ChatNav
|
||||
|
||||
function sortActivityChannels (items: ChatNavItemModel[], option: SortFnOptions): ChatNavItemModel[] {
|
||||
const { contexts } = option
|
||||
const contextByDoc = new Map(contexts.map((context) => [context.attachedTo, context]))
|
||||
const contextByDoc = new Map(contexts.map((context) => [context.objectId, context]))
|
||||
|
||||
return items.sort((i1, i2) => {
|
||||
const context1 = contextByDoc.get(i1.id)
|
||||
@@ -386,7 +375,7 @@ export function loadSavedAttachments (): void {
|
||||
|
||||
savedAttachmentsQuery.query(
|
||||
attachment.class.SavedAttachments,
|
||||
{},
|
||||
{ space: core.space.Workspace },
|
||||
(res) => {
|
||||
savedAttachmentsStore.set(res.filter(({ $lookup }) => $lookup?.attachedTo !== undefined))
|
||||
},
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@
|
||||
let title: string | undefined = undefined
|
||||
let channel: Doc | undefined = undefined
|
||||
|
||||
$: isThread = hierarchy.isDerived(context.attachedToClass, chunter.class.ThreadMessage)
|
||||
$: isThread = hierarchy.isDerived(context.objectClass, chunter.class.ThreadMessage)
|
||||
|
||||
$: loadChannel(object, isThread)
|
||||
$: channel &&
|
||||
@@ -46,7 +46,7 @@
|
||||
function loadChannel (object: ChatMessage, isThread: boolean): void {
|
||||
const _class = isThread ? (object as ThreadMessage).objectClass : object.attachedToClass
|
||||
const _id = isThread ? (object as ThreadMessage).objectId : object.attachedTo
|
||||
console.log({ _class, _id, isThread, object })
|
||||
|
||||
void client.findOne(_class, { _id, ...(isThread ? { space: object.space } : {}) }).then((res) => {
|
||||
channel = res
|
||||
})
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { DisplayDocUpdateMessage } from '@hcengineering/activity'
|
||||
import { BaseMessagePreview } from '@hcengineering/activity-resources'
|
||||
|
||||
import chunter from '../../plugin'
|
||||
|
||||
export let message: DisplayDocUpdateMessage
|
||||
</script>
|
||||
|
||||
<BaseMessagePreview intlLabel={chunter.string.YouJoinedChannel} {message} on:click />
|
||||
@@ -48,6 +48,9 @@ import ChatMessageNotificationLabel from './components/notification/ChatMessageN
|
||||
import ChatAside from './components/chat/ChatAside.svelte'
|
||||
import ThreadMessagePreview from './components/threads/ThreadMessagePreview.svelte'
|
||||
import ChatMessagePreview from './components/chat-message/ChatMessagePreview.svelte'
|
||||
import ChannelCreatedMessage from './components/activity/ChannelCreatedMessage.svelte'
|
||||
import MembersChangedMessage from './components/activity/MembersChangedMessage.svelte'
|
||||
import JoinChannelNotificationPresenter from './components/notification/JoinChannelNotificationPresenter.svelte'
|
||||
|
||||
import {
|
||||
ChannelTitleProvider,
|
||||
@@ -177,7 +180,12 @@ export default async (): Promise<Resources> => ({
|
||||
ThreadNotificationPresenter,
|
||||
ChatAside,
|
||||
ThreadMessagePreview,
|
||||
ChatMessagePreview
|
||||
ChatMessagePreview,
|
||||
JoinChannelNotificationPresenter
|
||||
},
|
||||
activity: {
|
||||
ChannelCreatedMessage,
|
||||
MembersChangedMessage
|
||||
},
|
||||
function: {
|
||||
GetDmName: getDmName,
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { getCurrentLocation, getCurrentResolvedLocation, getLocation, type Location, navigate } from '@hcengineering/ui'
|
||||
import {
|
||||
closePanel,
|
||||
getCurrentLocation,
|
||||
getCurrentResolvedLocation,
|
||||
getLocation,
|
||||
type Location,
|
||||
navigate
|
||||
} from '@hcengineering/ui'
|
||||
import { type Ref, type Doc, type Class } from '@hcengineering/core'
|
||||
import type { ActivityMessage } from '@hcengineering/activity'
|
||||
import { chunterId, type ChunterSpace, type ThreadMessage } from '@hcengineering/chunter'
|
||||
@@ -184,5 +191,6 @@ export async function resetChunterLocIfEqual (_id: Ref<Doc>, _class: Ref<Class<D
|
||||
loc.path[4] = ''
|
||||
loc.query = {}
|
||||
loc.path.length = 3
|
||||
closePanel()
|
||||
navigate(loc)
|
||||
}
|
||||
|
||||
@@ -491,47 +491,44 @@ export async function leaveChannelAction (
|
||||
}
|
||||
const client = getClient()
|
||||
const channel =
|
||||
props?.object ?? (await client.findOne(chunter.class.Channel, { _id: context.attachedTo as Ref<Channel> }))
|
||||
props?.object ?? (await client.findOne(chunter.class.Channel, { _id: context.objectId as Ref<Channel> }))
|
||||
|
||||
if (channel === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
await leaveChannel(channel, getCurrentAccount()._id)
|
||||
await client.remove(context)
|
||||
await resetChunterLocIfEqual(channel._id, channel._class, channel)
|
||||
}
|
||||
|
||||
export async function removeChannelAction (
|
||||
context?: DocNotifyContext,
|
||||
_?: Event,
|
||||
props?: { object?: Doc }
|
||||
): Promise<void> {
|
||||
export async function removeChannelAction (context?: DocNotifyContext, _?: Event): Promise<void> {
|
||||
if (context === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const { objectId, objectClass, objectSpace } = context
|
||||
|
||||
if (hierarchy.isDerived(context.attachedToClass, chunter.class.Channel)) {
|
||||
const channel = await client.findOne(chunter.class.Channel, { _id: context.attachedTo as Ref<Channel> })
|
||||
if (hierarchy.isDerived(objectClass, chunter.class.Channel)) {
|
||||
const channel = await client.findOne(chunter.class.Channel, { _id: objectId as Ref<Channel>, space: objectSpace })
|
||||
await leaveChannel(channel, getCurrentAccount()._id)
|
||||
} else {
|
||||
const object = await client.findOne(context.attachedToClass, { _id: context.attachedTo })
|
||||
const account = getCurrentAccount() as PersonAccount
|
||||
const object = await client.findOne(objectClass, { _id: objectId, space: objectSpace })
|
||||
// const account = getCurrentAccount() as PersonAccount
|
||||
|
||||
await client.createMixin(context._id, context._class, context.space, chunter.mixin.ChannelInfo, { hidden: true })
|
||||
|
||||
const chatInfo = await client.findOne(chunter.class.ChatInfo, { user: account.person })
|
||||
|
||||
if (chatInfo !== undefined) {
|
||||
await client.update(chatInfo, { hidden: chatInfo.hidden.concat([context._id]) })
|
||||
}
|
||||
await resetChunterLocIfEqual(context.attachedTo, context.attachedToClass, object)
|
||||
// await client.createMixin(context._id, context._class, context.space, chunter.mixin.ChannelInfo, { hidden: true })
|
||||
//
|
||||
// const chatInfo = await client.findOne(chunter.class.ChatInfo, { user: account.person })
|
||||
//
|
||||
// if (chatInfo !== undefined) {
|
||||
// await client.update(chatInfo, { hidden: chatInfo.hidden.concat([context._id]) })
|
||||
// }
|
||||
await resetChunterLocIfEqual(objectId, objectClass, object)
|
||||
}
|
||||
|
||||
void inboxClient.readDoc(client, context.attachedTo)
|
||||
await client.remove(context)
|
||||
}
|
||||
|
||||
export function isThreadMessage (message: ActivityMessage): message is ThreadMessage {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user