diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 01f83432fb..9fa0051bfd 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -18563,6 +18563,9 @@ importers: '@hcengineering/core': specifier: workspace:^0.7.26 version: link:../../foundations/core/packages/core + '@hcengineering/emoji-resources': + specifier: workspace:^0.7.0 + version: link:../emoji-resources '@hcengineering/image-cropper': specifier: workspace:^0.7.0 version: link:../image-cropper diff --git a/foundations/core/packages/core/src/classes.ts b/foundations/core/packages/core/src/classes.ts index d780f9cc53..dc242de928 100644 --- a/foundations/core/packages/core/src/classes.ts +++ b/foundations/core/packages/core/src/classes.ts @@ -593,7 +593,7 @@ export interface ModulePermissionGroup extends Doc { role: AccountRole permissions: Ref[] disabledPermissions?: Ref[] - spaceClass: Ref> + spaceClass?: Ref> enabled: boolean order?: number } diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index 6d7231b9dc..3a70e8692c 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -76,7 +76,7 @@ export function createModel (builder: Builder): void { application: chunter.app.Chunter, role: AccountRole.Guest, permissions: [], - spaceClass: chunter.class.ChunterSpace, + spaceClass: chunter.class.Channel, enabled: true, order: 30 }, @@ -90,7 +90,7 @@ export function createModel (builder: Builder): void { application: chunter.app.Chunter, role: AccountRole.ReadOnlyGuest, permissions: [], - spaceClass: chunter.class.ChunterSpace, + spaceClass: chunter.class.Channel, enabled: true, order: 15 }, diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index a029118299..d590f7012c 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -34,7 +34,8 @@ import { type SocialIdentity, type Status, type SocialIdentityProvider, - type Translation + type Translation, + type WorkspaceMemberStatus } from '@hcengineering/contact' import { AccountRole, @@ -52,6 +53,7 @@ import { type PersonId, type PersonUuid, type Ref, + type Space, type Timestamp } from '@hcengineering/core' import { createSystemType } from '@hcengineering/model-card' @@ -72,6 +74,7 @@ import { TypeRef, TypeString, TypeTimestamp, + TypeAccountUuid, UX, type Builder } from '@hcengineering/model' @@ -301,6 +304,24 @@ export class TTranslation extends TPreference implements Translation { dontTranslate!: string[] } +@Model(contact.class.WorkspaceMemberStatus, core.class.Doc, DOMAIN_CONTACT) +@UX(contact.string.WorkspaceStatusNote, contact.icon.User) +export class TWorkspaceMemberStatus extends TDoc implements WorkspaceMemberStatus { + @Prop(TypeRef(core.class.Space), core.string.Space) + @Index(IndexKind.Indexed) + declare space: Ref + + @Prop(TypeAccountUuid(), core.string.Members) + @Index(IndexKind.Indexed) + user!: AccountUuid + + @Prop(TypeString(), core.string.Description) + message!: string + + @Prop(TypeTimestamp(), contact.string.StatusDueDate) + clearAt?: Timestamp +} + export function createModel (builder: Builder): void { builder.createModel( TAvatarProvider, @@ -317,13 +338,20 @@ export function createModel (builder: Builder): void { TContactsTab, TPersonSpace, TUserRole, - TTranslation + TTranslation, + TWorkspaceMemberStatus ) builder.mixin(contact.class.PersonSpace, core.class.Class, core.mixin.TxAccessLevel, { createAccessLevel: AccountRole.Guest }) + builder.mixin(contact.class.WorkspaceMemberStatus, core.class.Class, core.mixin.TxAccessLevel, { + createAccessLevel: AccountRole.Guest, + updateAccessLevel: AccountRole.Guest, + removeAccessLevel: AccountRole.Guest + }) + builder.mixin(contact.class.Person, core.class.Class, core.mixin.TxAccessLevel, { createAccessLevel: AccountRole.Guest, isIdentity: true @@ -1401,6 +1429,12 @@ export function createModel (builder: Builder): void { _class: 1, [contact.mixin.Employee + '.active']: 1 } + }, + { + keys: { + _class: 1, + user: 1 + } } ], disabled: [{ attachedToClass: 1 }, { modifiedBy: 1 }, { createdBy: 1 }, { createdOn: -1 }, { attachedTo: 1 }] diff --git a/models/controlled-documents/src/index.ts b/models/controlled-documents/src/index.ts index c60a24f062..973f13fc61 100644 --- a/models/controlled-documents/src/index.ts +++ b/models/controlled-documents/src/index.ts @@ -96,12 +96,19 @@ function defineRelationMetadata (builder: Builder): void { rel(documents.class.Document, 'category', documents.class.DocumentCategory, 'forward') rel(documents.class.Document, 'template', documents.class.Document, 'forward') - rel(documents.class.Document, 'meta', documents.class.ProjectMeta, 'inverse') rel(documents.class.Document, 'document', documents.class.ProjectDocument, 'inverse') rel(documents.class.HierarchyDocument, 'attachedTo', documents.class.DocumentMeta, 'forward') rel(documents.class.ControlledDocument, 'changeControl', documents.class.ChangeControl, 'forward') - rel(documents.class.ProjectMeta, 'meta', documents.class.ProjectMeta, 'inverse') - rel(documents.class.ProjectMeta, 'document', documents.class.ProjectDocument, 'inverse') + rel(documents.class.DocumentMeta, 'meta', documents.class.ProjectMeta, 'inverse') + rel(documents.class.Project, 'project', documents.class.ProjectMeta, 'inverse') + rel(documents.class.ProjectMeta, 'meta', documents.class.DocumentMeta, 'forward') + rel(documents.class.ProjectMeta, 'parent', documents.class.DocumentMeta, 'forward') + rel(documents.class.ProjectMeta, 'path', documents.class.DocumentMeta, 'forward') + rel(documents.class.ProjectMeta, 'project', documents.class.Project, 'forward') + rel(documents.class.ProjectDocument, 'project', documents.class.Project, 'forward') + rel(documents.class.ProjectDocument, 'initial', documents.class.Project, 'forward') + rel(documents.class.ProjectDocument, 'attachedTo', documents.class.ProjectMeta, 'forward') + rel(documents.class.ProjectDocument, 'document', documents.class.Document, 'forward') } export function createModel (builder: Builder): void { diff --git a/models/love/src/index.ts b/models/love/src/index.ts index 343c2aa218..760d8bc982 100644 --- a/models/love/src/index.ts +++ b/models/love/src/index.ts @@ -273,7 +273,6 @@ export function createModel (builder: Builder): void { application: love.app.Love, role: AccountRole.Guest, permissions: [], - spaceClass: love.class.Office, enabled: true, order: 50 }, @@ -287,7 +286,6 @@ export function createModel (builder: Builder): void { application: love.app.Love, role: AccountRole.ReadOnlyGuest, permissions: [], - spaceClass: love.class.Office, enabled: false, order: 50 }, diff --git a/models/time/src/index.ts b/models/time/src/index.ts index c8a0f4ec5c..4e64b04b08 100644 --- a/models/time/src/index.ts +++ b/models/time/src/index.ts @@ -220,7 +220,7 @@ export function createModel (builder: Builder): void { application: time.app.Me, role: AccountRole.Guest, permissions: [], - spaceClass: core.class.TypedSpace, + spaceClass: tracker.class.Project, enabled: true, order: 55 }, @@ -234,7 +234,7 @@ export function createModel (builder: Builder): void { application: time.app.Me, role: AccountRole.ReadOnlyGuest, permissions: [], - spaceClass: core.class.TypedSpace, + spaceClass: tracker.class.Project, enabled: false, order: 55 }, diff --git a/models/training/src/index.ts b/models/training/src/index.ts index 1b531e8506..449846c00f 100644 --- a/models/training/src/index.ts +++ b/models/training/src/index.ts @@ -917,7 +917,6 @@ function defineSettings (builder: Builder): void { application: training.app.Training, role: AccountRole.Guest, permissions: [training.ids.GuestTrainingAttemptClassPermission], - spaceClass: core.class.TypedSpace, enabled: true, order: 25 }, @@ -931,7 +930,6 @@ function defineSettings (builder: Builder): void { application: training.app.Training, role: AccountRole.ReadOnlyGuest, permissions: [], - spaceClass: core.class.TypedSpace, enabled: false, order: 25 }, diff --git a/plugins/calendar-resources/src/components/IntegrationConnect.svelte b/plugins/calendar-resources/src/components/IntegrationConnect.svelte index e457b56ef4..3d5b617661 100644 --- a/plugins/calendar-resources/src/components/IntegrationConnect.svelte +++ b/plugins/calendar-resources/src/components/IntegrationConnect.svelte @@ -80,9 +80,9 @@ - + + @@ -91,9 +91,12 @@ position: relative; display: flex; flex-direction: column; - width: 40rem; - min-width: 40rem; - max-width: 40rem; + width: min(40rem, calc(100vw - 2rem)); + min-width: 0; + max-width: min(40rem, calc(100vw - 2rem)); + max-height: calc(100vh - 2rem); + max-height: calc(100dvh - 2rem); + overflow: hidden; background-color: var(--popup-bg-hover); border-radius: 0.75rem; box-shadow: var(--popup-shadow); @@ -114,10 +117,14 @@ } .content { - flex-shrink: 0; - flex-grow: 1; + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; color: var(--theme-content-color); - margin: 0 1.75rem 0.5rem; + margin: 0 1.75rem; + padding-bottom: 0.5rem; } .image { @@ -127,11 +134,14 @@ } .footer { + flex-shrink: 0; display: flex; flex-direction: row-reverse; justify-content: space-between; align-items: center; - padding: 1rem 0; + padding: 1rem 1.75rem 1.25rem; + margin-top: auto; + background-color: var(--popup-bg-hover); } } diff --git a/plugins/client-resources/src/connection.ts b/plugins/client-resources/src/connection.ts index 2cf53ca2b8..51a96301f1 100644 --- a/plugins/client-resources/src/connection.ts +++ b/plugins/client-resources/src/connection.ts @@ -777,7 +777,7 @@ class Connection implements ClientConnection { params: [_class, query, options], measure: (time, result, serverTime, queue, toReceive) => { if (typeof window !== 'undefined' && (time > 1000 || serverTime > 500)) { - console.error( + console.warn( 'measure slow findAll', time, serverTime, diff --git a/plugins/contact-assets/lang/cs.json b/plugins/contact-assets/lang/cs.json index b3a47e6c42..9c821d9480 100644 --- a/plugins/contact-assets/lang/cs.json +++ b/plugins/contact-assets/lang/cs.json @@ -111,6 +111,10 @@ "ViewProfile": "Zobrazit profil", "Viber": "Viber", "ViberPlaceholder": "Viber", + "SocialId": "Sociální ID", + "SocialIds": "Sociální ID", + "Type": "Typ", + "Confirmed": "Potvrzeno", "UserProfile": "Uživatelský profil", "DeactivatedAccount": "Deaktivovaný účet", "LocalTime": "místní čas", @@ -125,6 +129,26 @@ "TranslateTo": "Přeložit do", "DontTranslate": "Nepřekládat", "SelectLanguage": "Vyberte jazyk", - "SelectLanguages": "Vyberte jazyky" + "SelectLanguages": "Vyberte jazyky", + "WorkspaceStatusNote": "Stav uživatele", + "WorkspaceStatusUntil": "Zobrazit do", + "WorkspaceStatusMenu": "Váš stav", + "WorkspaceStatusSetYour": "Nastavte svůj stav", + "WorkspaceStatusUpdateYour": "Aktualizujte svůj stav", + "WorkspaceStatusMessage": "Jaký je váš stav?", + "WorkspaceStatusAway": "Pryč", + "WorkspaceStatusVacation": "Na dovolené", + "WorkspaceStatusOutSick": "Nemoc", + "WorkspaceStatusClear": "Vymazat stav", + "WorkspaceStatusSave": "Uložit", + "WorkspaceStatusQuickPick": "Rychlé stavy", + "WorkspaceStatusComposeHint": "Krátká poznámka (volitelné)", + "WorkspaceStatusClearUntil": "Vymazat datum", + "WorkspaceStatusDoNotClear": "Stav automaticky nečistit", + "WorkspaceStatusIn30Min": "Za 30 minut", + "WorkspaceStatusIn1Hour": "Za 1 hodinu", + "WorkspaceStatusIn4Hours": "Za 4 hodiny", + "WorkspaceStatusEndOfDay": "Do konce dne", + "WorkspaceStatusPickDate": "Vyberte datum" } } diff --git a/plugins/contact-assets/lang/de.json b/plugins/contact-assets/lang/de.json index 9d58954a88..eaf64bfafe 100644 --- a/plugins/contact-assets/lang/de.json +++ b/plugins/contact-assets/lang/de.json @@ -111,6 +111,10 @@ "ViewProfile": "Profil anzeigen", "Viber": "Viber", "ViberPlaceholder": "Viber", + "SocialId": "Social-ID", + "SocialIds": "Social-IDs", + "Type": "Typ", + "Confirmed": "Bestätigt", "UserProfile": "Benutzerprofil", "DeactivatedAccount": "Deaktivierter Account", "LocalTime": "Ortszeit", @@ -125,6 +129,26 @@ "TranslateTo": "Übersetzen in", "DontTranslate": "Nicht übersetzen", "SelectLanguage": "Sprache auswählen", - "SelectLanguages": "Sprachen auswählen" + "SelectLanguages": "Sprachen auswählen", + "WorkspaceStatusNote": "Benutzerstatus", + "WorkspaceStatusUntil": "Anzeigen bis", + "WorkspaceStatusMenu": "Ihr Status", + "WorkspaceStatusSetYour": "Status festlegen", + "WorkspaceStatusUpdateYour": "Status aktualisieren", + "WorkspaceStatusMessage": "Wie lautet Ihr Status?", + "WorkspaceStatusAway": "Abwesend", + "WorkspaceStatusVacation": "Im Urlaub", + "WorkspaceStatusOutSick": "Krank", + "WorkspaceStatusClear": "Status löschen", + "WorkspaceStatusSave": "Speichern", + "WorkspaceStatusQuickPick": "Schnellauswahl", + "WorkspaceStatusComposeHint": "Kurze Notiz hinzufügen (optional)", + "WorkspaceStatusClearUntil": "Datum löschen", + "WorkspaceStatusDoNotClear": "Status nicht automatisch löschen", + "WorkspaceStatusIn30Min": "In 30 Minuten", + "WorkspaceStatusIn1Hour": "In 1 Stunde", + "WorkspaceStatusIn4Hours": "In 4 Stunden", + "WorkspaceStatusEndOfDay": "Ende des Tages", + "WorkspaceStatusPickDate": "Datum wählen" } } diff --git a/plugins/contact-assets/lang/en.json b/plugins/contact-assets/lang/en.json index a3fef6df7c..315baf7a16 100644 --- a/plugins/contact-assets/lang/en.json +++ b/plugins/contact-assets/lang/en.json @@ -129,6 +129,26 @@ "TranslateTo": "Translate to", "DontTranslate": "Don't translate", "SelectLanguage": "Select language", - "SelectLanguages": "Select languages" + "SelectLanguages": "Select languages", + "WorkspaceStatusNote": "User status", + "WorkspaceStatusUntil": "Show until", + "WorkspaceStatusMenu": "Your status", + "WorkspaceStatusSetYour": "Set your status", + "WorkspaceStatusUpdateYour": "Update your status", + "WorkspaceStatusMessage": "What is your status?", + "WorkspaceStatusAway": "Away", + "WorkspaceStatusVacation": "On vacation", + "WorkspaceStatusOutSick": "Out sick", + "WorkspaceStatusClear": "Clear status", + "WorkspaceStatusSave": "Save", + "WorkspaceStatusQuickPick": "Quick statuses", + "WorkspaceStatusComposeHint": "Add a short note (optional)", + "WorkspaceStatusClearUntil": "Clear date", + "WorkspaceStatusDoNotClear": "Do not clear status", + "WorkspaceStatusIn30Min": "In 30 minutes", + "WorkspaceStatusIn1Hour": "In 1 hour", + "WorkspaceStatusIn4Hours": "In 4 hours", + "WorkspaceStatusEndOfDay": "End of day", + "WorkspaceStatusPickDate": "Choose date" } } diff --git a/plugins/contact-assets/lang/es.json b/plugins/contact-assets/lang/es.json index c1246161db..a1a6837567 100644 --- a/plugins/contact-assets/lang/es.json +++ b/plugins/contact-assets/lang/es.json @@ -129,6 +129,26 @@ "TranslateTo": "Traducir a", "DontTranslate": "No traducir", "SelectLanguage": "Seleccionar idioma", - "SelectLanguages": "Seleccionar idiomas" + "SelectLanguages": "Seleccionar idiomas", + "WorkspaceStatusNote": "Estado del usuario", + "WorkspaceStatusUntil": "Mostrar hasta", + "WorkspaceStatusMenu": "Tu estado", + "WorkspaceStatusSetYour": "Establecer tu estado", + "WorkspaceStatusUpdateYour": "Actualizar tu estado", + "WorkspaceStatusMessage": "¿Cuál es tu estado?", + "WorkspaceStatusAway": "Ausente", + "WorkspaceStatusVacation": "De vacaciones", + "WorkspaceStatusOutSick": "De baja por enfermedad", + "WorkspaceStatusClear": "Borrar estado", + "WorkspaceStatusSave": "Guardar", + "WorkspaceStatusQuickPick": "Estados rápidos", + "WorkspaceStatusComposeHint": "Añade una nota breve (opcional)", + "WorkspaceStatusClearUntil": "Borrar fecha", + "WorkspaceStatusDoNotClear": "No borrar el estado automáticamente", + "WorkspaceStatusIn30Min": "En 30 minutos", + "WorkspaceStatusIn1Hour": "En 1 hora", + "WorkspaceStatusIn4Hours": "En 4 horas", + "WorkspaceStatusEndOfDay": "Fin del día", + "WorkspaceStatusPickDate": "Elegir fecha" } } diff --git a/plugins/contact-assets/lang/fr.json b/plugins/contact-assets/lang/fr.json index 8e17e7b97f..8401064a71 100644 --- a/plugins/contact-assets/lang/fr.json +++ b/plugins/contact-assets/lang/fr.json @@ -129,6 +129,26 @@ "TranslateTo": "Traduire en", "DontTranslate": "Ne pas traduire", "SelectLanguage": "Sélectionner la langue", - "SelectLanguages": "Sélectionner les langues" + "SelectLanguages": "Sélectionner les langues", + "WorkspaceStatusNote": "Statut utilisateur", + "WorkspaceStatusUntil": "Afficher jusqu’au", + "WorkspaceStatusMenu": "Votre statut", + "WorkspaceStatusSetYour": "Définir votre statut", + "WorkspaceStatusUpdateYour": "Mettre à jour votre statut", + "WorkspaceStatusMessage": "Quel est votre statut ?", + "WorkspaceStatusAway": "Absent", + "WorkspaceStatusVacation": "En congé", + "WorkspaceStatusOutSick": "Malade", + "WorkspaceStatusClear": "Effacer le statut", + "WorkspaceStatusSave": "Enregistrer", + "WorkspaceStatusQuickPick": "Statuts rapides", + "WorkspaceStatusComposeHint": "Ajouter une courte note (facultatif)", + "WorkspaceStatusClearUntil": "Effacer la date", + "WorkspaceStatusDoNotClear": "Ne pas effacer le statut automatiquement", + "WorkspaceStatusIn30Min": "Dans 30 minutes", + "WorkspaceStatusIn1Hour": "Dans 1 heure", + "WorkspaceStatusIn4Hours": "Dans 4 heures", + "WorkspaceStatusEndOfDay": "Fin de journée", + "WorkspaceStatusPickDate": "Choisir une date" } } diff --git a/plugins/contact-assets/lang/it.json b/plugins/contact-assets/lang/it.json index 0a688aea02..3f853c6e30 100644 --- a/plugins/contact-assets/lang/it.json +++ b/plugins/contact-assets/lang/it.json @@ -129,6 +129,26 @@ "TranslateTo": "Traduci in", "DontTranslate": "Non tradurre", "SelectLanguage": "Seleziona lingua", - "SelectLanguages": "Seleziona lingue" + "SelectLanguages": "Seleziona lingue", + "WorkspaceStatusNote": "Stato utente", + "WorkspaceStatusUntil": "Mostra fino al", + "WorkspaceStatusMenu": "Il tuo stato", + "WorkspaceStatusSetYour": "Imposta il tuo stato", + "WorkspaceStatusUpdateYour": "Aggiorna il tuo stato", + "WorkspaceStatusMessage": "Qual è il tuo stato?", + "WorkspaceStatusAway": "Assente", + "WorkspaceStatusVacation": "In ferie", + "WorkspaceStatusOutSick": "Malato", + "WorkspaceStatusClear": "Cancella stato", + "WorkspaceStatusSave": "Salva", + "WorkspaceStatusQuickPick": "Stati rapidi", + "WorkspaceStatusComposeHint": "Aggiungi una breve nota (facoltativo)", + "WorkspaceStatusClearUntil": "Cancella data", + "WorkspaceStatusDoNotClear": "Non cancellare lo stato automaticamente", + "WorkspaceStatusIn30Min": "Tra 30 minuti", + "WorkspaceStatusIn1Hour": "Tra 1 ora", + "WorkspaceStatusIn4Hours": "Tra 4 ore", + "WorkspaceStatusEndOfDay": "Fine giornata", + "WorkspaceStatusPickDate": "Scegli data" } } diff --git a/plugins/contact-assets/lang/ja.json b/plugins/contact-assets/lang/ja.json index 27f8725792..82575cdba0 100644 --- a/plugins/contact-assets/lang/ja.json +++ b/plugins/contact-assets/lang/ja.json @@ -129,6 +129,26 @@ "TranslateTo": "翻訳先", "DontTranslate": "翻訳しない", "SelectLanguage": "言語を選択", - "SelectLanguages": "言語を選択" + "SelectLanguages": "言語を選択", + "WorkspaceStatusNote": "ユーザーステータス", + "WorkspaceStatusUntil": "表示期限", + "WorkspaceStatusMenu": "あなたのステータス", + "WorkspaceStatusSetYour": "ステータスを設定", + "WorkspaceStatusUpdateYour": "ステータスを更新", + "WorkspaceStatusMessage": "ステータスは何ですか?", + "WorkspaceStatusAway": "離席中", + "WorkspaceStatusVacation": "休暇中", + "WorkspaceStatusOutSick": "病欠", + "WorkspaceStatusClear": "ステータスをクリア", + "WorkspaceStatusSave": "保存", + "WorkspaceStatusQuickPick": "クイックステータス", + "WorkspaceStatusComposeHint": "短いメモを追加(任意)", + "WorkspaceStatusClearUntil": "日付をクリア", + "WorkspaceStatusDoNotClear": "ステータスを自動ではクリアしない", + "WorkspaceStatusIn30Min": "30分後", + "WorkspaceStatusIn1Hour": "1時間後", + "WorkspaceStatusIn4Hours": "4時間後", + "WorkspaceStatusEndOfDay": "今日の終わりまで", + "WorkspaceStatusPickDate": "日付を選択" } } diff --git a/plugins/contact-assets/lang/pt-br.json b/plugins/contact-assets/lang/pt-br.json index 5500dac95a..f9624fb6c5 100644 --- a/plugins/contact-assets/lang/pt-br.json +++ b/plugins/contact-assets/lang/pt-br.json @@ -129,6 +129,26 @@ "TranslateTo": "Traduzir para", "DontTranslate": "Não traduzir", "SelectLanguage": "Selecionar idioma", - "SelectLanguages": "Selecionar idiomas" + "SelectLanguages": "Selecionar idiomas", + "WorkspaceStatusNote": "Status do usuário", + "WorkspaceStatusUntil": "Mostrar até", + "WorkspaceStatusMenu": "Seu status", + "WorkspaceStatusSetYour": "Definir seu status", + "WorkspaceStatusUpdateYour": "Atualizar seu status", + "WorkspaceStatusMessage": "Qual é o seu status?", + "WorkspaceStatusAway": "Ausente", + "WorkspaceStatusVacation": "De férias", + "WorkspaceStatusOutSick": "Afastado por saúde", + "WorkspaceStatusClear": "Limpar status", + "WorkspaceStatusSave": "Salvar", + "WorkspaceStatusQuickPick": "Status rápidos", + "WorkspaceStatusComposeHint": "Adicione uma nota curta (opcional)", + "WorkspaceStatusClearUntil": "Limpar data", + "WorkspaceStatusDoNotClear": "Não limpar o status automaticamente", + "WorkspaceStatusIn30Min": "Em 30 minutos", + "WorkspaceStatusIn1Hour": "Em 1 hora", + "WorkspaceStatusIn4Hours": "Em 4 horas", + "WorkspaceStatusEndOfDay": "Fim do dia", + "WorkspaceStatusPickDate": "Escolher data" } } diff --git a/plugins/contact-assets/lang/pt.json b/plugins/contact-assets/lang/pt.json index d2e55eb879..759d6f10c2 100644 --- a/plugins/contact-assets/lang/pt.json +++ b/plugins/contact-assets/lang/pt.json @@ -129,6 +129,26 @@ "TranslateTo": "Traduzir para", "DontTranslate": "Não traduzir", "SelectLanguage": "Selecionar idioma", - "SelectLanguages": "Selecionar idiomas" + "SelectLanguages": "Selecionar idiomas", + "WorkspaceStatusNote": "Estado do utilizador", + "WorkspaceStatusUntil": "Mostrar até", + "WorkspaceStatusMenu": "O seu estado", + "WorkspaceStatusSetYour": "Definir o seu estado", + "WorkspaceStatusUpdateYour": "Atualizar o seu estado", + "WorkspaceStatusMessage": "Qual é o seu estado?", + "WorkspaceStatusAway": "Ausente", + "WorkspaceStatusVacation": "De férias", + "WorkspaceStatusOutSick": "Baixa por doença", + "WorkspaceStatusClear": "Limpar estado", + "WorkspaceStatusSave": "Guardar", + "WorkspaceStatusQuickPick": "Estados rápidos", + "WorkspaceStatusComposeHint": "Adicionar uma nota breve (opcional)", + "WorkspaceStatusClearUntil": "Limpar data", + "WorkspaceStatusDoNotClear": "Não limpar o estado automaticamente", + "WorkspaceStatusIn30Min": "Em 30 minutos", + "WorkspaceStatusIn1Hour": "Em 1 hora", + "WorkspaceStatusIn4Hours": "Em 4 horas", + "WorkspaceStatusEndOfDay": "Fim do dia", + "WorkspaceStatusPickDate": "Escolher data" } } diff --git a/plugins/contact-assets/lang/ru.json b/plugins/contact-assets/lang/ru.json index cec1b52da1..e98bbc5892 100644 --- a/plugins/contact-assets/lang/ru.json +++ b/plugins/contact-assets/lang/ru.json @@ -129,6 +129,26 @@ "TranslateTo": "Переводить на", "DontTranslate": "Не переводить", "SelectLanguage": "Выберите язык", - "SelectLanguages": "Выберите языки" + "SelectLanguages": "Выберите языки", + "WorkspaceStatusNote": "Статус пользователя", + "WorkspaceStatusUntil": "Показывать до", + "WorkspaceStatusMenu": "Ваш статус", + "WorkspaceStatusSetYour": "Установить статус", + "WorkspaceStatusUpdateYour": "Обновить статус", + "WorkspaceStatusMessage": "Какой ваш статус?", + "WorkspaceStatusAway": "Отошёл", + "WorkspaceStatusVacation": "В отпуске", + "WorkspaceStatusOutSick": "На больничном", + "WorkspaceStatusClear": "Очистить статус", + "WorkspaceStatusSave": "Сохранить", + "WorkspaceStatusQuickPick": "Быстрые статусы", + "WorkspaceStatusComposeHint": "Краткая заметка (необязательно)", + "WorkspaceStatusClearUntil": "Сбросить дату", + "WorkspaceStatusDoNotClear": "Не сбрасывать статус автоматически", + "WorkspaceStatusIn30Min": "Через 30 минут", + "WorkspaceStatusIn1Hour": "Через 1 час", + "WorkspaceStatusIn4Hours": "Через 4 часа", + "WorkspaceStatusEndOfDay": "До конца дня", + "WorkspaceStatusPickDate": "Выбрать дату" } } diff --git a/plugins/contact-assets/lang/tr.json b/plugins/contact-assets/lang/tr.json index 424a04d6b5..efbea87cea 100644 --- a/plugins/contact-assets/lang/tr.json +++ b/plugins/contact-assets/lang/tr.json @@ -124,6 +124,31 @@ "HereDescription": "Bu {title} içindeki çevrimiçi üyeleri bilgilendir", "Guest": "Misafir", "Deleted": "Silindi", - "CannotMerge": "Hata: Global kişiler birleştirilemez" + "CannotMerge": "Hata: Global kişiler birleştirilemez", + "AutoTranslation": "Otomatik çeviri", + "TranslateTo": "Şuna çevir", + "DontTranslate": "Çevirme", + "SelectLanguage": "Dil seç", + "SelectLanguages": "Dilleri seç", + "WorkspaceStatusNote": "Kullanıcı durumu", + "WorkspaceStatusUntil": "Şu tarihe kadar göster", + "WorkspaceStatusMenu": "Durumunuz", + "WorkspaceStatusSetYour": "Durumunuzu ayarlayın", + "WorkspaceStatusUpdateYour": "Durumunuzu güncelleyin", + "WorkspaceStatusMessage": "Durumunuz nedir?", + "WorkspaceStatusAway": "Uzakta", + "WorkspaceStatusVacation": "Tatilde", + "WorkspaceStatusOutSick": "Hastalık izni", + "WorkspaceStatusClear": "Durumu temizle", + "WorkspaceStatusSave": "Kaydet", + "WorkspaceStatusQuickPick": "Hızlı durumlar", + "WorkspaceStatusComposeHint": "Kısa bir not ekleyin (isteğe bağlı)", + "WorkspaceStatusClearUntil": "Tarihi temizle", + "WorkspaceStatusDoNotClear": "Durumu otomatik temizleme", + "WorkspaceStatusIn30Min": "30 dakika içinde", + "WorkspaceStatusIn1Hour": "1 saat içinde", + "WorkspaceStatusIn4Hours": "4 saat içinde", + "WorkspaceStatusEndOfDay": "Gün sonu", + "WorkspaceStatusPickDate": "Tarih seç" } } diff --git a/plugins/contact-assets/lang/zh.json b/plugins/contact-assets/lang/zh.json index 12132b87f0..663081fbcd 100644 --- a/plugins/contact-assets/lang/zh.json +++ b/plugins/contact-assets/lang/zh.json @@ -129,6 +129,26 @@ "TranslateTo": "翻译为", "DontTranslate": "不翻译", "SelectLanguage": "选择语言", - "SelectLanguages": "选择语言" + "SelectLanguages": "选择语言", + "WorkspaceStatusNote": "用户状态", + "WorkspaceStatusUntil": "显示截止日期", + "WorkspaceStatusMenu": "你的状态", + "WorkspaceStatusSetYour": "设置你的状态", + "WorkspaceStatusUpdateYour": "更新你的状态", + "WorkspaceStatusMessage": "你的状态是什么?", + "WorkspaceStatusAway": "离开", + "WorkspaceStatusVacation": "休假中", + "WorkspaceStatusOutSick": "病假", + "WorkspaceStatusClear": "清除状态", + "WorkspaceStatusSave": "保存", + "WorkspaceStatusQuickPick": "快捷状态", + "WorkspaceStatusComposeHint": "添加简短备注(可选)", + "WorkspaceStatusClearUntil": "清除日期", + "WorkspaceStatusDoNotClear": "不自动清除状态", + "WorkspaceStatusIn30Min": "30 分钟后", + "WorkspaceStatusIn1Hour": "1 小时后", + "WorkspaceStatusIn4Hours": "4 小时后", + "WorkspaceStatusEndOfDay": "今天结束", + "WorkspaceStatusPickDate": "选择日期" } } diff --git a/plugins/contact-resources/package.json b/plugins/contact-resources/package.json index a90f68c3f6..898119415a 100644 --- a/plugins/contact-resources/package.json +++ b/plugins/contact-resources/package.json @@ -45,6 +45,7 @@ "@hcengineering/attachment-resources": "workspace:^0.7.0", "@hcengineering/contact": "workspace:^0.7.0", "@hcengineering/core": "workspace:^0.7.26", + "@hcengineering/emoji-resources": "workspace:^0.7.0", "@hcengineering/image-cropper": "workspace:^0.7.0", "@hcengineering/login": "workspace:^0.7.0", "@hcengineering/notification": "workspace:^0.7.0", diff --git a/plugins/contact-resources/src/components/EmployeePresenter.svelte b/plugins/contact-resources/src/components/EmployeePresenter.svelte index b3d5f10c36..701eb30e8f 100644 --- a/plugins/contact-resources/src/components/EmployeePresenter.svelte +++ b/plugins/contact-resources/src/components/EmployeePresenter.svelte @@ -1,10 +1,17 @@ - +
+ + {#if showWorkspaceStatusEmoji && shouldShowName && statusEmoji !== undefined && isWorkspaceMemberStatusVisible(statusDoc)} + + {statusEmoji} + + {/if} +
+ + diff --git a/plugins/contact-resources/src/components/WorkspaceMemberStatusEditor.svelte b/plugins/contact-resources/src/components/WorkspaceMemberStatusEditor.svelte new file mode 100644 index 0000000000..538e10fda6 --- /dev/null +++ b/plugins/contact-resources/src/components/WorkspaceMemberStatusEditor.svelte @@ -0,0 +1,545 @@ + + + +
+
+
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+ {#each presets as item} + + {/each} +
+ +
+
+
+ +
+ {#if clearAt !== undefined && clearMode === 'pickDate'} +
+
+ +
+ {#key clearAt} + + {/key} +
+ {/if} +
+ + +
+ + + diff --git a/plugins/contact-resources/src/components/person/EmployeePreviewPopup.svelte b/plugins/contact-resources/src/components/person/EmployeePreviewPopup.svelte index 3d510f157f..c35eb6f5d6 100644 --- a/plugins/contact-resources/src/components/person/EmployeePreviewPopup.svelte +++ b/plugins/contact-resources/src/components/person/EmployeePreviewPopup.svelte @@ -13,7 +13,7 @@ // limitations under the License. --> @@ -108,8 +114,21 @@ on:click={viewProfile} />
-
- + {#if statusSubtitle} +
+
+ {statusSubtitle} +
+
+ {/if} + {#if hasRating}
diff --git a/plugins/contact-resources/src/index.ts b/plugins/contact-resources/src/index.ts index 27a2116cf3..315b454710 100644 --- a/plugins/contact-resources/src/index.ts +++ b/plugins/contact-resources/src/index.ts @@ -110,6 +110,7 @@ import SelectAvatars from './components/SelectAvatars.svelte' import SelectUsersPopup from './components/SelectUsersPopup.svelte' import SocialEditor from './components/SocialEditor.svelte' import SpaceMembers from './components/SpaceMembers.svelte' +import WorkspaceMemberStatusEditor from './components/WorkspaceMemberStatusEditor.svelte' import SpaceMembersEditor from './components/SpaceMembersEditor.svelte' import SystemAvatar from './components/SystemAvatar.svelte' import UserBox from './components/UserBox.svelte' @@ -155,6 +156,7 @@ import { } from './utils' export * from './utils' +export * from './workspaceMemberStatus' export { employeeByIdStore } from './utils' export * from './assignee' export * from './translation' @@ -199,6 +201,7 @@ export { SelectAvatars, SelectUsersPopup, SpaceMembers, + WorkspaceMemberStatusEditor, SystemAvatar, UserBox, UserBoxItems, @@ -403,7 +406,8 @@ export default async (): Promise => ({ PersonIdFilter, AssigneePopup, TranslationSettings, - SocialIdentityPresenter + SocialIdentityPresenter, + WorkspaceMemberStatusEditor }, completion: { EmployeeQuery: async ( diff --git a/plugins/contact-resources/src/plugin.ts b/plugins/contact-resources/src/plugin.ts index 5319090a13..f2f6bfc5e3 100644 --- a/plugins/contact-resources/src/plugin.ts +++ b/plugins/contact-resources/src/plugin.ts @@ -90,7 +90,26 @@ export default mergeIds(contactId, contact, { TranslateTo: '' as IntlString, DontTranslate: '' as IntlString, SelectLanguage: '' as IntlString, - SelectLanguages: '' as IntlString + SelectLanguages: '' as IntlString, + WorkspaceStatusUntil: '' as IntlString, + WorkspaceStatusMenu: '' as IntlString, + WorkspaceStatusMessage: '' as IntlString, + WorkspaceStatusSetYour: '' as IntlString, + WorkspaceStatusUpdateYour: '' as IntlString, + WorkspaceStatusAway: '' as IntlString, + WorkspaceStatusVacation: '' as IntlString, + WorkspaceStatusOutSick: '' as IntlString, + WorkspaceStatusClear: '' as IntlString, + WorkspaceStatusSave: '' as IntlString, + WorkspaceStatusQuickPick: '' as IntlString, + WorkspaceStatusComposeHint: '' as IntlString, + WorkspaceStatusClearUntil: '' as IntlString, + WorkspaceStatusDoNotClear: '' as IntlString, + WorkspaceStatusIn30Min: '' as IntlString, + WorkspaceStatusIn1Hour: '' as IntlString, + WorkspaceStatusIn4Hours: '' as IntlString, + WorkspaceStatusEndOfDay: '' as IntlString, + WorkspaceStatusPickDate: '' as IntlString }, function: { GetContactLink: '' as Resource<(doc: Doc, props: Record) => Promise>, diff --git a/plugins/contact-resources/src/utils.ts b/plugins/contact-resources/src/utils.ts index 164757d75c..cb0eac7232 100644 --- a/plugins/contact-resources/src/utils.ts +++ b/plugins/contact-resources/src/utils.ts @@ -14,6 +14,8 @@ // limitations under the License. // +import { loadWorkspaceMemberStatuses } from './workspaceMemberStatus' + import { type AccountClient, getClient as getAccountClientRaw } from '@hcengineering/account-client' import { addEmployeeListenrer, @@ -411,6 +413,8 @@ onClient(() => { channelProviders.set(res) }) + loadWorkspaceMemberStatuses() + employeesQuery.query( contact.mixin.Employee, {}, diff --git a/plugins/contact-resources/src/workspaceMemberStatus.ts b/plugins/contact-resources/src/workspaceMemberStatus.ts new file mode 100644 index 0000000000..cc075834e6 --- /dev/null +++ b/plugins/contact-resources/src/workspaceMemberStatus.ts @@ -0,0 +1,33 @@ +// +// Copyright © 2026 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 contact, { type WorkspaceMemberStatus } from '@hcengineering/contact' +import type { AccountUuid } from '@hcengineering/core' +import { writable } from 'svelte/store' + +import { createQuery } from '@hcengineering/presentation' + +export const workspaceMemberStatusByAccountStore = writable>(new Map()) + +const workspaceMemberStatusQuery = createQuery(true) +let workspaceStatusesLoaded = false + +export function loadWorkspaceMemberStatuses (): void { + if (workspaceStatusesLoaded) return + workspaceStatusesLoaded = true + workspaceMemberStatusQuery.query(contact.class.WorkspaceMemberStatus, {}, (res) => { + workspaceMemberStatusByAccountStore.set(new Map(res.map((it) => [it.user, it]))) + }) +} diff --git a/plugins/contact/src/__tests__/workspaceMemberStatusUtils.test.ts b/plugins/contact/src/__tests__/workspaceMemberStatusUtils.test.ts new file mode 100644 index 0000000000..84e8d34fbf --- /dev/null +++ b/plugins/contact/src/__tests__/workspaceMemberStatusUtils.test.ts @@ -0,0 +1,47 @@ +import { + WORKSPACE_MEMBER_STATUS_MESSAGE_MAX, + extractLeadingStatusEmoji, + getWorkspaceMemberStatusSubtitle, + isWorkspaceMemberStatusVisible, + trimWorkspaceMemberStatusMessage +} from '../workspaceMemberStatusUtils' + +describe('workspaceMemberStatusUtils', () => { + it('trimWorkspaceMemberStatusMessage enforces max length', () => { + const long = 'x'.repeat(WORKSPACE_MEMBER_STATUS_MESSAGE_MAX + 50) + expect(trimWorkspaceMemberStatusMessage(long).length).toBe(WORKSPACE_MEMBER_STATUS_MESSAGE_MAX) + expect(trimWorkspaceMemberStatusMessage(' hi ')).toBe('hi') + }) + + it('trimWorkspaceMemberStatusMessage keeps emoji intact at boundary', () => { + const max = WORKSPACE_MEMBER_STATUS_MESSAGE_MAX + const input = 'a'.repeat(max - 1) + '😀' + 'z' + const out = trimWorkspaceMemberStatusMessage(input) + expect(Array.from(out).length).toBe(max) + expect(out.endsWith('😀')).toBe(true) + }) + + it('isWorkspaceMemberStatusVisible respects clearAt and empty message', () => { + const now = 1_000_000 + expect(isWorkspaceMemberStatusVisible(undefined, now)).toBe(false) + expect(isWorkspaceMemberStatusVisible({ message: '', clearAt: now - 1 }, now)).toBe(false) + expect(isWorkspaceMemberStatusVisible({ message: '' }, now)).toBe(false) + expect(isWorkspaceMemberStatusVisible({ message: 'Hi' }, now)).toBe(true) + expect(isWorkspaceMemberStatusVisible({ message: '🏖️' }, now)).toBe(true) + }) + + it('getWorkspaceMemberStatusSubtitle returns trimmed message when visible', () => { + const now = 10_000_000 + expect(getWorkspaceMemberStatusSubtitle({ message: '🏖️ Beach', clearAt: now + 1000 }, now)).toBe('🏖️ Beach') + expect(getWorkspaceMemberStatusSubtitle({ message: 'Only text' }, now)).toBe('Only text') + expect(getWorkspaceMemberStatusSubtitle({ message: '' }, now)).toBe(undefined) + }) + + it('extractLeadingStatusEmoji takes first emoji sequence', () => { + expect(extractLeadingStatusEmoji('🏖️ Holiday')).toBe('🏖️') + expect(extractLeadingStatusEmoji('⏳ In a meeting')).toBe('⏳') + expect(extractLeadingStatusEmoji('No emoji')).toBe(undefined) + expect(extractLeadingStatusEmoji('')).toBe(undefined) + expect(extractLeadingStatusEmoji('👋')).toBe('👋') + }) +}) diff --git a/plugins/contact/src/index.ts b/plugins/contact/src/index.ts index ca103a8b81..17deee76fa 100644 --- a/plugins/contact/src/index.ts +++ b/plugins/contact/src/index.ts @@ -217,6 +217,17 @@ export interface Translation extends Preference { dontTranslate: string[] } +/** + * Persistent user status in workspace (e.g. vacation, short note). + * @public + */ +export interface WorkspaceMemberStatus extends Doc { + space: Ref + user: AccountUuid + message: string + clearAt?: Timestamp +} + /** * @public */ @@ -236,7 +247,8 @@ export const contactPlugin = plugin(contactId, { SocialIdentity: '' as Ref>, UserProfile: '' as Ref, UserRole: '' as Ref>, - Translation: '' as Ref> + Translation: '' as Ref>, + WorkspaceMemberStatus: '' as Ref> }, mixin: { Employee: '' as Ref> @@ -264,7 +276,8 @@ export const contactPlugin = plugin(contactId, { PersonFilterValuePresenter: '' as AnyComponent, PersonIdFilter: '' as AnyComponent, AssigneePopup: '' as AnyComponent, - EmployeePresenter: '' as AnyComponent + EmployeePresenter: '' as AnyComponent, + WorkspaceMemberStatusEditor: '' as AnyComponent }, channelProvider: { Email: '' as Ref, @@ -378,7 +391,8 @@ export const contactPlugin = plugin(contactId, { HereDescription: '' as IntlString, Guest: '' as IntlString, Deleted: '' as IntlString, - Email: '' as IntlString + Email: '' as IntlString, + WorkspaceStatusNote: '' as IntlString }, viewlet: { TableMember: '' as Ref, @@ -429,3 +443,10 @@ export * from './types' export * from './utils' export * from './analytics' export * from './avatar' +export { + WORKSPACE_MEMBER_STATUS_MESSAGE_MAX, + trimWorkspaceMemberStatusMessage, + isWorkspaceMemberStatusVisible, + getWorkspaceMemberStatusSubtitle, + extractLeadingStatusEmoji +} from './workspaceMemberStatusUtils' diff --git a/plugins/contact/src/workspaceMemberStatusUtils.ts b/plugins/contact/src/workspaceMemberStatusUtils.ts new file mode 100644 index 0000000000..5547093330 --- /dev/null +++ b/plugins/contact/src/workspaceMemberStatusUtils.ts @@ -0,0 +1,94 @@ +// +// Copyright © 2026 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. +// + +/** @public */ +export const WORKSPACE_MEMBER_STATUS_MESSAGE_MAX = 200 + +/** + * Minimal shape for status helpers (see {@link WorkspaceMemberStatus}). + */ +interface WorkspaceMemberStatusLike { + message: string + clearAt?: number +} + +/** @public */ +export function trimWorkspaceMemberStatusMessage (message: string): string { + const trimmed = message.trim() + return Array.from(trimmed).slice(0, WORKSPACE_MEMBER_STATUS_MESSAGE_MAX).join('') +} + +/** @public */ +export function isWorkspaceMemberStatusVisible ( + s: WorkspaceMemberStatusLike | undefined, + now: number = Date.now() +): boolean { + if (s === undefined) return false + if (s.clearAt !== undefined && s.clearAt <= now) return false + const m = s.message?.trim() ?? '' + return m !== '' +} + +/** + * Plain-text line for member lists / tooltips (full stored message, including any leading emoji). + * @public + */ +export function getWorkspaceMemberStatusSubtitle ( + s: WorkspaceMemberStatusLike | undefined, + now: number = Date.now() +): string | undefined { + if (!isWorkspaceMemberStatusVisible(s, now)) return undefined + return s?.message?.trim() ?? '' +} + +const EMOJI_HEAD = /^\p{Extended_Pictographic}/u + +/** + * Returns the first emoji sequence at the start of the status message (after trim), or undefined. + * Handles variation selectors, skin tones, and ZWJ sequences (e.g. family emoji). + * @public + */ +export function extractLeadingStatusEmoji (raw: string | undefined): string | undefined { + const text = raw?.trim() ?? '' + if (text === '') return undefined + + try { + const seg = new Intl.Segmenter(undefined, { granularity: 'grapheme' }) + const segments = [...seg.segment(text)].map((x) => x.segment) + if (segments.length === 0) return undefined + if (!EMOJI_HEAD.test(segments[0])) return undefined + + let out = segments[0] + let i = 1 + while (i < segments.length) { + const s = segments[i] + if (s === '\u200D' && i + 1 < segments.length && EMOJI_HEAD.test(segments[i + 1])) { + out += s + segments[i + 1] + i += 2 + continue + } + if (s === '\uFE0F' || /^[\u{1F3FB}-\u{1F3FF}]$/u.test(s)) { + out += s + i++ + continue + } + break + } + return out + } catch { + const m = text.match(/^(\p{Extended_Pictographic})/u) + return m?.[1] + } +} diff --git a/plugins/export/src/types.ts b/plugins/export/src/types.ts index bd3acfb2ab..eb373d272a 100644 --- a/plugins/export/src/types.ts +++ b/plugins/export/src/types.ts @@ -66,6 +66,8 @@ export interface TransformConfig { } export interface RelationDefinition { + /** When set, this relation applies only to documents of this class (or its subclasses). */ + sourceClass?: Ref> field: string class: Ref> direction?: 'forward' | 'inverse' diff --git a/plugins/setting-assets/lang/cs.json b/plugins/setting-assets/lang/cs.json index 750a405a7b..14aba53801 100644 --- a/plugins/setting-assets/lang/cs.json +++ b/plugins/setting-assets/lang/cs.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Umožňuje anonymním uživatelům připojit se k vašemu pracovnímu prostoru jako hosté s omezenými editačními právy", "GuestChannelsDescription": "Kanály, kde hosté mohou psát zprávy po připojení", "GuestChannelsArrayLabel": "Vybrat kanály", + "GuestAutoJoinAvailableSpaces": "Dostupné prostory", + "GuestAutoJoinAvailableSpacesHint": "Každá karta aplikace má vlastní řádek „Dostupné prostory“ pro automatické připojení hostů; změny se projeví okamžitě.", "ManageIdentities": "Spravovat identity", "Release": "Uvolnění", "ReleaseSocialId": "Uvolnit sociální ID", diff --git a/plugins/setting-assets/lang/de.json b/plugins/setting-assets/lang/de.json index 8564840884..d44044976d 100644 --- a/plugins/setting-assets/lang/de.json +++ b/plugins/setting-assets/lang/de.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Ermöglicht anonymen Benutzern den Beitritt zu Ihrem Arbeitsbereich als Gäste mit eingeschränkten Bearbeitungsrechten", "GuestChannelsDescription": "Kanäle, in denen Gäste nach dem Beitritt Nachrichten schreiben können", "GuestChannelsArrayLabel": "Kanäle auswählen", + "GuestAutoJoinAvailableSpaces": "Verfügbare Bereiche", + "GuestAutoJoinAvailableSpacesHint": "Jede Anwendungskarte hat eine eigene Zeile „Verfügbare Bereiche“ für den automatischen Gästebeitritt; Änderungen gelten sofort.", "ManageIdentities": "Identitäten verwalten", "Release": "Freigeben", "ReleaseSocialId": "Social ID freigeben", diff --git a/plugins/setting-assets/lang/en.json b/plugins/setting-assets/lang/en.json index 3d5efb12b8..f867cf36b4 100644 --- a/plugins/setting-assets/lang/en.json +++ b/plugins/setting-assets/lang/en.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Allows anonymous users to join your workspace as guests with limited editing rights", "GuestChannelsDescription": "Channels where guests can write messages after joining", "GuestChannelsArrayLabel": "Select channels", + "GuestAutoJoinAvailableSpaces": "Available spaces", + "GuestAutoJoinAvailableSpacesHint": "Each application card has its own “Available spaces” row to pick where workspace guests are added on activation. Changes apply immediately.", "ManageIdentities": "Manage identities", "Release": "Release", "ReleaseSocialId": "Release social ID", diff --git a/plugins/setting-assets/lang/es.json b/plugins/setting-assets/lang/es.json index 12b8659bf6..a63b17d0eb 100644 --- a/plugins/setting-assets/lang/es.json +++ b/plugins/setting-assets/lang/es.json @@ -165,6 +165,8 @@ "GuestSignUpDescription": "Permite a usuarios anónimos unirse a su espacio de trabajo como invitados con derechos de edición limitados", "GuestChannelsDescription": "Canales donde los invitados pueden escribir mensajes después de unirse", "GuestChannelsArrayLabel": "Seleccionar canales", + "GuestAutoJoinAvailableSpaces": "Espacios disponibles", + "GuestAutoJoinAvailableSpacesHint": "Cada tarjeta de aplicación tiene su propia fila « Espacios disponibles » para la adhesión automática de invitados; los cambios son inmediatos.", "ManageIdentities": "Gestionar identidades", "Release": "Liberar", "ReleaseSocialId": "Liberar ID social", diff --git a/plugins/setting-assets/lang/fr.json b/plugins/setting-assets/lang/fr.json index 1abd0c8933..8305bd751e 100644 --- a/plugins/setting-assets/lang/fr.json +++ b/plugins/setting-assets/lang/fr.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Permet aux utilisateurs anonymes de rejoindre votre espace de travail en tant qu'invités avec des droits d'édition limités", "GuestChannelsDescription": "Canaux où les invités peuvent écrire des messages après leur adhésion", "GuestChannelsArrayLabel": "Sélectionner des canaux", + "GuestAutoJoinAvailableSpaces": "Espaces disponibles", + "GuestAutoJoinAvailableSpacesHint": "Chaque carte d’application a sa propre ligne « Espaces disponibles » pour l’adhésion automatique des invités ; les changements sont immédiats.", "ManageIdentities": "Gérer les identités", "Release": "Libération", "ReleaseSocialId": "Libérer l'ID social", diff --git a/plugins/setting-assets/lang/it.json b/plugins/setting-assets/lang/it.json index a221189882..a2f4e354c5 100644 --- a/plugins/setting-assets/lang/it.json +++ b/plugins/setting-assets/lang/it.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Consente agli utenti anonimi di unirsi al tuo spazio di lavoro come ospiti con diritti di modifica limitati", "GuestChannelsDescription": "Canali in cui gli ospiti possono scrivere messaggi dopo essersi uniti", "GuestChannelsArrayLabel": "Seleziona canali", + "GuestAutoJoinAvailableSpaces": "Spazi disponibili", + "GuestAutoJoinAvailableSpacesHint": "Ogni scheda applicazione ha la propria riga « Spazi disponibili » per l’ingresso automatico degli ospiti; le modifiche sono immediate.", "ManageIdentities": "Gestisci identità", "Release": "Rilascio", "ReleaseSocialId": "Rilascia ID social", diff --git a/plugins/setting-assets/lang/ja.json b/plugins/setting-assets/lang/ja.json index 6d09048146..2abcffd54e 100644 --- a/plugins/setting-assets/lang/ja.json +++ b/plugins/setting-assets/lang/ja.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "匿名ユーザーがゲストとしてワークスペースに参加し、制限された編集権限を得られるようにします", "GuestChannelsDescription": "参加後、ゲストがメッセージを書き込めるチャンネル", "GuestChannelsArrayLabel": "チャンネルを選択", + "GuestAutoJoinAvailableSpaces": "利用可能なスペース", + "GuestAutoJoinAvailableSpacesHint": "各アプリのカードにゲスト自動参加用の「利用可能なスペース」行があります。変更はすぐに反映されます。", "ManageIdentities": "IDを管理", "Release": "リリース", "ReleaseSocialId": "ソーシャルIDをリリース", diff --git a/plugins/setting-assets/lang/pt-br.json b/plugins/setting-assets/lang/pt-br.json index 3410f19f0a..8550ff3875 100644 --- a/plugins/setting-assets/lang/pt-br.json +++ b/plugins/setting-assets/lang/pt-br.json @@ -165,6 +165,8 @@ "GuestSignUpDescription": "Permite que usuários anônimos entrem em seu espaço de trabalho como convidados com direitos de edição limitados", "GuestChannelsDescription": "Canais onde convidados podem escrever mensagens após entrar", "GuestChannelsArrayLabel": "Selecionar canais", + "GuestAutoJoinAvailableSpaces": "Espaços disponíveis", + "GuestAutoJoinAvailableSpacesHint": "Cada cartão de app tem sua própria linha « Espaços disponíveis » para adesão automática de convidados; as alterações são aplicadas na hora.", "ManageIdentities": "Gerenciar identidades", "Release": "Liberação", "ReleaseSocialId": "Liberar ID social", diff --git a/plugins/setting-assets/lang/pt.json b/plugins/setting-assets/lang/pt.json index adfc22ba78..cd79967e81 100644 --- a/plugins/setting-assets/lang/pt.json +++ b/plugins/setting-assets/lang/pt.json @@ -165,6 +165,8 @@ "GuestSignUpDescription": "Permite que usuários anônimos entrem em seu espaço de trabalho como convidados com direitos de edição limitados", "GuestChannelsDescription": "Canais onde convidados podem escrever mensagens após ingressar", "GuestChannelsArrayLabel": "Selecionar canais", + "GuestAutoJoinAvailableSpaces": "Espaços disponíveis", + "GuestAutoJoinAvailableSpacesHint": "Cada cartão de aplicação tem a sua própria linha « Espaços disponíveis » para adesão automática de convidados; as alterações aplicam-se de imediato.", "ManageIdentities": "Gerenciar identidades", "Release": "Libertação", "ReleaseSocialId": "Liberar ID social", diff --git a/plugins/setting-assets/lang/ru.json b/plugins/setting-assets/lang/ru.json index fe29107b42..f1b902d2ca 100644 --- a/plugins/setting-assets/lang/ru.json +++ b/plugins/setting-assets/lang/ru.json @@ -179,6 +179,8 @@ "GuestSignUpDescription": "Позволяет анонимным пользователям присоединяться к вашему рабочему пространству в качестве гостей с ограниченными правами редактирования", "GuestChannelsDescription": "Каналы, в которых гости могут писать сообщения после присоединения", "GuestChannelsArrayLabel": "Выбрать каналы", + "GuestAutoJoinAvailableSpaces": "Доступные пространства", + "GuestAutoJoinAvailableSpacesHint": "У каждого приложения ниже своя строка «Доступные пространства»: выберите, куда при активации добавлять гостей воркспейса. Изменения применяются сразу.", "ManageIdentities": "Управление идентификаторами", "Release": "Освободить", "ReleaseSocialId": "Освободить социальный ID", diff --git a/plugins/setting-assets/lang/tr.json b/plugins/setting-assets/lang/tr.json index 1aa6cf55f1..a6823e1518 100644 --- a/plugins/setting-assets/lang/tr.json +++ b/plugins/setting-assets/lang/tr.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "Anonim kullanıcıların çalışma alanınıza sınırlı düzenleme haklarıyla misafir olarak katılmasına izin verir", "GuestChannelsDescription": "Misafirlerin katıldıktan sonra mesaj yazabileceği kanallar", "GuestChannelsArrayLabel": "Kanalları seç", + "GuestAutoJoinAvailableSpaces": "Kullanılabilir alanlar", + "GuestAutoJoinAvailableSpacesHint": "Her uygulama kartının misafir otomatik katılımı için kendi « Kullanılabilir alanlar » satırı vardır; değişiklikler hemen uygulanır.", "ManageIdentities": "Kimlikleri yönet", "Release": "Serbest bırak", "ReleaseSocialId": "Sosyal ID'yi serbest bırak", diff --git a/plugins/setting-assets/lang/zh.json b/plugins/setting-assets/lang/zh.json index 4c2e15f2ba..dbb836da06 100644 --- a/plugins/setting-assets/lang/zh.json +++ b/plugins/setting-assets/lang/zh.json @@ -174,6 +174,8 @@ "GuestSignUpDescription": "允许匿名用户以访客身份加入您的工作区,获得有限的编辑权限", "GuestChannelsDescription": "访客加入后可以发送消息的频道", "GuestChannelsArrayLabel": "选择频道", + "GuestAutoJoinAvailableSpaces": "可用空间", + "GuestAutoJoinAvailableSpacesHint": "每个应用卡片都有各自的「可用空间」行,用于选择在激活时添加工作区访客的位置;更改会立即生效。", "ManageIdentities": "管理身份", "Release": "释放", "ReleaseSocialId": "释放社交ID", diff --git a/plugins/setting-resources/src/components/AvailableSpacesInput.svelte b/plugins/setting-resources/src/components/AvailableSpacesInput.svelte new file mode 100644 index 0000000000..9ae1f0d4c7 --- /dev/null +++ b/plugins/setting-resources/src/components/AvailableSpacesInput.svelte @@ -0,0 +1,143 @@ + + + + diff --git a/plugins/setting-resources/src/components/GuestPermissionsSettings.svelte b/plugins/setting-resources/src/components/GuestPermissionsSettings.svelte index 551258871a..4e4eff6c4d 100644 --- a/plugins/setting-resources/src/components/GuestPermissionsSettings.svelte +++ b/plugins/setting-resources/src/components/GuestPermissionsSettings.svelte @@ -48,6 +48,7 @@ } from '@hcengineering/ui' import setting from '@hcengineering/setting' import { onMount } from 'svelte' + import AvailableSpacesInput from './AvailableSpacesInput.svelte' import settingsRes from '../plugin' let loadingSettings = true @@ -244,6 +245,14 @@ allowGuestSignUp = e.detail } + function onReadonlyGuestsToggle (e: CustomEvent): void { + void handleToggleReadonlyAccess(e) + } + + function onGuestSignUpToggle (e: CustomEvent): void { + void handleToggleGuestSignUp(e) + } + async function onAllowedCardsChange (value: Ref[]): Promise { if (existingGuestChatSettings === undefined) { await client.createDoc(communication.class.GuestCommunicationSettings, core.space.Workspace, { @@ -317,12 +326,7 @@
- { - void handleToggleReadonlyAccess(e) - }} - /> +
@@ -330,13 +334,7 @@
- { - void handleToggleGuestSignUp(e) - }} - /> +
{#if communicationApiEnabled} @@ -376,6 +374,14 @@