mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
UBERF-8999 Presence service (#7539)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Generated
+105
-5
@@ -431,6 +431,9 @@ dependencies:
|
||||
'@rush-temp/model-preference':
|
||||
specifier: file:./projects/model-preference.tgz
|
||||
version: file:projects/model-preference.tgz
|
||||
'@rush-temp/model-presence':
|
||||
specifier: file:./projects/model-presence.tgz
|
||||
version: file:projects/model-presence.tgz
|
||||
'@rush-temp/model-presentation':
|
||||
specifier: file:./projects/model-presentation.tgz
|
||||
version: file:projects/model-presentation.tgz
|
||||
@@ -686,6 +689,12 @@ dependencies:
|
||||
'@rush-temp/preference-assets':
|
||||
specifier: file:./projects/preference-assets.tgz
|
||||
version: file:projects/preference-assets.tgz(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/presence':
|
||||
specifier: file:./projects/presence.tgz
|
||||
version: file:projects/presence.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/presence-resources':
|
||||
specifier: file:./projects/presence-resources.tgz
|
||||
version: file:projects/presence-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/presentation':
|
||||
specifier: file:./projects/presentation.tgz
|
||||
version: file:projects/presentation.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)
|
||||
@@ -1607,9 +1616,6 @@ dependencies:
|
||||
fast-copy:
|
||||
specifier: ~3.0.1
|
||||
version: 3.0.1
|
||||
fast-equals:
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1
|
||||
file-api:
|
||||
specifier: ^0.10.4
|
||||
version: 0.10.4
|
||||
@@ -25797,7 +25803,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/model-all.tgz:
|
||||
resolution: {integrity: sha512-t+T01n/lk1uFmDQvCw+ldE7yBemi2GcvJHXQKaRBXGprTf//JM9Wd9GgvQoYyQsQO7HA8ilAkmnVH3gfP7xxFg==, tarball: file:projects/model-all.tgz}
|
||||
resolution: {integrity: sha512-POSTd7U69WG8HMf3/Budl2bpSfRrigifVT+i8kAOYT8EfuJvT0squXq0TMjYThMNQak91IwJF040+PjIWtlTBw==, tarball: file:projects/model-all.tgz}
|
||||
name: '@rush-temp/model-all'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
@@ -26216,6 +26222,24 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/model-presence.tgz:
|
||||
resolution: {integrity: sha512-bE9NfhmtkeenHePBuorhYSQloGaNnGqtlw2i8ObXBD2ecu21ArwfbrJdHnQiy+Qtq8rs3j+rcCV/BcWpJSBJYQ==, tarball: file:projects/model-presence.tgz}
|
||||
name: '@rush-temp/model-presence'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
prettier: 3.2.5
|
||||
typescript: 5.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/model-presentation.tgz:
|
||||
resolution: {integrity: sha512-fwOpgUcuXhN/upzKDq9tRE1T4bWjBYLHGqHoqu3yrOo82+0aIM7qtCu4bzhl9AdLaOtD/5VYYzFCFWYo2KfRBQ==, tarball: file:projects/model-presentation.tgz}
|
||||
name: '@rush-temp/model-presentation'
|
||||
@@ -28693,6 +28717,82 @@ packages:
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/presence-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-wPkp1Gl14BRxVtSA7GHeRGse3P/mNyw8ZMFaB+GWPy6uzKem9XOIIk6KKgvNgyZBZROcI9KxlEc5nCn6JUZNUw==, tarball: file:projects/presence-resources.tgz}
|
||||
id: file:projects/presence-resources.tgz
|
||||
name: '@rush-temp/presence-resources'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2)
|
||||
fast-equals: 5.0.1
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19)
|
||||
sass: 1.71.1
|
||||
svelte: 4.2.19
|
||||
svelte-check: 3.6.9(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)
|
||||
svelte-eslint-parser: 0.33.1(svelte@4.2.19)
|
||||
svelte-loader: 3.2.0(svelte@4.2.19)
|
||||
svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)(typescript@5.6.2)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2)
|
||||
typescript: 5.6.2
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- coffeescript
|
||||
- esbuild
|
||||
- less
|
||||
- node-notifier
|
||||
- postcss
|
||||
- postcss-load-config
|
||||
- pug
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/presence.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-UAKP+9sJPe3sFFYkuaoRLl5OGmzjdjb35+WCRBenMndS9HljrLekTZp2DL9F1XiyBa4OkB38vYYy2OoobeXx6Q==, tarball: file:projects/presence.tgz}
|
||||
id: file:projects/presence.tgz
|
||||
name: '@rush-temp/presence'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.6.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.6.2)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
prettier: 3.2.5
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.6.2)
|
||||
typescript: 5.6.2
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/presentation.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-oPHDMQuOu5zTYR4++5vrc3LWTZgdZLCxCmnFGSHhNSOG0uRezdWBXlJyN0IL85CI2S03RO/WT16siUOrjG5vwA==, tarball: file:projects/presentation.tgz}
|
||||
id: file:projects/presentation.tgz
|
||||
@@ -28854,7 +28954,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/prod.tgz(bufferutil@4.0.8)(sass@1.71.1)(ts-node@10.9.2)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-5Lih7OOjrS1TenY/2rwnCFmfxjY0Ef0XgCiKURsCa6Rr5BixyOBIKDznMdFXIogr6vxKf0QWbpJVYm6iZE4J/A==, tarball: file:projects/prod.tgz}
|
||||
resolution: {integrity: sha512-Vhce2P4UQlBdcnn6eYAjevEqIDE2pkstFrPKam87+2O8XmnR7ZPzuMVZwkWVbVmXsNjE0N9lKiKNYMdcW2ByRQ==, tarball: file:projects/prod.tgz}
|
||||
id: file:projects/prod.tgz
|
||||
name: '@rush-temp/prod'
|
||||
version: 0.0.0
|
||||
|
||||
@@ -182,6 +182,8 @@
|
||||
"@hcengineering/guest": "^0.6.4",
|
||||
"@hcengineering/guest-assets": "^0.6.0",
|
||||
"@hcengineering/guest-resources": "^0.6.0",
|
||||
"@hcengineering/presence": "^0.6.0",
|
||||
"@hcengineering/presence-resources": "^0.6.0",
|
||||
"@hcengineering/uploader": "^0.6.0",
|
||||
"@hcengineering/uploader-assets": "^0.6.0",
|
||||
"@hcengineering/uploader-resources": "^0.6.0",
|
||||
|
||||
@@ -29,6 +29,7 @@ import { leadId } from '@hcengineering/lead'
|
||||
import login, { loginId } from '@hcengineering/login'
|
||||
import notification, { notificationId } from '@hcengineering/notification'
|
||||
import onboard, { onboardId } from '@hcengineering/onboard'
|
||||
import presence, { presenceId } from '@hcengineering/presence'
|
||||
import { recruitId } from '@hcengineering/recruit'
|
||||
import rekoni from '@hcengineering/rekoni'
|
||||
import { requestId } from '@hcengineering/request'
|
||||
@@ -245,6 +246,7 @@ export async function configurePlatform (): Promise<void> {
|
||||
setMetadata(uiPlugin.metadata.DefaultApplication, login.component.LoginApp)
|
||||
setMetadata(analyticsCollector.metadata.EndpointURL, config.ANALYTICS_COLLECTOR_URL)
|
||||
setMetadata(aiBot.metadata.EndpointURL, config.AI_URL)
|
||||
setMetadata(presence.metadata.PresenceUrl, config.PRESENCE_URL ?? '')
|
||||
|
||||
const languages = myBranding.languages !== undefined && myBranding.languages !== '' ? myBranding.languages.split(',').map((l) => l.trim()) : ['en', 'ru', 'es', 'pt', 'zh', 'fr', 'cs', 'it']
|
||||
|
||||
@@ -303,6 +305,7 @@ export async function configurePlatform (): Promise<void> {
|
||||
addLocation(productsId, async () => await import('@hcengineering/products-resources'))
|
||||
addLocation(documentsId, async () => await import('@hcengineering/controlled-documents-resources'))
|
||||
addLocation(uploaderId, async () => await import('@hcengineering/uploader-resources'))
|
||||
addLocation(presenceId, async () => await import('@hcengineering/presence-resources'))
|
||||
addLocation(githubId, async () => await import(/* webpackChunkName: "github" */ '@hcengineering/github-resources'))
|
||||
addLocation(
|
||||
desktopPreferencesId,
|
||||
@@ -313,7 +316,7 @@ export async function configurePlatform (): Promise<void> {
|
||||
addLocation(printId, () => import(/* webpackChunkName: "print" */ '@hcengineering/print-resources'))
|
||||
addLocation(textEditorId, () => import(/* webpackChunkName: "text-editor" */ '@hcengineering/text-editor-resources'))
|
||||
addLocation(testManagementId, () => import(/* webpackChunkName: "test-management" */ '@hcengineering/test-management-resources'))
|
||||
addLocation(surveyId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/survey-resources'))
|
||||
addLocation(surveyId, () => import(/* webpackChunkName: "survey" */ '@hcengineering/survey-resources'))
|
||||
|
||||
setMetadata(client.metadata.FilterModel, 'ui')
|
||||
setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin])
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface Config {
|
||||
DESKTOP_UPDATES_URL?: string
|
||||
DESKTOP_UPDATES_CHANNEL?: string
|
||||
TELEGRAM_BOT_URL?: string
|
||||
PRESENCE_URL?: string
|
||||
|
||||
STATS_URL?: string
|
||||
}
|
||||
|
||||
@@ -213,6 +213,8 @@
|
||||
"@hcengineering/print": "^0.6.0",
|
||||
"@hcengineering/print-assets": "^0.6.0",
|
||||
"@hcengineering/print-resources": "^0.6.0",
|
||||
"@hcengineering/presence": "^0.6.0",
|
||||
"@hcengineering/presence-resources": "^0.6.0",
|
||||
"@hcengineering/uploader": "^0.6.0",
|
||||
"@hcengineering/uploader-assets": "^0.6.0",
|
||||
"@hcengineering/uploader-resources": "^0.6.0",
|
||||
|
||||
@@ -62,6 +62,7 @@ import { viewId } from '@hcengineering/view'
|
||||
import workbench, { workbenchId } from '@hcengineering/workbench'
|
||||
import { testManagementId } from '@hcengineering/test-management'
|
||||
import { surveyId } from '@hcengineering/survey'
|
||||
import presence, { presenceId } from '@hcengineering/presence'
|
||||
|
||||
import { bitrixId } from '@hcengineering/bitrix'
|
||||
|
||||
@@ -161,6 +162,7 @@ export interface Config {
|
||||
PREVIEW_CONFIG?: string
|
||||
UPLOAD_CONFIG?: string
|
||||
STATS_URL?: string
|
||||
PRESENCE_URL?: string
|
||||
USE_BINARY_PROTOCOL?: boolean,
|
||||
TRANSACTOR_OVERRIDE?: string
|
||||
}
|
||||
@@ -342,6 +344,7 @@ export async function configurePlatform() {
|
||||
setMetadata(love.metadata.WebSocketURL, config.LIVEKIT_WS)
|
||||
setMetadata(print.metadata.PrintURL, config.PRINT_URL)
|
||||
setMetadata(sign.metadata.SignURL, config.SIGN_URL)
|
||||
setMetadata(presence.metadata.PresenceUrl, config.PRESENCE_URL ?? '')
|
||||
|
||||
const languages = myBranding.languages ? (myBranding.languages as string).split(',').map((l) => l.trim()) : ['en', 'ru', 'es', 'pt', 'zh', 'fr', 'cs', 'it']
|
||||
|
||||
@@ -409,7 +412,8 @@ export async function configurePlatform() {
|
||||
addLocation(textEditorId, () => import(/* webpackChunkName: "text-editor" */ '@hcengineering/text-editor-resources'))
|
||||
addLocation(uploaderId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/uploader-resources'))
|
||||
addLocation(testManagementId, () => import(/* webpackChunkName: "test-management" */ '@hcengineering/test-management-resources'))
|
||||
addLocation(surveyId, () => import(/* webpackChunkName: "uploader" */ '@hcengineering/survey-resources'))
|
||||
addLocation(surveyId, () => import(/* webpackChunkName: "survey" */ '@hcengineering/survey-resources'))
|
||||
addLocation(presenceId, () => import(/* webpackChunkName: "presence" */ '@hcengineering/presence-resources'))
|
||||
|
||||
setMetadata(client.metadata.FilterModel, 'ui')
|
||||
setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin])
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
"@hcengineering/model-ai-bot": "^0.6.0",
|
||||
"@hcengineering/model-server-fulltext": "^0.6.0",
|
||||
"@hcengineering/model-test-management": "^0.6.0",
|
||||
"@hcengineering/model-survey": "^0.6.0"
|
||||
"@hcengineering/model-survey": "^0.6.0",
|
||||
"@hcengineering/model-presence": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ import {
|
||||
} from '@hcengineering/model-server-controlled-documents'
|
||||
import { serverFulltextId, createModel as serverFulltextModel } from '@hcengineering/model-server-fulltext'
|
||||
import { surveyId, createModel as surveyModel } from '@hcengineering/model-survey'
|
||||
import { presenceId, createModel as presenceModel } from '@hcengineering/model-presence'
|
||||
|
||||
import { type Plugin } from '@hcengineering/platform'
|
||||
|
||||
@@ -422,6 +423,7 @@ export default function buildModel (enabled: string[] = ['*'], disabled: string[
|
||||
}
|
||||
],
|
||||
[surveyModel, surveyId],
|
||||
[presenceModel, presenceId],
|
||||
|
||||
[serverCoreModel, serverCoreId],
|
||||
[serverAttachmentModel, serverAttachmentId],
|
||||
|
||||
@@ -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,41 @@
|
||||
{
|
||||
"name": "@hcengineering/model-presence",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Hardcore Engineering Inc.",
|
||||
"template": "@hcengineering/model-package",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/model": "^0.6.11",
|
||||
"@hcengineering/model-core": "^0.6.0",
|
||||
"@hcengineering/model-presentation": "^0.6.0",
|
||||
"@hcengineering/model-workbench": "^0.6.1",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/ui": "^0.6.15",
|
||||
"@hcengineering/presence": "^0.6.0",
|
||||
"@hcengineering/presence-resources": "^0.6.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
|
||||
import presence from './plugin'
|
||||
|
||||
export { presenceId } from '@hcengineering/presence'
|
||||
export { presence as default }
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, {
|
||||
extension: workbench.extensions.WorkbenchExtensions,
|
||||
component: presence.component.WorkbenchExtension
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import { type AnyComponent } from '@hcengineering/ui'
|
||||
import { presenceId } from '@hcengineering/presence'
|
||||
import presence from '@hcengineering/presence-resources/src/plugin'
|
||||
|
||||
export default mergeIds(presenceId, presence, {
|
||||
component: {
|
||||
WorkbenchExtension: '' as AnyComponent
|
||||
}
|
||||
})
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
"@hcengineering/chunter": "^0.6.20",
|
||||
"@hcengineering/presentation": "^0.6.3",
|
||||
"@hcengineering/activity": "^0.6.0",
|
||||
"@hcengineering/calendar": "^0.6.24"
|
||||
"@hcengineering/calendar": "^0.6.24",
|
||||
"@hcengineering/presence": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
} from '@hcengineering/ui'
|
||||
import type { ButtonItem } from '@hcengineering/ui'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import presence from '@hcengineering/presence'
|
||||
|
||||
export let title: string | undefined = undefined
|
||||
export let withoutActivity: boolean = false
|
||||
@@ -41,6 +42,7 @@
|
||||
export let isSub: boolean = true
|
||||
export let isAside: boolean = true
|
||||
export let isUtils: boolean = true
|
||||
export let isPresence: boolean = true
|
||||
export let isCustomAttr: boolean = true
|
||||
export let floatAside: boolean = false
|
||||
export let allowClose: boolean = true
|
||||
@@ -146,6 +148,8 @@
|
||||
dispatch('select', result.detail)
|
||||
}}
|
||||
>
|
||||
<Component is={presence.component.Presence} props={{ object }} />
|
||||
|
||||
<svelte:fragment slot="title">
|
||||
{#if !withoutTitle}
|
||||
{#if $$slots.title}
|
||||
@@ -156,6 +160,12 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="presence">
|
||||
{#if isPresence}
|
||||
<Component is={presence.component.PresenceAvatars} props={{ object, size: 'x-small', limit: 5 }} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="pre-utils">
|
||||
<slot name="pre-utils" />
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
export let hideSearch: boolean = false
|
||||
export let hideActions: boolean = false
|
||||
export let hideExtra: boolean = false
|
||||
export let hidePresence: boolean = false
|
||||
export let overflowExtra: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let freezeBefore: boolean = false
|
||||
@@ -149,6 +150,11 @@
|
||||
</div>
|
||||
<!-- <div class="hulyHeader-row__divider" /> -->
|
||||
<div class="hulyHeader-row no-print" class:between={$$slots.search} class:reverse={!$$slots.search}>
|
||||
{#if $$slots.presence && !hidePresence}
|
||||
<div class="hulyHeader-buttonsGroup presence no-print">
|
||||
<slot name="presence" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.search}
|
||||
<div class="hulyHeader-buttonsGroup search">
|
||||
<slot name="search" {doubleRow} />
|
||||
@@ -214,12 +220,19 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.presence && !hidePresence}
|
||||
<div class="hulyHeader-buttonsGroup presence no-print">
|
||||
<slot name="presence" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.search && !hideSearch}
|
||||
<div class="hulyHeader-buttonsGroup search no-print">
|
||||
<slot name="search" {doubleRow} />
|
||||
</div>
|
||||
{#if $$slots.actions && !hideActions}<div class="hulyHeader-divider no-print" />{/if}
|
||||
{/if}
|
||||
|
||||
{#if $$slots.extra && !hideExtra}
|
||||
<div
|
||||
class="hulyHeader-buttonsGroup extra"
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<slot name="actions" />
|
||||
<slot name="presence" />
|
||||
<slot name="pre-utils" />
|
||||
<slot name="utils" />
|
||||
{#if useMaxWidth !== undefined}
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"@hcengineering/view-resources": "^0.6.0",
|
||||
"@hcengineering/workbench": "^0.6.16",
|
||||
"@hcengineering/workbench-resources": "^0.6.1",
|
||||
"@hcengineering/presence-resources": "^0.6.0",
|
||||
"fast-equals": "^5.0.1",
|
||||
"svelte": "^4.2.19",
|
||||
"@hcengineering/text-editor-resources": "^0.6.0",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
export let canOpen: boolean = false
|
||||
export let withAside: boolean = false
|
||||
export let withSearch: boolean = true
|
||||
export let withPresence: boolean = true
|
||||
export let isAsideShown: boolean = false
|
||||
export let filters: Ref<ActivityMessagesFilter>[] = []
|
||||
export let canOpenInSidebar: boolean = false
|
||||
@@ -80,6 +81,7 @@
|
||||
{withAside}
|
||||
{isAsideShown}
|
||||
{withSearch}
|
||||
{withPresence}
|
||||
{canOpenInSidebar}
|
||||
{closeOnEscape}
|
||||
bind:realWidth
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import { Widget } from '@hcengineering/workbench'
|
||||
import { ActivityMessage } from '@hcengineering/activity'
|
||||
import { ChatWidgetTab } from '@hcengineering/chunter'
|
||||
import { Presence } from '@hcengineering/presence-resources'
|
||||
import { updateTabData } from '@hcengineering/workbench-resources'
|
||||
|
||||
import Channel from './Channel.svelte'
|
||||
@@ -76,6 +77,7 @@
|
||||
</script>
|
||||
|
||||
{#if object && renderChannel && visible}
|
||||
<Presence {object} />
|
||||
<div class="channel" class:invisible={threadId !== undefined} style:height style:width>
|
||||
<ChannelHeader
|
||||
_id={object._id}
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import chunter, { TypingInfo } from '@hcengineering/chunter'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { getName, Person } from '@hcengineering/contact'
|
||||
import { personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getCurrentAccount, IdMap } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import { PresenceTyping } from '../types'
|
||||
|
||||
export let typingInfo: TypingInfo[] = []
|
||||
export let typingInfo: PresenceTyping[] = []
|
||||
|
||||
const typingDelay = 2000
|
||||
const maxTypingPersons = 3
|
||||
@@ -34,7 +35,7 @@
|
||||
|
||||
$: updateTypingPersons($personByIdStore, typingInfo)
|
||||
|
||||
function updateTypingPersons (personById: IdMap<Person>, typingInfo: TypingInfo[]) {
|
||||
function updateTypingPersons (personById: IdMap<Person>, typingInfo: PresenceTyping[]): void {
|
||||
const now = Date.now()
|
||||
const personIds = new Set(
|
||||
typingInfo
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
import { Channel, ObjectChatPanel } from '@hcengineering/chunter'
|
||||
import view from '@hcengineering/view'
|
||||
import { messageInFocus } from '@hcengineering/activity-resources'
|
||||
import { Presence } from '@hcengineering/presence-resources'
|
||||
|
||||
import ChannelComponent from './Channel.svelte'
|
||||
import ChannelHeader from './ChannelHeader.svelte'
|
||||
@@ -103,6 +104,8 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Presence {object} />
|
||||
|
||||
<div class="popupPanel">
|
||||
<ChannelHeader
|
||||
_id={object._id}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
import ChannelSidebarView from './ChannelSidebarView.svelte'
|
||||
import chunter from '../plugin'
|
||||
import ThreadSidebarView from './threads/ThreadSidebarView.svelte'
|
||||
|
||||
export let widget: Widget | undefined
|
||||
export let tab: ChatWidgetTab | undefined
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import { ActivityMessagesFilter } from '@hcengineering/activity'
|
||||
import workbench from '@hcengineering/workbench'
|
||||
import { PresenceAvatars } from '@hcengineering/presence-resources'
|
||||
|
||||
import { userSearch } from '../index'
|
||||
import chunter from '../plugin'
|
||||
@@ -53,6 +54,7 @@
|
||||
export let titleKind: 'default' | 'breadcrumbs' = 'default'
|
||||
export let withFilters: boolean = false
|
||||
export let withSearch: boolean = true
|
||||
export let withPresence: boolean = true
|
||||
export let filters: Ref<ActivityMessagesFilter>[] = []
|
||||
export let adaptive: HeaderAdaptive = 'default'
|
||||
export let hideActions: boolean = false
|
||||
@@ -118,6 +120,12 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="presence">
|
||||
{#if withPresence && object}
|
||||
<PresenceAvatars {object} size="x-small" limit={3} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="search" let:doubleRow>
|
||||
{#if withSearch}
|
||||
<SearchInput
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
|
||||
import chunter, { ChatMessage, ChunterEvents, ThreadMessage, TypingInfo } from '@hcengineering/chunter'
|
||||
import chunter, { ChatMessage, ChunterEvents, ThreadMessage } from '@hcengineering/chunter'
|
||||
import { Class, Doc, generateId, Ref, type CommitResult, getCurrentAccount } from '@hcengineering/core'
|
||||
import { createQuery, DraftController, draftsStore, getClient } from '@hcengineering/presentation'
|
||||
import { EmptyMarkup, isEmptyMarkup } from '@hcengineering/text'
|
||||
@@ -25,7 +25,9 @@
|
||||
import { ThrottledCaller } from '@hcengineering/ui'
|
||||
import { getSpace } from '@hcengineering/activity-resources'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import { presenceByObjectId, updateMyPresence } from '@hcengineering/presence-resources'
|
||||
|
||||
import { type PresenceTyping } from '../../types'
|
||||
import { getChannelSpace } from '../../utils'
|
||||
import ChannelTypingInfo from '../ChannelTypingInfo.svelte'
|
||||
|
||||
@@ -75,15 +77,9 @@
|
||||
createdMessageQuery.unsubscribe()
|
||||
}
|
||||
|
||||
const typingInfoQuery = createQuery()
|
||||
let typingInfo: TypingInfo[] = []
|
||||
$: if (withTypingInfo) {
|
||||
typingInfoQuery.query(chunter.class.TypingInfo, { objectId: object._id, space: getSpace(object) }, (res) => {
|
||||
typingInfo = res
|
||||
})
|
||||
} else {
|
||||
typingInfoQuery.unsubscribe()
|
||||
}
|
||||
let typingInfo: PresenceTyping[] = []
|
||||
$: presence = $presenceByObjectId.get(object._id) ?? []
|
||||
$: typingInfo = presence.map((p) => p.presence.typing).filter((p) => p !== undefined)
|
||||
|
||||
function clear (): void {
|
||||
currentMessage = getDefault()
|
||||
@@ -111,29 +107,18 @@
|
||||
|
||||
async function deleteTypingInfo (): Promise<void> {
|
||||
if (!withTypingInfo) return
|
||||
const myTypingInfo = typingInfo.find((info) => info.person === me.person)
|
||||
if (myTypingInfo === undefined) return
|
||||
await client.remove(myTypingInfo)
|
||||
const room = { objectId: object._id, objectClass: object._class }
|
||||
updateMyPresence(room, { typing: undefined })
|
||||
}
|
||||
|
||||
async function updateTypingInfo (): Promise<void> {
|
||||
if (!withTypingInfo) return
|
||||
const myTypingInfo = typingInfo.find((info) => info.person === me.person)
|
||||
|
||||
if (myTypingInfo === undefined) {
|
||||
await client.createDoc(chunter.class.TypingInfo, getSpace(object), {
|
||||
objectId: object._id,
|
||||
objectClass: object._class,
|
||||
person: me.person,
|
||||
lastTyping: Date.now()
|
||||
})
|
||||
} else {
|
||||
throttle.call(() => {
|
||||
void client.update(myTypingInfo, {
|
||||
lastTyping: Date.now()
|
||||
})
|
||||
})
|
||||
}
|
||||
throttle.call(() => {
|
||||
const room = { objectId: object._id, objectClass: object._class }
|
||||
const typing = { person: me.person, lastTyping: Date.now() }
|
||||
updateMyPresence(room, { typing })
|
||||
})
|
||||
}
|
||||
|
||||
function onUpdate (event: CustomEvent): void {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { Person } from '@hcengineering/contact'
|
||||
import type { Ref, Timestamp } from '@hcengineering/core'
|
||||
|
||||
export interface PresenceTyping {
|
||||
person: Ref<Person>
|
||||
lastTyping: Timestamp
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/ui/eslint.config.json'],
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"useTabs": false,
|
||||
"bracketSpacing": true,
|
||||
"proseWrap": "preserve",
|
||||
"plugins": [
|
||||
"prettier-plugin-svelte"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig",
|
||||
"rigProfile": "ui"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)']
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "@hcengineering/presence-resources",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Hardcore Engineering Inc.",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile ui",
|
||||
"build:docs": "api-extractor run --local",
|
||||
"format": "format src",
|
||||
"svelte-check": "do-svelte-check",
|
||||
"_phase:svelte-check": "do-svelte-check",
|
||||
"build:watch": "compile ui",
|
||||
"_phase:build": "compile ui",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader": "^3.2.0",
|
||||
"sass": "^1.53.0",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.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",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"prettier-plugin-svelte": "^3.2.2",
|
||||
"eslint": "^8.54.0",
|
||||
"prettier": "^3.1.0",
|
||||
"svelte-check": "^3.6.9",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5",
|
||||
"svelte-eslint-parser": "^0.33.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/presentation": "^0.6.3",
|
||||
"@hcengineering/theme": "^0.6.5",
|
||||
"@hcengineering/ui": "^0.6.15",
|
||||
"@hcengineering/view": "^0.6.13",
|
||||
"@hcengineering/view-resources": "^0.6.0",
|
||||
"@hcengineering/contact": "^0.6.24",
|
||||
"@hcengineering/contact-resources": "^0.6.0",
|
||||
"@hcengineering/presence": "^0.6.0",
|
||||
"svelte": "^4.2.19",
|
||||
"fast-equals": "^5.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// 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 Ref, concatLink, getCurrentAccount } from '@hcengineering/core'
|
||||
import { type Person, type PersonAccount } from '@hcengineering/contact'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import presence from '@hcengineering/presence'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import { type Unsubscriber, get } from 'svelte/store'
|
||||
|
||||
import { myPresence, onPersonUpdate, onPersonLeave } from './store'
|
||||
import { type RoomPresence } from './types'
|
||||
|
||||
interface Message {
|
||||
id: Ref<Person>
|
||||
type: 'update' | 'remove'
|
||||
presence?: RoomPresence[]
|
||||
lastUpdate?: number
|
||||
}
|
||||
|
||||
export class PresenceClient implements Disposable {
|
||||
private ws: WebSocket | null = null
|
||||
private closed = false
|
||||
private reconnectTimeout: number | undefined
|
||||
private readonly reconnectInterval = 1000
|
||||
|
||||
private presence: RoomPresence[]
|
||||
private readonly myPresenceUnsub: Unsubscriber
|
||||
|
||||
constructor (private readonly url: string | URL) {
|
||||
this.presence = get(myPresence)
|
||||
this.myPresenceUnsub = myPresence.subscribe((presence) => {
|
||||
this.handlePresenceChanged(presence)
|
||||
})
|
||||
|
||||
this.connect()
|
||||
}
|
||||
|
||||
close (): void {
|
||||
this.closed = true
|
||||
clearTimeout(this.reconnectTimeout)
|
||||
|
||||
this.myPresenceUnsub()
|
||||
|
||||
if (this.ws !== null) {
|
||||
this.ws.close()
|
||||
this.ws = null
|
||||
}
|
||||
}
|
||||
|
||||
private connect (): void {
|
||||
try {
|
||||
const ws = new WebSocket(this.url)
|
||||
this.ws = ws
|
||||
|
||||
ws.onopen = () => {
|
||||
if (this.ws !== ws) {
|
||||
return
|
||||
}
|
||||
|
||||
this.handleConnect()
|
||||
}
|
||||
|
||||
ws.onclose = (event: CloseEvent) => {
|
||||
if (this.ws !== ws) {
|
||||
ws.close()
|
||||
return
|
||||
}
|
||||
|
||||
this.reconnect()
|
||||
}
|
||||
|
||||
ws.onmessage = (event: MessageEvent) => {
|
||||
if (this.closed || this.ws !== ws) {
|
||||
return
|
||||
}
|
||||
|
||||
this.handleMessage(event.data)
|
||||
}
|
||||
|
||||
ws.onerror = (event: Event) => {
|
||||
if (this.ws !== ws) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('client websocket error', event)
|
||||
}
|
||||
} catch (err: any) {
|
||||
this.reconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private reconnect (): void {
|
||||
clearTimeout(this.reconnectTimeout)
|
||||
|
||||
if (!this.closed) {
|
||||
this.reconnectTimeout = window.setTimeout(() => {
|
||||
this.connect()
|
||||
}, this.reconnectInterval)
|
||||
}
|
||||
}
|
||||
|
||||
private handleConnect (): void {
|
||||
const me = getCurrentAccount() as PersonAccount
|
||||
this.sendPresence(me.person, this.presence)
|
||||
}
|
||||
|
||||
private handleMessage (data: string): void {
|
||||
try {
|
||||
const message = JSON.parse(data) as Message
|
||||
if (message.type === 'update' && message.presence !== undefined) {
|
||||
onPersonUpdate(message.id, message.presence ?? [])
|
||||
} else if (message.type === 'remove') {
|
||||
onPersonLeave(message.id)
|
||||
} else {
|
||||
console.warn('Unknown message type', message)
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Error parsing message', err, data)
|
||||
}
|
||||
}
|
||||
|
||||
private handlePresenceChanged (presence: RoomPresence[]): void {
|
||||
const me = getCurrentAccount() as PersonAccount
|
||||
this.presence = presence
|
||||
this.sendPresence(me.person, this.presence)
|
||||
}
|
||||
|
||||
private sendPresence (person: Ref<Person>, presence: RoomPresence[]): void {
|
||||
if (!this.closed && this.ws !== null && this.ws.readyState === WebSocket.OPEN) {
|
||||
const message: Message = { id: person, type: 'update', presence }
|
||||
this.ws.send(JSON.stringify(message))
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.dispose] (): void {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
|
||||
export function connect (): PresenceClient | undefined {
|
||||
const workspaceId = getMetadata(presentation.metadata.WorkspaceId)
|
||||
if (workspaceId === undefined) {
|
||||
console.warn('Workspace ID is not defined')
|
||||
return undefined
|
||||
}
|
||||
|
||||
const token = getMetadata(presentation.metadata.Token)
|
||||
|
||||
const presenceUrl = getMetadata(presence.metadata.PresenceUrl)
|
||||
if (presenceUrl === undefined || presenceUrl === '') {
|
||||
console.warn('Presence URL is not defined')
|
||||
return undefined
|
||||
}
|
||||
|
||||
const url = new URL(concatLink(presenceUrl, workspaceId))
|
||||
if (token !== undefined) {
|
||||
url.searchParams.set('token', token)
|
||||
}
|
||||
|
||||
return new PresenceClient(url)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { Doc } from '@hcengineering/core'
|
||||
|
||||
import PresenceContext from './PresenceContext.svelte'
|
||||
|
||||
export let object: Doc
|
||||
</script>
|
||||
|
||||
{#key object._id}
|
||||
<PresenceContext {object} />
|
||||
{/key}
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { type Doc } from '@hcengineering/core'
|
||||
import contact, { formatName } from '@hcengineering/contact'
|
||||
import { Avatar, CombineAvatars, personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { IconSize, tooltip } from '@hcengineering/ui'
|
||||
import { presenceByObjectId } from '../store'
|
||||
|
||||
export let object: Doc
|
||||
|
||||
export let size: IconSize = 'small'
|
||||
export let limit: number = 5
|
||||
export let hideLimit: boolean = false
|
||||
export let combine = false
|
||||
|
||||
$: presence = $presenceByObjectId?.get(object._id) ?? []
|
||||
$: items = presence.map((it) => it.person)
|
||||
</script>
|
||||
|
||||
{#if items.length > 0}
|
||||
{#if combine}
|
||||
<CombineAvatars _class={contact.mixin.Employee} {items} {size} {limit} {hideLimit} />
|
||||
{:else}
|
||||
<div class="flex-row-center flex-gap-0-5">
|
||||
{#each items as item}
|
||||
{@const person = $personByIdStore.get(item)}
|
||||
{#if person}
|
||||
<div use:tooltip={{ label: getEmbeddedLabel(formatName(person.name)) }}>
|
||||
<Avatar name={person.name} {size} {person} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -0,0 +1,33 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { Doc } from '@hcengineering/core'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
import { updateMyPresence, removeMyPresence } from '../store'
|
||||
|
||||
export let object: Doc
|
||||
|
||||
onMount(() => {
|
||||
updateMyPresence({ objectId: object._id, objectClass: object._class }, {})
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
removeMyPresence({ objectId: object._id, objectClass: object._class })
|
||||
})
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
import { type PresenceClient, connect } from '../client'
|
||||
|
||||
let parentElement: HTMLDivElement
|
||||
let client: PresenceClient | undefined
|
||||
|
||||
onMount(() => {
|
||||
client = connect()
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
client?.close()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this={parentElement} class="hidden"></div>
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// 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 Resources } from '@hcengineering/platform'
|
||||
|
||||
import Presence from './components/Presence.svelte'
|
||||
import PresenceAvatars from './components/PresenceAvatars.svelte'
|
||||
import WorkbenchExtension from './components/WorkbenchExtension.svelte'
|
||||
|
||||
export { Presence, PresenceAvatars }
|
||||
export { updateMyPresence, removeMyPresence, presenceByObjectId } from './store'
|
||||
|
||||
export * from './types'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
Presence,
|
||||
PresenceAvatars,
|
||||
WorkbenchExtension
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import presence, { presenceId } from '@hcengineering/presence'
|
||||
|
||||
export default mergeIds(presenceId, presence, {})
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// 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 Doc, type Ref, getCurrentAccount } from '@hcengineering/core'
|
||||
import { type Person, type PersonAccount } from '@hcengineering/contact'
|
||||
import { type PresenceData } from '@hcengineering/presence'
|
||||
import { type Readable, derived, writable } from 'svelte/store'
|
||||
|
||||
import { type PersonRoomPresence, type Room, type RoomPresence } from './types'
|
||||
|
||||
type PersonPresenceMap = Map<Ref<Person>, RoomPresence[]>
|
||||
|
||||
export const myPresence = writable<RoomPresence[]>([])
|
||||
export const otherPresence = writable<PersonPresenceMap>(new Map())
|
||||
|
||||
export const presenceByObjectId = derived<Readable<PersonPresenceMap>, Map<Ref<Doc>, PersonRoomPresence[]>>(
|
||||
otherPresence,
|
||||
($presence) => {
|
||||
const me = getCurrentAccount() as PersonAccount
|
||||
const map = new Map<Ref<Doc>, PersonRoomPresence[]>()
|
||||
for (const [person, presences] of $presence.entries()) {
|
||||
if (person === me.person) continue
|
||||
|
||||
presences.forEach((presence) => {
|
||||
const values = map.get(presence.room.objectId) ?? []
|
||||
values.push({ person, ...presence })
|
||||
|
||||
map.set(presence.room.objectId, values)
|
||||
})
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
)
|
||||
|
||||
export function updateMyPresence (room: Room, presence: PresenceData): void {
|
||||
myPresence.update((rooms) => {
|
||||
const value = { room, presence, lastUpdated: Date.now() }
|
||||
|
||||
const index = rooms.findIndex((it) => it.room.objectId === room.objectId)
|
||||
if (index >= 0) {
|
||||
rooms[index] = value
|
||||
} else {
|
||||
rooms.push(value)
|
||||
}
|
||||
|
||||
return rooms
|
||||
})
|
||||
}
|
||||
|
||||
export function removeMyPresence (room: Room): void {
|
||||
myPresence.update((old) => {
|
||||
return old.filter((it) => it.room.objectId !== room.objectId)
|
||||
})
|
||||
}
|
||||
|
||||
export function onPersonUpdate (person: Ref<Person>, presence: RoomPresence[]): void {
|
||||
otherPresence.update((map) => {
|
||||
map.set(person, [...presence])
|
||||
return map
|
||||
})
|
||||
}
|
||||
|
||||
export function onPersonLeave (person: Ref<Person>): void {
|
||||
otherPresence.update((map) => {
|
||||
map.delete(person)
|
||||
return map
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type Person } from '@hcengineering/contact'
|
||||
import { type PresenceData } from '@hcengineering/presence'
|
||||
|
||||
export interface Room {
|
||||
objectId: Ref<Doc>
|
||||
objectClass: Ref<Class<Doc>>
|
||||
}
|
||||
|
||||
export interface RoomPresence {
|
||||
room: Room
|
||||
presence: PresenceData
|
||||
lastUpdated: number
|
||||
}
|
||||
|
||||
export interface PersonRoomPresence {
|
||||
person: Ref<Person>
|
||||
room: Room
|
||||
presence: PresenceData
|
||||
lastUpdated: number
|
||||
}
|
||||
|
||||
export interface PersonPresence {
|
||||
person: Ref<Person>
|
||||
presence: RoomPresence[]
|
||||
lastUpdated: number
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types"
|
||||
}
|
||||
}
|
||||
@@ -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,48 @@
|
||||
{
|
||||
"name": "@hcengineering/presence",
|
||||
"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.",
|
||||
"license": "EPL-2.0",
|
||||
"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",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.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",
|
||||
"eslint": "^8.54.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/ui": "^0.6.15"
|
||||
},
|
||||
"repository": "https://github.com/hcengineering/platform",
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { presenceId, presencePlugin } from './plugin'
|
||||
|
||||
export * from './types'
|
||||
|
||||
export { presenceId }
|
||||
export default presencePlugin
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// 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 { Metadata, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
|
||||
/** @public */
|
||||
export const presenceId = 'presence' as Plugin
|
||||
|
||||
export const presencePlugin = plugin(presenceId, {
|
||||
metadata: {
|
||||
PresenceUrl: '' as Metadata<string>
|
||||
},
|
||||
component: {
|
||||
Presence: '' as AnyComponent,
|
||||
PresenceAvatars: '' as AnyComponent
|
||||
}
|
||||
})
|
||||
|
||||
export default presencePlugin
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
export type PresenceData = Record<string, any>
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,6 @@
|
||||
} from '@hcengineering/text-editor'
|
||||
import { addTableHandler } from '../utils'
|
||||
|
||||
import CollaborationUsers from './CollaborationUsers.svelte'
|
||||
import TextEditorToolbar from './TextEditorToolbar.svelte'
|
||||
import { noSelectionRender, renderCursor } from './editor/collaboration'
|
||||
import { defaultEditorAttributes } from './editor/editorProps'
|
||||
@@ -584,11 +583,11 @@
|
||||
|
||||
<div class="textInput">
|
||||
<div class="select-text" class:hidden={loading} style="width: 100%;" bind:this={element} />
|
||||
<div class="collaborationUsers-container flex-col flex-gap-2 pt-2">
|
||||
<!-- <div class="collaborationUsers-container flex-col flex-gap-2 pt-2">
|
||||
{#if remoteProvider && editor && userComponent}
|
||||
<CollaborationUsers provider={remoteProvider} {editor} component={userComponent} />
|
||||
{/if}
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
{#if refActions.length > 0}
|
||||
|
||||
@@ -37,6 +37,7 @@ startFront(metricsContext, {
|
||||
LOVE_ENDPOINT: process.env.LOVE_ENDPOINT ?? '',
|
||||
SIGN_URL: process.env.SIGN_URL ?? '',
|
||||
PRINT_URL: process.env.PRINT_URL ?? '',
|
||||
PRESENCE_URL: process.env.PRESENCE_URL ?? '',
|
||||
PUSH_PUBLIC_KEY: process.env.PUSH_PUBLIC_KEY ?? '',
|
||||
POSTHOG_API_KEY: process.env.POSTHOG_API_KEY,
|
||||
POSTHOG_HOST: process.env.POSTHOG_HOST,
|
||||
|
||||
@@ -510,6 +510,21 @@
|
||||
"projectFolder": "models/uploader",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/presence",
|
||||
"projectFolder": "plugins/presence",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/presence-resources",
|
||||
"projectFolder": "plugins/presence-resources",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/model-presence",
|
||||
"projectFolder": "models/presence",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/collaborator-client",
|
||||
"projectFolder": "packages/collaborator-client",
|
||||
|
||||
Reference in New Issue
Block a user