From f94d564ec62c786fdc6bb8eccb78d3adf456ee1c Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Thu, 5 Mar 2026 15:19:43 +0700 Subject: [PATCH] Support default invite setting in branding (#10591) Signed-off-by: Artem Savchenko --- desktop/src/ui/platform.ts | 2 + desktop/src/ui/types.ts | 2 + dev/prod/src/platform.ts | 5 ++ .../src/components/InviteSetting.svelte | 47 +++++++++++++++---- plugins/setting/src/index.ts | 4 +- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/desktop/src/ui/platform.ts b/desktop/src/ui/platform.ts index b4a2bbd8e8..85527b6870 100644 --- a/desktop/src/ui/platform.ts +++ b/desktop/src/ui/platform.ts @@ -533,6 +533,8 @@ export async function configurePlatform (onWorkbenchConnect?: () => Promise diff --git a/dev/prod/src/platform.ts b/dev/prod/src/platform.ts index 59d7f0adff..57b91959b7 100644 --- a/dev/prod/src/platform.ts +++ b/dev/prod/src/platform.ts @@ -227,6 +227,8 @@ export interface Branding { defaultSpace?: string defaultSpecial?: string initWorkspace?: string + defaultInviteRole?: string + inviteLinkGeneratorRoles?: string[] } export type BrandingMap = Record @@ -736,6 +738,9 @@ export async function configurePlatform() { setMetadata(workbench.metadata.DefaultSpace, myBranding.defaultSpace ?? tracker.project.DefaultProject) setMetadata(workbench.metadata.DefaultSpecial, myBranding.defaultSpecial ?? 'issues') + setMetadata(setting.metadata.DefaultInviteRole, myBranding.defaultInviteRole) + setMetadata(setting.metadata.DefaultInviteLinkGeneratorRoles, myBranding.inviteLinkGeneratorRoles) + try { const parsed = JSON.parse(config.EXCLUDED_APPLICATIONS_FOR_ANONYMOUS ?? '') setMetadata(workbench.metadata.ExcludedApplicationsForAnonymous, Array.isArray(parsed) ? parsed : []) diff --git a/plugins/setting-resources/src/components/InviteSetting.svelte b/plugins/setting-resources/src/components/InviteSetting.svelte index f635d6589d..97d8793b28 100644 --- a/plugins/setting-resources/src/components/InviteSetting.svelte +++ b/plugins/setting-resources/src/components/InviteSetting.svelte @@ -18,7 +18,7 @@ import { createQuery, getClient } from '@hcengineering/presentation' import setting, { type InviteSettings, type RoleCapabilitySettings, RoleCapability } from '@hcengineering/setting' import { hasRoleCapability } from '../roleCapability' - import { translate } from '@hcengineering/platform' + import { getMetadata, translate } from '@hcengineering/platform' import { Breadcrumb, DropdownLabels, @@ -35,12 +35,42 @@ import UserRoleSelect from './UserRoleSelect.svelte' const client = getClient() + + const configDefaultInviteRole = getMetadata(setting.metadata.DefaultInviteRole) + const configInviteLinkGeneratorRoles = getMetadata(setting.metadata.DefaultInviteLinkGeneratorRoles) + + function normalizeRole (value: string | undefined, fallback: AccountRole): AccountRole { + if (typeof value === 'string') { + const normalizedValue = value.toLowerCase() + switch (normalizedValue) { + case 'guest': + return AccountRole.Guest + case 'user': + return AccountRole.User + case 'maintainer': + return AccountRole.Maintainer + case 'owner': + return AccountRole.Owner + } + } + return fallback + } + + function normalizeRoles (values: Array | undefined, fallback: AccountRole[]): AccountRole[] { + if (!Array.isArray(values) || values.length === 0) return [...fallback] + const mapped = values + .map((v) => normalizeRole(v, AccountRole.User)) + .filter((role, index, arr) => arr.indexOf(role) === index) + return mapped.length > 0 ? mapped : [...fallback] + } let loading = true let expTime: number = 48 let mask: string = '' let limit: number | undefined = -1 - let defaultInviteRole: AccountRole = AccountRole.User - let inviteLinkGeneratorRoles: AccountRole[] = [AccountRole.User, AccountRole.Maintainer, AccountRole.Owner] + const defaultGeneratorRoles: AccountRole[] = [AccountRole.User, AccountRole.Maintainer, AccountRole.Owner] + + let defaultInviteRole: AccountRole = normalizeRole(configDefaultInviteRole, AccountRole.User) + let inviteLinkGeneratorRoles: AccountRole[] = normalizeRoles(configInviteLinkGeneratorRoles, defaultGeneratorRoles) let noLimit: boolean = true let existingInviteSettings: InviteSettings[] = [] let existingRoleCapabilitySettings: { @@ -60,8 +90,6 @@ roleByCapability, undefined ) - const defaultGeneratorRoles: AccountRole[] = [AccountRole.User, AccountRole.Maintainer, AccountRole.Owner] - let inviteLinkGeneratorRolesItems: DropdownTextItem[] = [] $: lang = $themeStore?.language $: if (typeof lang === 'string') { @@ -85,17 +113,17 @@ expTime = first.expirationTime mask = first.emailMask limit = first.limit - defaultInviteRole = first.defaultInviteRole ?? AccountRole.User + defaultInviteRole = normalizeRole(first.defaultInviteRole, defaultInviteRole) inviteLinkGeneratorRoles = first.inviteLinkGeneratorRoles != null && first.inviteLinkGeneratorRoles.length > 0 - ? [...first.inviteLinkGeneratorRoles] + ? normalizeRoles(first.inviteLinkGeneratorRoles, defaultGeneratorRoles) : [...defaultGeneratorRoles] } else { expTime = 48 mask = '' limit = -1 - defaultInviteRole = AccountRole.User - inviteLinkGeneratorRoles = [...defaultGeneratorRoles] + defaultInviteRole = normalizeRole(configDefaultInviteRole, AccountRole.User) + inviteLinkGeneratorRoles = normalizeRoles(configInviteLinkGeneratorRoles, defaultGeneratorRoles) } noLimit = limit === -1 loading = false @@ -255,7 +283,6 @@ autoSelect={false} kind={'regular'} size={'medium'} - width={'100%'} on:selected={handleGeneratorRolesSelected} /> diff --git a/plugins/setting/src/index.ts b/plugins/setting/src/index.ts index ce3af0b930..ad0355d6d5 100644 --- a/plugins/setting/src/index.ts +++ b/plugins/setting/src/index.ts @@ -368,7 +368,9 @@ export default plugin(settingId, { Value: '' as Ref }, metadata: { - BackupUrl: '' as Metadata + BackupUrl: '' as Metadata, + DefaultInviteRole: '' as Metadata, + DefaultInviteLinkGeneratorRoles: '' as Metadata }, function: { HasRoleCapability: '' as Resource<(capabilityId: RoleCapabilityId | string) => Promise>