diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 86b4abd1e0..2ec66de014 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -514,6 +514,15 @@ importers: '@rush-temp/importer': specifier: file:./projects/importer.tgz version: file:projects/importer.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(prosemirror-inputrules@1.4.0)(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.2)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@rush-temp/inbox': + specifier: file:./projects/inbox.tgz + version: file:projects/inbox.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@rush-temp/inbox-assets': + specifier: file:./projects/inbox-assets.tgz + version: file:projects/inbox-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@rush-temp/inbox-resources': + specifier: file:./projects/inbox-resources.tgz + version: file:projects/inbox-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(prosemirror-inputrules@1.4.0)(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) '@rush-temp/integration-client': specifier: file:./projects/integration-client.tgz version: file:projects/integration-client.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) @@ -664,6 +673,9 @@ importers: '@rush-temp/model-huly-mail': specifier: file:./projects/model-huly-mail.tgz version: file:projects/model-huly-mail.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@rush-temp/model-inbox': + specifier: file:./projects/model-inbox.tgz + version: file:projects/model-inbox.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) '@rush-temp/model-inventory': specifier: file:./projects/model-inventory.tgz version: file:projects/model-inventory.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) @@ -4928,7 +4940,7 @@ packages: version: 0.0.0 '@rush-temp/desktop@file:projects/desktop.tgz': - resolution: {integrity: sha512-HiBnbdBc/mg0wlsEUcRw05sKWnlyUnExnNV3vkyEFlnSIN3ROFYSIhEI26+UpXhfa+8t6TTSQx9JK8gmiII0aQ==, tarball: file:projects/desktop.tgz} + resolution: {integrity: sha512-OqIIA7HRUTB18L4jdl39LCzh258UAs2Rp3qbua38PAsOV7qmoQC0+xFmtH0aAmaFL8cut6K88/FnbjjtzAYP8A==, tarball: file:projects/desktop.tgz} version: 0.0.0 '@rush-temp/devmodel-resources@file:projects/devmodel-resources.tgz': @@ -5103,6 +5115,18 @@ packages: resolution: {integrity: sha512-PXqcGrMal8EqtqMeGqvXahFZSbfitShE6UKT5WlIE9hCrNlMv2H13YqSSDoDmYPjmNbUlZ4RlL8z1BtZgC6XxA==, tarball: file:projects/importer.tgz} version: 0.0.0 + '@rush-temp/inbox-assets@file:projects/inbox-assets.tgz': + resolution: {integrity: sha512-Fe6/dReQqNS0AhZR3gFEajiP8Qm9CinWX9fSXeYnXbfTMh0ijzxIq9ra8kwsgIjI8bQ2GE09likyzVAa91IW1Q==, tarball: file:projects/inbox-assets.tgz} + version: 0.0.0 + + '@rush-temp/inbox-resources@file:projects/inbox-resources.tgz': + resolution: {integrity: sha512-xszlMc55DpQSp+mfmiY3EM3udDFfhLfWvzre9Px6XMN8Gnt0DcVFm0S3KyR8NKJzV3uVOPHaweXoXmZa2GFvxw==, tarball: file:projects/inbox-resources.tgz} + version: 0.0.0 + + '@rush-temp/inbox@file:projects/inbox.tgz': + resolution: {integrity: sha512-IxHFbCtBvZ8rEL/XqrSuSB+VgL83uYcjbO9OiPetTNWtz7rDmvLyj+UnkXJWtlyTKWn9dKfcsuB3bkHQZkm/fA==, tarball: file:projects/inbox.tgz} + version: 0.0.0 + '@rush-temp/integration-client@file:projects/integration-client.tgz': resolution: {integrity: sha512-p3uOUY9iHR+qtaBa8CNxEQc31gsM8dGdKU++quV8XDUAD+hOl+Ikjj8Fh+V1OLA0KXb2wN2Ob8MQUwmHsKPHIQ==, tarball: file:projects/integration-client.tgz} version: 0.0.0 @@ -5204,7 +5228,7 @@ packages: version: 0.0.0 '@rush-temp/model-all@file:projects/model-all.tgz': - resolution: {integrity: sha512-h3FPiVybmZEa2IAX89OlWzrRUJYLg5fVLdq2lO3ctmkwK20sbvBdhoLJZfg1YYaeO1NTsUP4j8kyu5DxTxu8og==, tarball: file:projects/model-all.tgz} + resolution: {integrity: sha512-DNEVWMrvvqLdwjxdOH270bA0W+mIxoLFBqx49J647HY4E9mmWqqgeMNSLLUXY1WlhpFSok3GyZqVV8AncdBCCQ==, tarball: file:projects/model-all.tgz} version: 0.0.0 '@rush-temp/model-analytics-collector@file:projects/model-analytics-collector.tgz': @@ -5303,6 +5327,10 @@ packages: resolution: {integrity: sha512-icnJmXV6KKX2gci/n1l8fOZIFPiRpq68/VIlhu2TdknycHtRKDADLSsZGpXaKoUq35tjwMmuZ9ZLF93jzWGSNQ==, tarball: file:projects/model-huly-mail.tgz} version: 0.0.0 + '@rush-temp/model-inbox@file:projects/model-inbox.tgz': + resolution: {integrity: sha512-lVBzx78GwVYVjBePMXW/hZ2c88MwaS6g2WGXV+3Sp5O+OoRzKaZ0Uoj6mKOabr4l5pJ/A/KnBFJ50Lh4jVNTZQ==, tarball: file:projects/model-inbox.tgz} + version: 0.0.0 + '@rush-temp/model-inventory@file:projects/model-inventory.tgz': resolution: {integrity: sha512-pYB7K/D3aGlYDsxFoqnScmPQr1TiJ3NbLRXNEIzqqI0cp5Fpaz9cqvOuKhscFxDJQ6fujf/NLOdKLHh3FxM3Cg==, tarball: file:projects/model-inventory.tgz} version: 0.0.0 @@ -5324,7 +5352,7 @@ packages: version: 0.0.0 '@rush-temp/model-notification@file:projects/model-notification.tgz': - resolution: {integrity: sha512-FKgjGbbY8VKz0bA+//O/OKfEXUhhTMfYMy7fcydejDs0uJ/m1XSaDF0IBkBR9XvDNaXO4v9/IYOmQJTIvAs6Ow==, tarball: file:projects/model-notification.tgz} + resolution: {integrity: sha512-uRMC3n/pyGJlDk/GCbSkZrUMklyVhUmcn+tvlqZxpXznr4WSlSDMkY3VfB7064Ydn/K4KX5Wj5BjdxFWowgTdg==, tarball: file:projects/model-notification.tgz} version: 0.0.0 '@rush-temp/model-preference@file:projects/model-preference.tgz': @@ -5560,7 +5588,7 @@ packages: version: 0.0.0 '@rush-temp/notification-resources@file:projects/notification-resources.tgz': - resolution: {integrity: sha512-k27Ea3pPJEKFqeuWkV4rahl88Uu7xCWeRz/ErVgPctWxIFw0xVGjbrsNyg+ufI+vZp40yaWVMw+tHn44s6VM1A==, tarball: file:projects/notification-resources.tgz} + resolution: {integrity: sha512-h0E2s9AO3VTo0SXkqqGMzpZFAasOIuaMJeX5L2FTUylV8fJtS5ONbDmmNssPLwQ+c2JWa5Ok6uXYB5KJx0I56g==, tarball: file:projects/notification-resources.tgz} version: 0.0.0 '@rush-temp/notification@file:projects/notification.tgz': @@ -5680,7 +5708,7 @@ packages: version: 0.0.0 '@rush-temp/pod-server@file:projects/pod-server.tgz': - resolution: {integrity: sha512-aR9P6JsNdSrHmfvsc3oqgYvdeEhH03KBR/xb0YmaL+Zjcey4erHd4lT0pz5bl8OKQnJKeL9hmuYp+G4PA/J3GQ==, tarball: file:projects/pod-server.tgz} + resolution: {integrity: sha512-kQYQpvwBHRxO7a4DXdzC8reqtzPv718JOuilFmULpoEa2KWNBUQKLHN71K3vxtMQwK/+vu7pl8H9jtjskSLySA==, tarball: file:projects/pod-server.tgz} version: 0.0.0 '@rush-temp/pod-sign@file:projects/pod-sign.tgz': @@ -5756,7 +5784,7 @@ packages: version: 0.0.0 '@rush-temp/prod@file:projects/prod.tgz': - resolution: {integrity: sha512-jk0NWxDQLOtjcbnQVNRPS7/IriZT/UntwqO+yH8RswKec9XKe99w7kjku2ooCIp85qZyeUiT0HxIWrApnsKBUw==, tarball: file:projects/prod.tgz} + resolution: {integrity: sha512-cBCJ4o7HyPky1hndFE/lQ/AxXM47a0iC4s8H6ihpgZ17SD3iLJwx5V7Wk9+zmfJK03XuqxE96oUt4EjezIStuw==, tarball: file:projects/prod.tgz} version: 0.0.0 '@rush-temp/products-assets@file:projects/products-assets.tgz': @@ -5844,7 +5872,7 @@ packages: version: 0.0.0 '@rush-temp/server-activity-resources@file:projects/server-activity-resources.tgz': - resolution: {integrity: sha512-mlvStvUKlViTLzdD2iir0RFdYbMtThsI2SGaSJYQS4xNx6kovGnuNzqNh/zT38g7eol5oNDQOep/yV8z+Y4ztQ==, tarball: file:projects/server-activity-resources.tgz} + resolution: {integrity: sha512-m1Ha9wIYVNbZdPtMCTmDjM8wOuMMSOgiykWCZQRWzf6OBtTlM+c04oUZ51bju78JiRCwAicYNcahJe8PNXcCyg==, tarball: file:projects/server-activity-resources.tgz} version: 0.0.0 '@rush-temp/server-activity@file:projects/server-activity.tgz': @@ -6316,7 +6344,7 @@ packages: version: 0.0.0 '@rush-temp/workbench-resources@file:projects/workbench-resources.tgz': - resolution: {integrity: sha512-bk7Jl+uJ94+3ceG1IJ/PjfDcxsINfvWlp0zIdwhs3Px3F/NQWhznRcI4pnb8CEWYmGWSI2AQhfzqDchC88NJ3g==, tarball: file:projects/workbench-resources.tgz} + resolution: {integrity: sha512-JVucJQFm2Dl0k/S5H3fnmMN/29bHklJ6MOCPbsPrrucIr8W59f+Wja5syWfsqvq/tvGgnhX2uCQD1Nz9gs54yg==, tarball: file:projects/workbench-resources.tgz} version: 0.0.0 '@rush-temp/workbench@file:projects/workbench.tgz': @@ -22292,6 +22320,131 @@ snapshots: - supports-color - ts-node + '@rush-temp/inbox-assets@file:projects/inbox-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': + dependencies: + '@hcengineering/platform': 0.7.5 + '@hcengineering/platform-rig': 0.7.19(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@types/jest': 29.5.12 + '@types/node': 22.15.29 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.9.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.9.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@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + prettier: 3.6.2 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - sass + - stylus + - sugarss + - supports-color + - ts-node + + '@rush-temp/inbox-resources@file:projects/inbox-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(prosemirror-inputrules@1.4.0)(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': + dependencies: + '@hcengineering/analytics': 0.7.5 + '@hcengineering/communication-shared': 0.7.5 + '@hcengineering/communication-types': 0.7.5 + '@hcengineering/core': 0.7.8 + '@hcengineering/platform': 0.7.5 + '@hcengineering/platform-rig': 0.7.19(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@hcengineering/rank': 0.7.5 + '@hcengineering/text': 0.7.5(prosemirror-inputrules@1.4.0)(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.2) + '@hcengineering/text-markdown': 0.7.5 + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.9.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.9.3) + eslint-plugin-import: 2.29.1(eslint@8.56.0) + eslint-plugin-n: 15.7.0(eslint@8.56.0) + eslint-plugin-promise: 6.1.1(eslint@8.56.0) + eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.20)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + fast-equals: 5.2.2 + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + prettier: 3.6.2 + prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@4.2.20) + sass: 1.93.2 + svelte: 4.2.20 + svelte-check: 3.6.9(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(svelte@4.2.20) + svelte-eslint-parser: 0.33.1(svelte@4.2.20) + svelte-loader: 3.2.0(svelte@4.2.20) + svelte-preprocess: 5.1.4(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(svelte@4.2.20)(typescript@5.9.3) + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - prosemirror-inputrules + - prosemirror-model + - prosemirror-state + - prosemirror-view + - pug + - stylus + - sugarss + - supports-color + - ts-node + + '@rush-temp/inbox@file:projects/inbox.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': + dependencies: + '@hcengineering/core': 0.7.8 + '@hcengineering/platform': 0.7.5 + '@hcengineering/platform-rig': 0.7.19(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@types/jest': 29.5.12 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.9.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.9.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@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + prettier: 3.6.2 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - '@types/node' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - sass + - stylus + - sugarss + - supports-color + - ts-node + '@rush-temp/integration-client@file:projects/integration-client.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': dependencies: '@hcengineering/account-client': 0.7.6 @@ -24261,6 +24414,43 @@ snapshots: - supports-color - ts-node + '@rush-temp/model-inbox@file:projects/model-inbox.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': + dependencies: + '@hcengineering/core': 0.7.8 + '@hcengineering/model': 0.7.5 + '@hcengineering/platform': 0.7.5 + '@hcengineering/platform-rig': 0.7.19(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + '@types/jest': 29.5.12 + '@types/node': 22.15.29 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.9.3) + eslint: 8.56.0 + eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.9.3))(eslint@8.56.0)(typescript@5.9.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.9.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@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)) + prettier: 3.6.2 + ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - '@babel/core' + - '@jest/types' + - babel-jest + - babel-plugin-macros + - coffeescript + - esbuild + - less + - node-notifier + - postcss + - postcss-load-config + - pug + - sass + - stylus + - sugarss + - supports-color + - ts-node + '@rush-temp/model-inventory@file:projects/model-inventory.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3)))(postcss@8.5.3)(sass@1.93.2)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.9.3))': dependencies: '@hcengineering/core': 0.7.8 diff --git a/common/scripts/version.txt b/common/scripts/version.txt index 955ba890f0..e8cb017a7e 100644 --- a/common/scripts/version.txt +++ b/common/scripts/version.txt @@ -1 +1 @@ -"0.7.269" +"0.7.278" diff --git a/desktop/package.json b/desktop/package.json index 941fd7df88..f9a8bdd268 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -266,6 +266,9 @@ "@hcengineering/ai-assistant": "^0.7.0", "@hcengineering/ai-assistant-assets": "^0.7.0", "@hcengineering/ai-assistant-resources": "^0.7.0", + "@hcengineering/inbox": "^0.7.0", + "@hcengineering/inbox-assets": "^0.7.0", + "@hcengineering/inbox-resources": "^0.7.0", "electron-squirrel-startup": "~1.0.0", "dotenv": "~16.0.0", "electron-context-menu": "^4.0.4", diff --git a/desktop/src/ui/index.ejs b/desktop/src/ui/index.ejs index ae893ba49a..5560107cc9 100644 --- a/desktop/src/ui/index.ejs +++ b/desktop/src/ui/index.ejs @@ -24,7 +24,12 @@ box-sizing: border-box; } + body { + background-color: var(--bg-body, #ffffff); + } + :root { + --bg-body: #ffffff; --bg-secondary: #f3f3f3; --bg-tertiary: #ffffff; --bg-hover: #e8e8e8; @@ -39,6 +44,7 @@ } [data-theme="theme-dark"] { + --bg-body: #1a1928; --bg-secondary: #323233; --bg-tertiary: #252526; --bg-hover: #2a2d2e; @@ -236,4 +242,13 @@ - \ No newline at end of file + + +<% if (typeof isWindows !== 'undefined' && isWindows) { %> + +<% } %> \ No newline at end of file diff --git a/desktop/src/ui/index.ts b/desktop/src/ui/index.ts index 6aa383ed5c..ff6553c742 100644 --- a/desktop/src/ui/index.ts +++ b/desktop/src/ui/index.ts @@ -25,6 +25,7 @@ import { closePopup, createApp, getCurrentResolvedLocation, + Menu, navigate, parseLocation, pushRootBarProgressComponent, @@ -33,10 +34,15 @@ import { } from '@hcengineering/ui' import { handleDownloadItem } from '@hcengineering/desktop-downloads' import notification, { notificationId } from '@hcengineering/notification' -import { chatId } from '@hcengineering/chat' +import { inboxId } from '@hcengineering/inbox' import workbench, { workbenchId, logOut } from '@hcengineering/workbench' import view, { Action, encodeObjectURI } from '@hcengineering/view' import { resolveLocation } from '@hcengineering/notification-resources' +import { themeStore, ThemeVariant } from '@hcengineering/theme' +import type { Application } from '@hcengineering/workbench' +import { isAllowedToRole } from '@hcengineering/workbench-resources' +import card from '@hcengineering/card' +import communication from '@hcengineering/communication' import { isOwnerOrMaintainer, getCurrentAccount, Ref } from '@hcengineering/core' import { configurePlatform } from './platform' @@ -44,9 +50,6 @@ import { setupTitleBarMenu } from './titleBarMenu' import { defineScreenShare, defineGetDisplayMedia } from './screenShare' import { CommandLogout, CommandSelectWorkspace, CommandOpenSettings, CommandOpenInbox, CommandOpenPlanner, CommandOpenOffice, CommandOpenApplication, LaunchApplication, NotificationParams, CommandCloseTab } from './types' import { ipcMainExposed } from './typesUtils' -import { themeStore, ThemeVariant } from '@hcengineering/theme' -import type { Application } from '@hcengineering/workbench' -import { isAllowedToRole } from '@hcengineering/workbench-resources' import { IpcMessage } from './ipcMessages' function currentOsIsWindows (): boolean { @@ -82,11 +85,13 @@ window.addEventListener('DOMContentLoaded', () => { } }) - void ipcMain.isOsUsingDarkTheme().then((isDarkTheme) => { - menuBar.setTheme(isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light) - }).catch(() => { - menuBar.setTheme(ThemeVariant.Light) // fallback - }) + if (menuBar.lastUsedThemeIsUnknown()) { + void ipcMain.isOsUsingDarkTheme().then((isDarkTheme) => { + menuBar.setTheme(isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light) + }).catch(() => { + menuBar.setTheme(ThemeVariant.Light) // fallback + }) + } }) } } @@ -194,39 +199,44 @@ window.addEventListener('DOMContentLoaded', () => { navigate(parseLocation(urlObject)) } - function getBasicNotificationPath (notificationParams: NotificationParams): string { - return `${workbenchId}/${notificationParams.application ?? notificationId}/${notificationId}` + function getBasicNotificationPath (worksapce: string, app: string): string { + return `${workbenchId}/${worksapce}/${app}` } ipcMain.handleNotificationNavigation((notificationParams: NotificationParams) => { + const currentLocation = getCurrentResolvedLocation() + const workspace = currentLocation.path[1] // Support for new inbox with cardId (card-based) if (notificationParams.cardId != null) { - const currentLocation = getCurrentResolvedLocation() - navigateToUrl(`${workbenchId}/${currentLocation.path[1]}/${chatId}/${notificationParams.cardId}`) + const objectUri = encodeObjectURI(notificationParams.cardId, card.class.Card) + navigateToUrl(`${workbenchId}/${workspace}/${inboxId}/${objectUri}`) return } + const isCommunicationEnabled = getMetadata(communication.metadata.Enabled) ?? false + const app = isCommunicationEnabled ? inboxId : notificationParams.application + // Support for old inbox with objectId + objectClass (legacy) if (notificationParams.objectId != null && notificationParams.objectClass != null) { const encodedObjectURI = encodeObjectURI(notificationParams.objectId, notificationParams.objectClass) const notificationLocation = { - path: [workbenchId, notificationParams.application, notificationId, encodedObjectURI], + path: [workbenchId, workspace, app, encodedObjectURI], fragment: undefined, - query: {} + query: undefined } void resolveLocation(notificationLocation).then((resolvedLocation) => { if (resolvedLocation?.loc != null) { navigate(resolvedLocation.loc) } else { - navigateToUrl(`${workbenchId}/${notificationParams.application}/${notificationId}/${encodedObjectURI}`) + navigateToUrl(`${workbenchId}/${workspace}/${app}/${encodedObjectURI}`) } }).catch(() => { - navigateToUrl(getBasicNotificationPath(notificationParams)) + navigateToUrl(getBasicNotificationPath(workspace, app)) }) } else { // Fallback to basic notification navigation - navigateToUrl(getBasicNotificationPath(notificationParams)) + navigateToUrl(getBasicNotificationPath(workspace, app)) } }) diff --git a/desktop/src/ui/notifications.ts b/desktop/src/ui/notifications.ts index 579fe78c9a..0ecc293c6a 100644 --- a/desktop/src/ui/notifications.ts +++ b/desktop/src/ui/notifications.ts @@ -29,7 +29,7 @@ import workbench, { workbenchId } from '@hcengineering/workbench' import desktopPreferences, { defaultNotificationPreference } from '@hcengineering/desktop-preferences' import { activePreferences } from '@hcengineering/desktop-preferences-resources' import { getDisplayInboxData, InboxNotificationsClientImpl } from '@hcengineering/notification-resources' -import { chatId } from '@hcengineering/chat' +import { inboxId } from '@hcengineering/inbox' import communication from '@hcengineering/communication' import { ipcMainExposed } from './typesUtils' @@ -179,7 +179,7 @@ export function configureNotifications (): void { notificationHistory.set(notification.id, notification.created.getTime()) electronAPI.sendNotification({ silent: !preferences.playSound, - application: chatId, + application: inboxId, title: notification.content.title, body: `${notification.content.senderName}: ${notification.content.shortText}`, cardId: notification.cardId, diff --git a/desktop/src/ui/platform.ts b/desktop/src/ui/platform.ts index abe1899a7b..2ccdda9610 100644 --- a/desktop/src/ui/platform.ts +++ b/desktop/src/ui/platform.ts @@ -76,6 +76,7 @@ import { viewId } from '@hcengineering/view' import workbench, { workbenchId } from '@hcengineering/workbench' import { mailId } from '@hcengineering/mail' import { chatId } from '@hcengineering/chat' +import { inboxId } from '@hcengineering/inbox' import { achievementId } from '@hcengineering/achievement' import communication, { communicationId } from '@hcengineering/communication' import { emojiId } from '@hcengineering/emoji' @@ -133,6 +134,7 @@ import '@hcengineering/view-assets' import '@hcengineering/workbench-assets' import '@hcengineering/mail-assets' import '@hcengineering/chat-assets' +import '@hcengineering/inbox-assets' import '@hcengineering/achievement-assets' import '@hcengineering/emoji-assets' import '@hcengineering/media-assets' @@ -256,6 +258,7 @@ function configureI18n (): void { addStringsLoader(cardId, async (lang: string) => await import(`@hcengineering/card-assets/lang/${lang}.json`)) addStringsLoader(mailId, async (lang: string) => await import(`@hcengineering/mail-assets/lang/${lang}.json`)) addStringsLoader(chatId, async (lang: string) => await import(`@hcengineering/chat-assets/lang/${lang}.json`)) + addStringsLoader(inboxId, async (lang: string) => await import(`@hcengineering/inbox-assets/lang/${lang}.json`)) addStringsLoader(processId, async (lang: string) => await import(`@hcengineering/process-assets/lang/${lang}.json`)) addStringsLoader(achievementId, async (lang: string) => await import(`@hcengineering/achievement-assets/lang/${lang}.json`)) addStringsLoader(communicationId, async (lang: string) => await import(`@hcengineering/communication-assets/lang/${lang}.json`)) @@ -433,6 +436,7 @@ export async function configurePlatform (onWorkbenchConnect?: () => Promise import(/* webpackChunkName: "survey" */ '@hcengineering/survey-resources')) addLocation(cardId, () => import(/* webpackChunkName: "card" */ '@hcengineering/card-resources')) addLocation(chatId, () => import(/* webpackChunkName: "chat" */ '@hcengineering/chat-resources')) + addLocation(inboxId, () => import(/* webpackChunkName: "inbox" */ '@hcengineering/inbox-resources')) addLocation(processId, () => import(/* webpackChunkName: "process" */ '@hcengineering/process-resources')) addLocation(achievementId, () => import(/* webpackChunkName: "achievement" */ '@hcengineering/achievement-resources')) addLocation(communicationId, () => import(/* webpackChunkName: "communication" */ '@hcengineering/communication-resources')) diff --git a/desktop/src/ui/titleBarMenu.ts b/desktop/src/ui/titleBarMenu.ts index 43847b2d67..32179830a3 100644 --- a/desktop/src/ui/titleBarMenu.ts +++ b/desktop/src/ui/titleBarMenu.ts @@ -16,7 +16,7 @@ import { IPCMainExposed, MenuBarAction } from './types' import { isMenuBarAction } from './typesUtils' import { TitleBarMenuState } from './titleBarMenuState' -import { ThemeVariant, type ThemeVariantType } from '@hcengineering/theme' +import { type ThemeVariantType } from '@hcengineering/theme' const ToggleMinimizeToTrayAction: MenuBarAction = 'toggle-minimize-to-tray' const ToggleAutoLaunchAction: MenuBarAction = 'toggle-auto-launch' @@ -28,7 +28,7 @@ const LabelAutoLaunchEnabled = '☑ Launch at Login' const LabelAutoLaunchDisabled = '☐ Launch at Login' export async function setupTitleBarMenu (ipcMain: IPCMainExposed, root: HTMLElement): Promise { - const themeManager = new ThemeManager(ThemeVariant.Light) + const themeManager = new ThemeManager() const minimizeToTrayEnabled = await ipcMain.isMinimizeToTrayEnabled() const isAutoLaunchEnabled = await ipcMain.isAutoLaunchEnabled() const menuManager = new MenuBarManager(root, minimizeToTrayEnabled, isAutoLaunchEnabled) @@ -75,12 +75,19 @@ export async function setupTitleBarMenu (ipcMain: IPCMainExposed, root: HTMLElem } export class MenuBar { + private static readonly lastUsedThemeKey = 'last-used-theme' + constructor (private readonly theme: ThemeManager) { } public setTheme (theme: ThemeVariantType): void { + localStorage.setItem(MenuBar.lastUsedThemeKey, theme) this.theme.setTheme(theme) } + + public lastUsedThemeIsUnknown (): boolean { + return localStorage.getItem(MenuBar.lastUsedThemeKey) == null + } } export function buildHulyApplicationMenu (minimizeToTrayEnabled: boolean, autoLaunchEnabled: boolean): HTMLElement { @@ -130,14 +137,14 @@ export function buildHulyApplicationMenu (minimizeToTrayEnabled: boolean, autoLa } class ThemeManager { - private readonly domThemeKey = 'data-theme' - - constructor (theme: ThemeVariantType) { - this.setTheme(theme) - } + private static readonly domThemeKey = 'data-theme' public setTheme (theme: ThemeVariantType): void { - document.body.setAttribute(this.domThemeKey, theme) + ThemeManager.setTheme(theme) + } + + public static setTheme (theme: ThemeVariantType): void { + document.body.setAttribute(ThemeManager.domThemeKey, theme) } } diff --git a/dev/prod/package.json b/dev/prod/package.json index 4d5b89b69e..d3810cf5da 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -286,6 +286,9 @@ "@hcengineering/ai-assistant": "^0.7.0", "@hcengineering/ai-assistant-assets": "^0.7.0", "@hcengineering/ai-assistant-resources": "^0.7.0", + "@hcengineering/inbox": "^0.7.0", + "@hcengineering/inbox-assets": "^0.7.0", + "@hcengineering/inbox-resources": "^0.7.0", "readable-stream": "^4.7.0", "svelte": "^4.2.20" } diff --git a/dev/prod/src/platform.ts b/dev/prod/src/platform.ts index 24d1ea41ab..cba5f7d6ed 100644 --- a/dev/prod/src/platform.ts +++ b/dev/prod/src/platform.ts @@ -73,7 +73,8 @@ import { mailId } from '@hcengineering/mail' import { chatId } from '@hcengineering/chat' import github, { githubId } from '@hcengineering/github' import { bitrixId } from '@hcengineering/bitrix' -import { achievementId } from '@hcengineering/achievement' +import {inboxId} from '@hcengineering/inbox' +import {achievementId} from '@hcengineering/achievement' import communication, { communicationId } from '@hcengineering/communication' import { emojiId } from '@hcengineering/emoji' import billingPlugin, { billingId } from '@hcengineering/billing' @@ -129,6 +130,7 @@ import '@hcengineering/media-assets' import '@hcengineering/view-assets' import '@hcengineering/workbench-assets' import '@hcengineering/chat-assets' +import '@hcengineering/inbox-assets' import '@hcengineering/mail-assets' import '@hcengineering/github-assets' import '@hcengineering/achievement-assets' @@ -387,6 +389,7 @@ function configureI18n (): void { communicationId, async (lang: string) => await import(`@hcengineering/communication-assets/lang/${lang}.json`) ) + addStringsLoader(inboxId, async (lang: string) => await import(`@hcengineering/inbox-assets/lang/${lang}.json`)) addStringsLoader(emojiId, async (lang: string) => await import(`@hcengineering/emoji-assets/lang/${lang}.json`)) addStringsLoader(billingId, async (lang: string) => await import(`@hcengineering/billing-assets/lang/${lang}.json`)) addStringsLoader( diff --git a/models/activity/src/plugin.ts b/models/activity/src/plugin.ts index f820672389..ac7757bd31 100644 --- a/models/activity/src/plugin.ts +++ b/models/activity/src/plugin.ts @@ -23,7 +23,7 @@ import { type ViewAction, type ViewActionAvailabilityFunction } from '@hcengineering/view' -import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' +import { type NotificationGroup } from '@hcengineering/notification' export default mergeIds(activityId, activity, { string: { @@ -44,7 +44,6 @@ export default mergeIds(activityId, activity, { ids: { ReactionAddedActivityViewlet: '' as Ref, ActivityNotificationGroup: '' as Ref, - AddReactionNotification: '' as Ref, AddReactionAction: '' as Ref, SaveForLaterAction: '' as Ref, RemoveFromLaterAction: '' as Ref, diff --git a/models/all/package.json b/models/all/package.json index a2ad599704..12b6ad01b4 100644 --- a/models/all/package.json +++ b/models/all/package.json @@ -133,6 +133,7 @@ "@hcengineering/model-emoji": "^0.7.0", "@hcengineering/model-billing": "^0.7.0", "@hcengineering/model-huly-mail": "^0.7.0", - "@hcengineering/model-ai-assistant": "^0.7.0" + "@hcengineering/model-ai-assistant": "^0.7.0", + "@hcengineering/model-inbox": "^0.7.0" } } diff --git a/models/all/src/index.ts b/models/all/src/index.ts index 086a10e5b9..253e5e2d95 100644 --- a/models/all/src/index.ts +++ b/models/all/src/index.ts @@ -118,6 +118,7 @@ import survey, { surveyId, createModel as surveyModel } from '@hcengineering/mod import { presenceId, createModel as presenceModel } from '@hcengineering/model-presence' import chat, { chatId, createModel as chatModel } from '@hcengineering/model-chat' import processes, { processId, createModel as processModel } from '@hcengineering/model-process' +import inbox, { createModel as inboxModel, inboxId } from '@hcengineering/model-inbox' import { achievementId, createModel as achievementModel } from '@hcengineering/model-achievement' import { emojiId, createModel as emojiModel } from '@hcengineering/model-emoji' import { billingId, createModel as billingModel } from '@hcengineering/model-billing' @@ -480,6 +481,11 @@ export default function buildModel (): Builder { chatId, { label: chat.string.Chat, hidden: true, enabled: false, beta: true, classFilter: defaultFilter } ], + [ + inboxModel, + inboxId, + { label: inbox.string.Inbox, hidden: true, enabled: false, beta: true, classFilter: defaultFilter } + ], [achievementModel, achievementId], [emojiModel, emojiId], [communicationModel, communicationId], diff --git a/models/all/src/migration.ts b/models/all/src/migration.ts index 28aa45ff34..fa75741808 100644 --- a/models/all/src/migration.ts +++ b/models/all/src/migration.ts @@ -57,6 +57,7 @@ import { surveyOperation } from '@hcengineering/model-survey' import { cardOperation } from '@hcengineering/model-card' import { aiBotId, aiBotOperation } from '@hcengineering/model-ai-bot' import { chatId, chatOperation } from '@hcengineering/model-chat' +import { inboxId, inboxOperation } from '@hcengineering/model-inbox' import { processId, processOperation } from '@hcengineering/model-process' import { communicationId, communicationOperation } from '@hcengineering/model-communication' import { recorderId, recorderOperation } from '@hcengineering/model-recorder' @@ -106,6 +107,7 @@ export const migrateOperations: [string, MigrateOperation][] = [ ['survey', surveyOperation], [aiBotId, aiBotOperation], [chatId, chatOperation], + [inboxId, inboxOperation], [processId, processOperation], [communicationId, communicationOperation], [recorderId, recorderOperation] diff --git a/models/inbox/.eslintrc.js b/models/inbox/.eslintrc.js new file mode 100644 index 0000000000..c1cf82cba0 --- /dev/null +++ b/models/inbox/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@hcengineering/platform-rig/profiles/model/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/models/inbox/.npmignore b/models/inbox/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/inbox/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/inbox/config/rig.json b/models/inbox/config/rig.json new file mode 100644 index 0000000000..2f6be36605 --- /dev/null +++ b/models/inbox/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + "rigPackageName": "@hcengineering/platform-rig", + "rigProfile": "model" +} diff --git a/models/inbox/jest.config.js b/models/inbox/jest.config.js new file mode 100644 index 0000000000..2cfd408b67 --- /dev/null +++ b/models/inbox/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + roots: ["./src"], + coverageReporters: ["text-summary", "html"] +} diff --git a/models/inbox/package.json b/models/inbox/package.json new file mode 100644 index 0000000000..23fea1cb23 --- /dev/null +++ b/models/inbox/package.json @@ -0,0 +1,50 @@ +{ + "name": "@hcengineering/model-inbox", + "version": "0.7.0", + "main": "lib/index.js", + "svelte": "src/index.ts", + "types": "types/index.d.ts", + "author": "Hardcore Engineering Inc", + "template": "@hcengineering/model-package", + "license": "EPL-2.0", + "scripts": { + "build": "compile", + "build:watch": "compile", + "format": "format src", + "_phase:build": "compile transpile src", + "_phase:format": "format src", + "_phase:validate": "compile validate", + "_phase:test": "jest --passWithNoTests --silent --forceExit", + "test": "jest --passWithNoTests --silent --forceExit" + }, + "devDependencies": { + "@hcengineering/platform-rig": "^0.7.19", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-n": "^15.4.0", + "eslint": "^8.54.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "prettier": "^3.6.2", + "typescript": "^5.9.3", + "@types/node": "^22.15.29", + "jest": "^29.7.0", + "@types/jest": "^29.5.5", + "ts-jest": "^29.1.1" + }, + "dependencies": { + "@hcengineering/card": "^0.7.0", + "@hcengineering/inbox": "^0.7.0", + "@hcengineering/inbox-resources": "^0.7.0", + "@hcengineering/core": "^0.7.8", + "@hcengineering/model": "^0.7.5", + "@hcengineering/model-core": "^0.7.0", + "@hcengineering/model-workbench": "^0.7.0", + "@hcengineering/platform": "^0.7.5", + "@hcengineering/setting": "^0.7.0", + "@hcengineering/ui": "^0.7.0", + "@hcengineering/view": "^0.7.0", + "@hcengineering/workbench": "^0.7.0" + } +} diff --git a/models/inbox/src/index.ts b/models/inbox/src/index.ts new file mode 100644 index 0000000000..bde12f03ac --- /dev/null +++ b/models/inbox/src/index.ts @@ -0,0 +1,42 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type Builder } from '@hcengineering/model' +import core from '@hcengineering/model-core' +import workbench from '@hcengineering/model-workbench' +import { inboxId } from '@hcengineering/inbox' + +import inbox from './plugin' + +export { inboxId } from '@hcengineering/inbox' +export { inboxOperation } from './migration' +export default inbox + +export function createModel (builder: Builder): void { + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: inbox.string.Inbox, + icon: inbox.icon.Inbox, + alias: inboxId, + hidden: false, + component: inbox.component.InboxApplication, + position: 'top', + order: 100 + }, + inbox.app.Inbox + ) +} diff --git a/models/inbox/src/migration.ts b/models/inbox/src/migration.ts new file mode 100644 index 0000000000..ab4d876d36 --- /dev/null +++ b/models/inbox/src/migration.ts @@ -0,0 +1,21 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient } from '@hcengineering/model' + +export const inboxOperation: MigrateOperation = { + async migrate (client: MigrationClient, mode): Promise {}, + async upgrade (state: Map>, client: () => Promise, mode): Promise {} +} diff --git a/models/inbox/src/plugin.ts b/models/inbox/src/plugin.ts new file mode 100644 index 0000000000..f3cf60aa6b --- /dev/null +++ b/models/inbox/src/plugin.ts @@ -0,0 +1,26 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { inboxId } from '@hcengineering/inbox' +import inbox from '@hcengineering/inbox-resources/src/plugin' +import { type Ref } from '@hcengineering/core' +import { type Application } from '@hcengineering/model-workbench' +import { mergeIds } from '@hcengineering/platform' + +export default mergeIds(inboxId, inbox, { + app: { + Inbox: '' as Ref + } +}) diff --git a/models/inbox/tsconfig.json b/models/inbox/tsconfig.json new file mode 100644 index 0000000000..367a8578c9 --- /dev/null +++ b/models/inbox/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "./node_modules/@hcengineering/platform-rig/profiles/model/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./types", + "tsBuildInfoFile": ".build/build.tsbuildinfo" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "lib", "dist", "types", "bundle"] +} \ No newline at end of file diff --git a/models/notification/package.json b/models/notification/package.json index 2d3e5f9a1c..006481947c 100644 --- a/models/notification/package.json +++ b/models/notification/package.json @@ -39,6 +39,7 @@ "@hcengineering/contact": "^0.7.0", "@hcengineering/core": "^0.7.8", "@hcengineering/model": "^0.7.5", + "@hcengineering/model-activity": "^0.7.0", "@hcengineering/model-attachment": "^0.7.0", "@hcengineering/model-core": "^0.7.0", "@hcengineering/model-preference": "^0.7.0", diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index 1631b59d5b..66184f4e89 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -14,7 +14,7 @@ // limitations under the License. // -import activity, { type ActivityMessage } from '@hcengineering/activity' +import activity, { type ActivityMessage, type Reaction } from '@hcengineering/activity' import { type PersonSpace } from '@hcengineering/contact' import { AccountRole, @@ -83,7 +83,8 @@ import { type NotificationType, type NotificationTypeSetting, type PushSubscription, - type PushSubscriptionKeys + type PushSubscriptionKeys, + type ReactionInboxNotification } from '@hcengineering/notification' import { type Asset, type IntlString, type Resource } from '@hcengineering/platform' import setting from '@hcengineering/setting' @@ -285,6 +286,17 @@ export class TMentionInboxNotification extends TCommonInboxNotification implemen mentionedInClass!: Ref> } +@Model(notification.class.ReactionInboxNotification, notification.class.CommonInboxNotification) +export class TReactionInboxNotification extends TCommonInboxNotification implements ReactionInboxNotification { + emoji!: string + ref!: Ref + @Prop(TypeRef(activity.class.ActivityMessage), core.string.AttachedTo) + attachedTo!: Ref + + @Prop(TypeRef(activity.class.ActivityMessage), core.string.AttachedToClass) + attachedToClass!: Ref> +} + @Model(notification.class.ActivityNotificationViewlet, core.class.Doc, DOMAIN_MODEL) export class TActivityNotificationViewlet extends TDoc implements ActivityNotificationViewlet { messageMatch!: DocumentQuery @@ -358,7 +370,8 @@ export function createModel (builder: Builder): void { TNotificationProvider, TNotificationProviderSetting, TNotificationTypeSetting, - TNotificationProviderDefaults + TNotificationProviderDefaults, + TReactionInboxNotification ) builder.mixin(notification.class.BrowserNotification, core.class.Class, core.mixin.TransientConfiguration, { @@ -637,14 +650,6 @@ export function createModel (builder: Builder): void { notification.category.Notification ) - builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, { - messageMatch: { - _class: activity.class.DocUpdateMessage, - objectClass: activity.class.Reaction - }, - presenter: notification.component.ReactionNotificationPresenter - }) - builder.createDoc(core.class.DomainIndexConfiguration, core.space.Model, { domain: DOMAIN_NOTIFICATION, indexes: [{ keys: { user: 1, archived: 1, space: 1 } }], diff --git a/models/notification/src/migration.ts b/models/notification/src/migration.ts index a07c785206..06fa9a35d4 100644 --- a/models/notification/src/migration.ts +++ b/models/notification/src/migration.ts @@ -44,9 +44,12 @@ import notification, { type BrowserNotification, type DocNotifyContext, type InboxNotification, - type OldCollaborators + type OldCollaborators, + type ReactionInboxNotification, + type ActivityInboxNotification } from '@hcengineering/notification' import { DOMAIN_PREFERENCE } from '@hcengineering/preference' +import activity, { type ActivityMessage, type DocUpdateMessage, type Reaction } from '@hcengineering/activity' import { DOMAIN_SPACE, @@ -56,6 +59,7 @@ import { getSocialIdFromOldAccount } from '@hcengineering/model-core' import { DOMAIN_DOC_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_USER_NOTIFY } from './index' +import { DOMAIN_ACTIVITY, DOMAIN_REACTION } from '@hcengineering/model-activity' export async function removeNotifications ( client: MigrationClient, @@ -311,6 +315,88 @@ async function migrateCollaborators (client: MigrationClient): Promise { client.logger.log('finished processing collaborators ', {}) } +async function migrateReactionNotifications (client: MigrationClient): Promise { + const hierarchy = client.hierarchy + const iterator = await client.traverse(DOMAIN_DOC_NOTIFY, { + _class: notification.class.DocNotifyContext + }) + + try { + while (true) { + const contexts = await iterator.next(500) + const res: ReactionInboxNotification[] = [] + const removeIds: Ref[] = [] + if (contexts == null || contexts.length === 0) break + const filtered = contexts.filter((it) => hierarchy.isDerived(it.objectClass, activity.class.ActivityMessage)) + if (filtered.length === 0) continue + + for (const context of filtered) { + const notifications = await client.find(DOMAIN_NOTIFICATION, { + docNotifyContext: context._id, + _class: notification.class.ActivityInboxNotification, + attachedToClass: activity.class.DocUpdateMessage + }) + if (notifications.length === 0) continue + const messages = await client.find(DOMAIN_ACTIVITY, { + _id: { $in: notifications.map((it) => it.attachedTo) as Ref[] }, + _class: activity.class.DocUpdateMessage, + objectClass: activity.class.Reaction + }) + const contextMessage = ( + await client.find(DOMAIN_ACTIVITY, { _id: context.objectId as any }) + )[0] + if (contextMessage == null) continue + const newContext = ( + await client.find(DOMAIN_DOC_NOTIFY, { + user: context.user, + objectId: contextMessage.attachedTo + }) + )[0] + if (newContext == null) { + continue + } + for (const it of notifications) { + const reactionMessage = messages.find((m) => m._id === it.attachedTo) + if (reactionMessage == null) continue + const emoji = + it.data ?? + (await client.find(DOMAIN_REACTION, { _id: reactionMessage.objectId as Ref }))[0].emoji + if (emoji == null || emoji.trim() === '') continue + res.push({ + _id: it._id as Ref, + _class: notification.class.ReactionInboxNotification, + space: it.space, + emoji, + user: it.user, + docNotifyContext: newContext._id, + objectId: newContext.objectId, + objectClass: newContext.objectClass, + ref: reactionMessage.objectId as Ref, + attachedTo: reactionMessage.attachedTo as Ref, + attachedToClass: reactionMessage.attachedToClass as Ref>, + isViewed: it.isViewed, + archived: it.archived, + modifiedOn: it.modifiedOn, + createdBy: it.createdBy, + createdOn: it.createdOn, + modifiedBy: it.modifiedBy + }) + } + } + + if (removeIds.length > 0) { + await client.deleteMany(DOMAIN_NOTIFICATION, { _id: { $in: removeIds } }) + } + + if (res.length > 0) { + await client.create(DOMAIN_NOTIFICATION, res) + } + } + } catch (e) { + console.error(e) + } +} + /** * Migrates old accounts to new accounts/social ids. * Should be applied to prodcution directly without applying migrateSocialIdsToAccountUuids @@ -396,6 +482,7 @@ async function migrateAccounts (client: MigrationClient): Promise { client.logger.log('finished processing collaborators ', {}) client.logger.log('processing notifications fields ', {}) + function chunkArray (array: T[], chunkSize: number): T[][] { const chunks: T[][] = [] for (let i = 0; i < array.length; i += chunkSize) { @@ -845,6 +932,11 @@ export const notificationOperation: MigrateOperation = { state: 'migrate-collaborators-v2', mode: 'upgrade', func: migrateCollaborators + }, + { + state: 'migrate-reaction-notifications', + mode: 'upgrade', + func: migrateReactionNotifications } ]) }, diff --git a/models/process/src/index.ts b/models/process/src/index.ts index 88c67600ae..3917b7c700 100644 --- a/models/process/src/index.ts +++ b/models/process/src/index.ts @@ -315,7 +315,7 @@ export function createModel (builder: Builder): void { }, label: process.string.RunProcess, icon: process.icon.Process, - input: 'focus', + input: 'any', category: view.category.General, target: card.class.Card, context: { @@ -588,10 +588,10 @@ export function createModel (builder: Builder): void { component: process.component.ProcessesSettingSection }) - builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, { - extension: workbench.extensions.WorkbenchExtensions, - component: process.component.NotifierExtension - }) + // builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, { + // extension: workbench.extensions.WorkbenchExtensions, + // component: process.component.NotifierExtension + // }) builder.createDoc(process.class.UpdateCriteriaComponent, core.space.Model, { category: 'attribute', diff --git a/models/server-activity/src/index.ts b/models/server-activity/src/index.ts index 6a3d4a5fa3..15d60a1822 100644 --- a/models/server-activity/src/index.ts +++ b/models/server-activity/src/index.ts @@ -26,10 +26,6 @@ export { activityServerOperation } from './migration' export { serverActivityId } from '@hcengineering/server-activity' export function createModel (builder: Builder): void { - builder.mixin(activity.class.Reaction, core.class.Class, serverNotification.mixin.NotificationPresenter, { - presenter: serverActivity.function.ReactionNotificationContentProvider - }) - builder.mixin(activity.class.DocUpdateMessage, core.class.Class, serverNotification.mixin.TextPresenter, { presenter: serverActivity.function.DocUpdateMessageTextPresenter }) diff --git a/packages/presentation/src/___tests___/drawing.test.ts b/packages/presentation/src/___tests___/drawing.test.ts index 703cfe5fb9..14ed0a25ba 100644 --- a/packages/presentation/src/___tests___/drawing.test.ts +++ b/packages/presentation/src/___tests___/drawing.test.ts @@ -593,5 +593,54 @@ describe('drawing module tests', () => { ]) }) }) + + describe('tools selection', () => { + it('select color after panning', () => { + const colorsList: ColorsList = [ + ['alpha', new ThemeAwareColor('red', 'yellow')], + ['beta', new ThemeAwareColor('blue', 'blue')] + ] + + const toolChangedSpy = jest.fn() + + const initialPenColor: ColorMetaNameOrHex = 'alpha' + const systemUnderTest = drawing(drawingPlugInPoint, { + colorsList, + getCurrentTheme: () => 'theme-light', + subscribeOnThemeChange: () => {}, + readonly: false, + imageWidth: 400, + imageHeight: 300, + commands: [], + tool: 'pen', + penColor: initialPenColor, + toolChanged: toolChangedSpy + }) + + systemUnderTest.update?.({ + colorsList, + getCurrentTheme: () => 'theme-light', + subscribeOnThemeChange: () => {}, + readonly: false, + tool: 'pan', + toolChanged: toolChangedSpy + }) + + expect(toolChangedSpy).toHaveBeenCalledWith('pan') + toolChangedSpy.mockClear() + + const newColor: ColorMetaNameOrHex = 'beta' + systemUnderTest.update?.({ + colorsList, + getCurrentTheme: () => 'theme-light', + subscribeOnThemeChange: () => {}, + readonly: false, + penColor: newColor, + toolChanged: toolChangedSpy + }) + + expect(toolChangedSpy).toHaveBeenCalledWith('pen') + }) + }) }) }) diff --git a/packages/presentation/src/components/DrawingBoard.svelte b/packages/presentation/src/components/DrawingBoard.svelte index fe64e01704..d7cba893a4 100644 --- a/packages/presentation/src/components/DrawingBoard.svelte +++ b/packages/presentation/src/components/DrawingBoard.svelte @@ -230,6 +230,7 @@ penWidth, eraserWidth, fontSize, + enableMiddleMousePanning: false, changingCmdId, cmdAdded: addCommand, cmdChanging: showCommandProps, @@ -240,6 +241,9 @@ cmdDeleted: deleteCommand, editorCreated: (editor) => { cmdEditor = editor + }, + toolChanged: (newTool) => { + tool = newTool } }} > diff --git a/packages/presentation/src/drawing.ts b/packages/presentation/src/drawing.ts index f788163f08..8573286654 100644 --- a/packages/presentation/src/drawing.ts +++ b/packages/presentation/src/drawing.ts @@ -57,6 +57,7 @@ export interface DrawingProps { changingCmdId?: CommandUid personCursorPos?: Point personCursorVisible?: boolean + enableMiddleMousePanning?: boolean cmdAdded?: (cmd: DrawingCmd) => void cmdChanging?: (id: CommandUid) => void cmdUnchanged?: (id: CommandUid) => void @@ -67,6 +68,7 @@ export interface DrawingProps { personCursorMoved?: (nodePos: Point) => void panning?: (offset: Point) => void panned?: (offset: Point) => void + toolChanged?: (tool: DrawingTool) => void } export type DrawingTool = 'pen' | 'erase' | 'pan' | 'text' @@ -81,6 +83,7 @@ type PointStatus = 'last-point' | 'intermediate-point' class DrawState { on = false + usedBeforePanningTool: DrawingTool | undefined = undefined tool: DrawingTool = 'pen' penColor: ColorMetaNameOrHex = 'alpha' penWidth = 4 @@ -373,6 +376,7 @@ export function drawing ( resizeObserver.observe(canvas) let touchId: number | undefined + let isMiddleMousePanning = false function findTouch (touches: TouchList, id: number | undefined = touchId): Touch | undefined { for (let i = 0; i < touches.length; i++) { @@ -398,7 +402,8 @@ export function drawing ( } const touch = e.changedTouches[0] touchId = touch.identifier - drawStart(touchToNodePoint(touch, canvas)) + const forcePan = false + drawStart(touchToNodePoint(touch, canvas), forcePan) } canvas.ontouchmove = (e) => { @@ -407,7 +412,8 @@ export function drawing ( } const touch = findTouch(e.changedTouches) if (touch !== undefined) { - drawContinue(touchToNodePoint(touch, canvas)) + const forcePan = false + drawContinue(touchToNodePoint(touch, canvas), forcePan) } } @@ -417,7 +423,8 @@ export function drawing ( } const touch = findTouch(e.changedTouches) if (touch !== undefined) { - drawEnd(touchToNodePoint(touch, canvas)) + const forcePan = false + drawEnd(touchToNodePoint(touch, canvas), forcePan) } touchId = undefined } @@ -428,12 +435,22 @@ export function drawing ( if (readonly) { return } + const MiddleMouseButton = 1 + if (e.button === MiddleMouseButton && props.enableMiddleMousePanning === true) { + e.preventDefault() + isMiddleMousePanning = true + canvas.setPointerCapture(e.pointerId) + const forcePan = true + drawStart(pointerToNodePoint(e), forcePan) + return + } if (e.button !== 0) { return } e.preventDefault() canvas.setPointerCapture(e.pointerId) - drawStart(pointerToNodePoint(e)) + const forcePan = false + drawStart(pointerToNodePoint(e), forcePan) } canvas.onpointermove = (e) => { @@ -441,7 +458,8 @@ export function drawing ( return } e.preventDefault() - drawContinue(pointerToNodePoint(e)) + const forcePan = isMiddleMousePanning + drawContinue(pointerToNodePoint(e), forcePan) } canvas.onpointerup = (e) => { @@ -450,10 +468,23 @@ export function drawing ( } e.preventDefault() canvas.releasePointerCapture(e.pointerId) - drawEnd(pointerToNodePoint(e)) + const forcePan = isMiddleMousePanning + drawEnd(pointerToNodePoint(e), forcePan) + if (e.button === 1) { + isMiddleMousePanning = false + } } - canvas.onpointercancel = canvas.onpointerup + canvas.onpointercancel = (e) => { + if (readonly) { + return + } + e.preventDefault() + canvas.releasePointerCapture(e.pointerId) + const forcePan = isMiddleMousePanning + drawEnd(pointerToNodePoint(e), forcePan) + isMiddleMousePanning = false + } canvas.onpointerenter = () => { if (!readonly && draw.isDrawingTool()) { @@ -472,20 +503,20 @@ export function drawing ( return makeMouseScaledPoint(scaled.x, scaled.y) } - function drawStart (p: NodePoint): void { + function drawStart (p: NodePoint, forcePan: boolean): void { const scaledPoint = rescaleWithCss(p) draw.on = true draw.points = [] prevPos = scaledPoint - if (draw.isDrawingTool()) { + if (!forcePan && draw.isDrawingTool()) { draw.addPoint(scaledPoint) } } - function drawContinue (p: NodePoint): void { + function drawContinue (p: NodePoint, forcePan: boolean): void { const scaledPoint = rescaleWithCss(p) - if (draw.isDrawingTool()) { + if (!forcePan && draw.isDrawingTool()) { const cursorSize = draw.cursorWidth() const canvasOffsetInParent = offsetInParent(node, canvas) @@ -501,7 +532,7 @@ export function drawing ( } } - if (draw.on && draw.tool === 'pan') { + if (draw.on && (draw.tool === 'pan' || forcePan)) { requestAnimationFrame(() => { draw.offset.x += scaledPoint.x - prevPos.x draw.offset.y += scaledPoint.y - prevPos.y @@ -513,22 +544,22 @@ export function drawing ( }) } - if (draw.on && draw.tool === 'text') { + if (draw.on && draw.tool === 'text' && !forcePan) { prevPos = scaledPoint } - if (props.pointerMoved !== undefined) { + if (props.pointerMoved !== undefined && !forcePan) { props.pointerMoved(draw.mouseToCanvasPoint(scaledPoint)) } } - function drawEnd (p: NodePoint): void { + function drawEnd (p: NodePoint, forcePan: boolean): void { const scaledPoint = rescaleWithCss(p) if (draw.on) { - if (draw.isDrawingTool()) { + if (!forcePan && draw.isDrawingTool()) { draw.drawLine(scaledPoint, 'last-point', props.getCurrentTheme()) storeLineCommand() - } else if (draw.tool === 'pan') { + } else if (draw.tool === 'pan' || forcePan) { props.panned?.(draw.offset) } else if (draw.tool === 'text') { if (liveTextBox !== undefined) { @@ -1024,6 +1055,11 @@ export function drawing ( } if (props.tool !== undefined) { if (draw.tool !== props.tool) { + if (props.tool === 'pan') { + draw.usedBeforePanningTool = draw.tool + } else { + draw.usedBeforePanningTool = props.tool + } draw.tool = props.tool syncToolCursor = true toolChanged = true @@ -1031,6 +1067,10 @@ export function drawing ( } if (props.penColor !== undefined) { if (draw.penColor !== props.penColor) { + if (draw.tool === 'pan' && draw.usedBeforePanningTool != null) { + draw.tool = draw.usedBeforePanningTool + toolChanged = true + } draw.penColor = props.penColor syncLiveTextBox = true syncToolCursor = true @@ -1084,6 +1124,9 @@ export function drawing ( } } + if (toolChanged) { + props.toolChanged?.(draw.tool) + } if (syncToolCursor) { updateToolCursor() } diff --git a/plugins/activity-resources/src/activityMessagesUtils.ts b/plugins/activity-resources/src/activityMessagesUtils.ts index 0a901294e9..680de67620 100644 --- a/plugins/activity-resources/src/activityMessagesUtils.ts +++ b/plugins/activity-resources/src/activityMessagesUtils.ts @@ -19,7 +19,7 @@ import core, { type Client, type Collection, type Doc, - groupByArrayAsync, + groupByArray, type Hierarchy, type Mixin, type Ref, @@ -29,7 +29,6 @@ import view, { type AttributeModel } from '@hcengineering/view' import { getClient, getFiltredKeys } from '@hcengineering/presentation' import { buildRemovedDoc, - checkIsObjectRemoved, getAttributePresenter, getDocLinkTitle, hasAttributePresenter @@ -37,7 +36,6 @@ import { import contact, { type Person } from '@hcengineering/contact' import { type IntlString } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui' -import { getPersonRefByPersonId } from '@hcengineering/contact-resources' import activity, { type ActivityMessage, type DisplayActivityMessage, @@ -241,10 +239,10 @@ function wrapMessages ( return { toCombine, uncombined } } -export async function combineActivityMessages ( +export function combineActivityMessages ( messages: ActivityMessage[], sortingOrder: SortingOrder = SortingOrder.Ascending -): Promise { +): DisplayActivityMessage[] { const client = getClient() const { uncombined, toCombine } = wrapMessages(client.getHierarchy(), messages) @@ -256,10 +254,7 @@ export async function combineActivityMessages ( const result: Array = [...uncombined] - const groupedByType: Map = await groupByArrayAsync( - docUpdateMessages, - getDocUpdateMessageKey - ) + const groupedByType: Map = groupByArray(docUpdateMessages, getDocUpdateMessageKey) for (const [, groupedMessages] of groupedByType) { const cantMerge = groupedMessages.filter( @@ -280,40 +275,6 @@ export async function combineActivityMessages ( result.push(...cantMerge) } - const viewlets = client.getModel().findAllSync(activity.class.DocUpdateMessageViewlet, {}) - - for (const [index, message] of result.entries()) { - if (message?._class !== activity.class.DocUpdateMessage) { - continue - } - const docUpdateMessage = message as DocUpdateMessage - - if ( - docUpdateMessage.action === 'update' && - !hasAttributeModel(client, docUpdateMessage.attributeUpdates, docUpdateMessage.objectClass) - ) { - result[index] = undefined - continue - } - - const hideIfRemoved = viewlets.some( - (viewlet) => - viewlet.action === docUpdateMessage.action && - viewlet.hideIfRemoved === true && - viewlet.objectClass === docUpdateMessage.objectClass - ) - - if (!hideIfRemoved) { - continue - } - - const isRemoved = await checkIsObjectRemoved(client, docUpdateMessage.objectId, docUpdateMessage.objectClass) - - if (isRemoved) { - result[index] = undefined - } - } - return sortActivityMessages( result.filter((msg): msg is DisplayActivityMessage => msg !== undefined), sortingOrder @@ -367,17 +328,21 @@ function groupByTime (messages: T[]): T[][] { return result } -async function getDocUpdateMessageKey (message: DocUpdateMessage): Promise { - const personRef = await getPersonRefByPersonId(message.createdBy as any) - +function getDocUpdateMessageKey (message: DocUpdateMessage): string { if (message.action === 'update') { - return [message._class, message.attachedTo, message.action, personRef, getAttributeUpdatesKey(message)].join('_') + return [ + message._class, + message.attachedTo, + message.action, + message.createdBy, + getAttributeUpdatesKey(message) + ].join('_') } return [ message._class, message.attachedTo, - personRef, + message.createdBy, message.updateCollection, message.objectId === message.attachedTo ].join('_') @@ -579,18 +544,6 @@ export function isActivityMessage (message?: Doc): message is ActivityMessage { return getClient().getHierarchy().isDerived(message._class, activity.class.ActivityMessage) } -export function isReactionMessage (message?: ActivityMessage): message is DocUpdateMessage { - if (message === undefined) { - return false - } - - if (!isDocUpdateMessage(message)) { - return false - } - - return message.objectClass === activity.class.Reaction -} - export function isActivityMessageClass (_class?: Ref>): boolean { if (_class === undefined) { return false diff --git a/plugins/activity-resources/src/components/Activity.svelte b/plugins/activity-resources/src/components/Activity.svelte index ae113b41e9..c5b3fd4b90 100644 --- a/plugins/activity-resources/src/components/Activity.svelte +++ b/plugins/activity-resources/src/components/Activity.svelte @@ -215,17 +215,15 @@ $: allMessages = sortActivityMessages(messages.concat(refs)) - async function updateActivityMessages (objectId: Ref, order: SortingOrder): Promise { + function updateActivityMessages (objectId: Ref, order: SortingOrder): void { isMessagesLoading = true const res = activityMessagesQuery.query( activity.class.ActivityMessage, { attachedTo: objectId, space: getSpace(object) }, (result: ActivityMessage[]) => { - void combineActivityMessages(result, order).then((res) => { - messages = res - isMessagesLoading = false - }) + messages = combineActivityMessages(result, order) + isMessagesLoading = false }, { sort: { @@ -252,7 +250,7 @@ void scrollToMessage(selectedMessageId) } - $: void updateActivityMessages(object._id, isNewestFirst ? SortingOrder.Descending : SortingOrder.Ascending) + $: updateActivityMessages(object._id, isNewestFirst ? SortingOrder.Descending : SortingOrder.Ascending) export function editLastMessage (): void { if (isMessagesLoading) return diff --git a/plugins/activity-resources/src/components/BasePreview.svelte b/plugins/activity-resources/src/components/BasePreview.svelte index 13b0173664..ce45cc5b4a 100644 --- a/plugins/activity-resources/src/components/BasePreview.svelte +++ b/plugins/activity-resources/src/components/BasePreview.svelte @@ -36,6 +36,8 @@ export let headerIcon: Asset | undefined = undefined export let header: IntlString | undefined = undefined export let headerParams: Record = {} + export let color: 'primary' | 'secondary' = 'primary' + export let lower = false const client = getClient() const limit = 300 @@ -132,8 +134,9 @@ {#if text || intlLabel} {#if intlLabel} @@ -249,6 +252,9 @@ max-height: 1.25rem; color: var(--global-primary-TextColor); + &.secondary { + color: var(--global-secondary-TextColor); + } &.contentOnly { margin-left: 0; } diff --git a/plugins/activity-resources/src/components/Replies.svelte b/plugins/activity-resources/src/components/Replies.svelte index 513d9ab370..60415a948b 100644 --- a/plugins/activity-resources/src/components/Replies.svelte +++ b/plugins/activity-resources/src/components/Replies.svelte @@ -64,9 +64,12 @@ } return (inboxNotificationsByContext?.get(context._id) ?? []) - .filter((notification) => { - const activityNotifications = notification as ActivityInboxNotification - return activityNotifications.attachedToClass !== activity.class.DocUpdateMessage + .filter((it) => { + const activityNotifications = it as ActivityInboxNotification + return ( + activityNotifications.attachedToClass !== activity.class.DocUpdateMessage && + it._class !== notification.class.ReactionInboxNotification + ) }) .some(({ isViewed }) => !isViewed) } diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessagePreview.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessagePreview.svelte index efdb2716a9..76ba62e581 100644 --- a/plugins/activity-resources/src/components/activity-message/ActivityMessagePreview.svelte +++ b/plugins/activity-resources/src/components/activity-message/ActivityMessagePreview.svelte @@ -40,6 +40,7 @@ {#if previewMixin} , - MentionNotification: '' as Ref + MentionNotification: '' as Ref, + AddReactionNotification: '' as Ref }, extension: { ActivityEmployeePresenter: '' as ComponentExtensionId diff --git a/plugins/card-resources/src/utils.ts b/plugins/card-resources/src/utils.ts index eefae66a7d..2cf9c0b3b3 100644 --- a/plugins/card-resources/src/utils.ts +++ b/plugins/card-resources/src/utils.ts @@ -119,7 +119,6 @@ async function generateLocation (loc: Location, id: string): Promise>, view.mixin.ObjectPanel) @@ -131,7 +130,7 @@ async function generateLocation (loc: Location, id: string): Promise | undefined = undefined export let special: 'favorites' | 'all' | string | undefined = undefined - export let mode: 'chat' | 'inbox' = 'chat' const dispatch = createEventDispatcher() - let hasNewInboxNotifications: boolean = false - - const notificationCountQuery = createNotificationsQuery() - - notificationCountQuery.query({ read: false, limit: 1 }, (res) => { - hasNewInboxNotifications = res.getResult().length > 0 - }) - function getSpecial (special: 'favorites' | string | undefined): string | undefined { if (special === 'favorites') { return 'favorites' @@ -52,85 +36,52 @@ return undefined } - function handleInboxClick (): void { - mode = 'inbox' - } - function handleAllUpdatesClick (): void { dispatch('selectAll') } - - function selectInboxCard (event: CustomEvent): void { - const card = event.detail?.card - if (card != null) { - dispatch('selectCard', card) - } - } -{#if mode === 'inbox'} - - -{:else} - -
- - {#if hasNewInboxNotifications} -
- -
- {/if} -
-
-
- - + -{/if} + + diff --git a/plugins/chat-resources/src/components/inbox/InboxCardIcon.svelte b/plugins/chat-resources/src/components/inbox/InboxCardIcon.svelte deleted file mode 100644 index ec08235e6b..0000000000 --- a/plugins/chat-resources/src/components/inbox/InboxCardIcon.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - - - -
- - - {#if count > 0} -
- -
- {/if} -
- - diff --git a/plugins/chat-resources/src/components/inbox/InboxHeader.svelte b/plugins/chat-resources/src/components/inbox/InboxHeader.svelte deleted file mode 100644 index 0b29e53417..0000000000 --- a/plugins/chat-resources/src/components/inbox/InboxHeader.svelte +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - -
- -
- - -
- -
-
- - diff --git a/plugins/chat-resources/src/components/inbox/InboxNavigation.svelte b/plugins/chat-resources/src/components/inbox/InboxNavigation.svelte deleted file mode 100644 index ed6d4cb8da..0000000000 --- a/plugins/chat-resources/src/components/inbox/InboxNavigation.svelte +++ /dev/null @@ -1,201 +0,0 @@ - - - - -{#if contexts.length > 0} - - - -
- it.cardId === card?._id)} - noScroll - kind="full-size" - colorsSchema="lumia" - lazy={true} - getKey={getContextKey} - > - - {@const context = contexts[itemIndex]} - {@const contextCard = cards.find((c) => c._id === context.cardId)} - {#if context && contextCard} - { - dispatch('select', e.detail) - listSelection = itemIndex - }} - /> - {/if} - - -
-
-{:else if isLoading} -
- -
-{:else} -
-
-
- - -
-{/if} - - diff --git a/plugins/chunter-resources/src/channelDataProvider.ts b/plugins/chunter-resources/src/channelDataProvider.ts index 8d8fe3704c..27e9b494b5 100644 --- a/plugins/chunter-resources/src/channelDataProvider.ts +++ b/plugins/chunter-resources/src/channelDataProvider.ts @@ -291,7 +291,7 @@ export class ChannelDataProvider implements IChannelDataProvider { ...(this.tailStart !== undefined ? { createdOn: { $gte: this.tailStart } } : {}) }, async (res) => { - const result = await combineActivityMessages(res.reverse()) + const result = combineActivityMessages(res.reverse()) this.tailStore.set(result) this.isTailLoaded.set(true) @@ -368,7 +368,7 @@ export class ChannelDataProvider implements IChannelDataProvider { return { from: from.createdOn ?? from.modifiedOn, to: to.createdOn ?? to.modifiedOn, - data: isBackward ? await combineActivityMessages(messages.reverse()) : await combineActivityMessages(messages) + data: isBackward ? combineActivityMessages(messages.reverse()) : combineActivityMessages(messages) } } diff --git a/plugins/chunter-resources/src/components/BaseChatScroller.svelte b/plugins/chunter-resources/src/components/BaseChatScroller.svelte index a54eb7f434..c65589499c 100644 --- a/plugins/chunter-resources/src/components/BaseChatScroller.svelte +++ b/plugins/chunter-resources/src/components/BaseChatScroller.svelte @@ -22,6 +22,7 @@ export let loadingOverlay: boolean = false export let onScroll: () => void = () => {} export let onResize: () => void = () => {} + export let key: string {#if loadingOverlay} @@ -41,7 +42,9 @@ {onScroll} {onResize} > - + {#key key} + + {/key} diff --git a/plugins/chunter-resources/src/components/notification/ChatMessageNotificationLabel.svelte b/plugins/chunter-resources/src/components/notification/ChatMessageNotificationLabel.svelte index 56519aa040..116fa07bd2 100644 --- a/plugins/chunter-resources/src/components/notification/ChatMessageNotificationLabel.svelte +++ b/plugins/chunter-resources/src/components/notification/ChatMessageNotificationLabel.svelte @@ -61,7 +61,7 @@ } - + {#if isThread || (object.replies ?? 0) > 0} - + {#if isThread} {:else} {/if} + + diff --git a/plugins/chunter-resources/src/components/notification/JoinChannelNotificationPresenter.svelte b/plugins/chunter-resources/src/components/notification/JoinChannelNotificationPresenter.svelte index ed0e057149..62e8fd4560 100644 --- a/plugins/chunter-resources/src/components/notification/JoinChannelNotificationPresenter.svelte +++ b/plugins/chunter-resources/src/components/notification/JoinChannelNotificationPresenter.svelte @@ -13,12 +13,13 @@ // limitations under the License. --> - + diff --git a/plugins/chunter-resources/src/components/notification/ThreadNotificationPresenter.svelte b/plugins/chunter-resources/src/components/notification/ThreadNotificationPresenter.svelte index 7c9e59d256..be01a1b101 100644 --- a/plugins/chunter-resources/src/components/notification/ThreadNotificationPresenter.svelte +++ b/plugins/chunter-resources/src/components/notification/ThreadNotificationPresenter.svelte @@ -15,8 +15,10 @@ - + diff --git a/plugins/chunter-resources/src/utils.ts b/plugins/chunter-resources/src/utils.ts index d450b328b0..2efcbcc666 100644 --- a/plugins/chunter-resources/src/utils.ts +++ b/plugins/chunter-resources/src/utils.ts @@ -19,7 +19,6 @@ import activity, { type DisplayDocUpdateMessage, type DocUpdateMessage } from '@hcengineering/activity' -import { isReactionMessage } from '@hcengineering/activity-resources' import aiBot from '@hcengineering/ai-bot' import { summarizeMessages as aiSummarizeMessages, translate as aiTranslate } from '@hcengineering/ai-bot-resources' import { type Channel, type ChatMessage, type DirectMessage, type ThreadMessage } from '@hcengineering/chunter' @@ -42,7 +41,8 @@ import notification, { type DocNotifyContext, type InboxNotification } from '@hc import { InboxNotificationsClientImpl, isActivityNotification, - isMentionNotification + isMentionNotification, + isReactionNotification } from '@hcengineering/notification-resources' import { type Asset, getMetadata, translate } from '@hcengineering/platform' import { getClient } from '@hcengineering/presentation' @@ -414,13 +414,7 @@ export async function readChannelMessages ( const notifications = get(inboxClient.activityInboxNotifications) .filter(({ attachedTo, $lookup, isViewed }) => { if (isViewed) return false - const includes = allIds.includes(attachedTo) - if (includes) return true - const msg = $lookup?.attachedTo - if (isReactionMessage(msg)) { - return allIds.includes(msg.attachedTo as Ref) - } - return false + return allIds.includes(attachedTo) }) .map((n) => n._id) @@ -428,6 +422,10 @@ export async function readChannelMessages ( .filter((n) => !n.isViewed && isMentionNotification(n) && allIds.includes(n.mentionedIn as Ref)) .map((n) => n._id) + const reactionNotifications = get(inboxClient.otherInboxNotifications) + .filter((n) => !n.isViewed && isReactionNotification(n) && allIds.includes(n.attachedTo)) + .map((n) => n._id) + chatReadMessagesStore.update((store) => new Set([...store, ...allIds])) const storedTimestampUpdates = get(contextsTimestampStore).get(context._id) @@ -441,7 +439,7 @@ export async function readChannelMessages ( }) await op.update(context, { lastViewedTimestamp: newTimestamp }) } - await inboxClient.readNotifications(op, [...notifications, ...relatedMentions]) + await inboxClient.readNotifications(op, [...notifications, ...relatedMentions, ...reactionNotifications]) } finally { await op.commit() } diff --git a/plugins/client-resources/package.json b/plugins/client-resources/package.json index ec941e712e..ce36f4f289 100644 --- a/plugins/client-resources/package.json +++ b/plugins/client-resources/package.json @@ -38,7 +38,7 @@ "@types/snappyjs": "^0.7.1" }, "dependencies": { - "@hcengineering/analytics": "^0.7.3", + "@hcengineering/analytics": "^0.7.5", "@hcengineering/client": "^0.7.3", "@hcengineering/communication-sdk-types": "^0.7.5", "@hcengineering/communication-types": "^0.7.5", diff --git a/plugins/contact-resources/src/components/SelectAvatarPopup.svelte b/plugins/contact-resources/src/components/SelectAvatarPopup.svelte index bc9111c28d..021ee19883 100644 --- a/plugins/contact-resources/src/components/SelectAvatarPopup.svelte +++ b/plugins/contact-resources/src/components/SelectAvatarPopup.svelte @@ -19,9 +19,10 @@ import type { Ref } from '@hcengineering/core' import { Blob as PlatformBlob } from '@hcengineering/core' import { Asset } from '@hcengineering/platform' - import presentation, { Card, getFileUrl } from '@hcengineering/presentation' - import { + import presentation, { Card, getFileUrl, uiContext } from '@hcengineering/presentation' + import ui, { AnySvelteComponent, + Button, ColorDefinition, Label, TabList, @@ -171,6 +172,12 @@ } } + function handleClearClick (): void { + selectedAvatar = undefined + selectedAvatarType = AvatarType.COLOR + selectedAvatarProps = { color: getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name } + } + const showColorPopup = (event: MouseEvent) => { showPopup( ColorsPopup, @@ -238,6 +245,9 @@ on:select={handleDropdownSelection} />
+ +