diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml
index 68c8f8e4f70..f73f28108c7 100644
--- a/common/config/rush/pnpm-lock.yaml
+++ b/common/config/rush/pnpm-lock.yaml
@@ -5199,7 +5199,7 @@ packages:
version: 0.0.0
'@rush-temp/model-billing@file:projects/model-billing.tgz':
- resolution: {integrity: sha512-1eQLuznSm1zZvdCWlGy3hA8xIwRz8RheuLbgmTh/amnobGuia/8ycCJEiPykrsvoLJSiVHrKyaXyySM5+r5jPg==, tarball: file:projects/model-billing.tgz}
+ resolution: {integrity: sha512-gXVvJywcc4AxaQFQNIy3i/YTJpxtJ7Bo+RSWx4Kn8lVMVSHQ1hK8Crr81hKwP0gNslAXV+TOH+xWRn5WY/xntA==, tarball: file:projects/model-billing.tgz}
version: 0.0.0
'@rush-temp/model-bitrix@file:projects/model-bitrix.tgz':
@@ -5599,7 +5599,7 @@ packages:
version: 0.0.0
'@rush-temp/pod-billing@file:projects/pod-billing.tgz':
- resolution: {integrity: sha512-8NzYAsIUJIXwLfBF2mhvK1N70CrgXR/zN4Ppn0YiKrCAPWUaEg6mxz47qvAKyoYZcNvnzGr/6jQbR/Iv7kPEvA==, tarball: file:projects/pod-billing.tgz}
+ resolution: {integrity: sha512-JaJcuMheg+Um4mTADRrB3cYwpb/XFg9rZQCuh1CAWdZDsKh6g8EoeImFZtD1TeiKXB2wkT+mdbFN0dXYR65LXg==, tarball: file:projects/pod-billing.tgz}
version: 0.0.0
'@rush-temp/pod-calendar-mailer@file:projects/pod-calendar-mailer.tgz':
@@ -28046,6 +28046,7 @@ snapshots:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.3)
cors: 2.8.5
+ cross-env: 7.0.3
dotenv: 16.0.3
esbuild: 0.25.11
eslint: 8.57.1
diff --git a/models/billing/package.json b/models/billing/package.json
index 678aef35d30..072c057f509 100644
--- a/models/billing/package.json
+++ b/models/billing/package.json
@@ -37,8 +37,10 @@
"@hcengineering/core": "^0.7.20",
"@hcengineering/model": "^0.7.17",
"@hcengineering/model-core": "^0.7.0",
+ "@hcengineering/model-presentation": "^0.7.0",
"@hcengineering/setting": "^0.7.0",
"@hcengineering/billing": "^0.7.0",
- "@hcengineering/platform": "^0.7.17"
+ "@hcengineering/platform": "^0.7.17",
+ "@hcengineering/workbench": "^0.7.0"
}
}
diff --git a/models/billing/src/index.ts b/models/billing/src/index.ts
index 6fb1a36c6a3..b94a3e65d63 100644
--- a/models/billing/src/index.ts
+++ b/models/billing/src/index.ts
@@ -19,6 +19,8 @@ import { type IntlString } from '@hcengineering/platform'
import setting from '@hcengineering/setting'
import billing, { type Tier } from '@hcengineering/billing'
import { AccountRole, DOMAIN_MODEL } from '@hcengineering/core'
+import presentation from '@hcengineering/model-presentation'
+import workbench from '@hcengineering/workbench'
export { billingId } from '@hcengineering/billing'
export { billing as default }
@@ -107,4 +109,9 @@ export function createModel (builder: Builder): void {
},
billing.tier.Legendary
)
+
+ builder.createDoc(presentation.class.ComponentPointExtension, core.space.Model, {
+ extension: workbench.extensions.WorkbenchExtensions,
+ component: billing.component.WorkbenchExtension
+ })
}
diff --git a/packages/theme/styles/_colors.scss b/packages/theme/styles/_colors.scss
index de226a53a8a..7ef6e0410c6 100644
--- a/packages/theme/styles/_colors.scss
+++ b/packages/theme/styles/_colors.scss
@@ -138,6 +138,15 @@
--theme-button-container-color: #25262A;
+ --theme-button-attention-gradient: linear-gradient(135deg, #7C3AED, #A855F7);
+ --theme-button-attention-border: #A855F7;
+ --theme-button-attention-hover-gradient: linear-gradient(135deg, #8B5CF6, #7C3AED);
+ --theme-button-attention-hover-border: #7C3AED;
+ --theme-button-attention-active-gradient: linear-gradient(135deg, #6D28D9, #7C3AED);
+ --theme-button-attention-hover-shadow: 0 8px 24px rgba(124, 58, 237, 0.4);
+ --theme-button-attention-active-shadow: 0 4px 12px rgba(124, 58, 237, 0.6);
+ --theme-button-attention-focus-shadow: 0 0 0 3px rgba(124, 58, 237, 0.3);
+
--theme-refinput-divider: rgba(255, 255, 255, .07);
--theme-refinput-border: rgba(255, 255, 255, .1);
@@ -449,6 +458,15 @@
--theme-button-container-color: #F1F1F1;
+ --theme-button-attention-gradient: linear-gradient(135deg, #EC4899, #F97316);
+ --theme-button-attention-border: #F97316;
+ --theme-button-attention-hover-gradient: linear-gradient(135deg, #F97316, #EC4899);
+ --theme-button-attention-hover-border: #EC4899;
+ --theme-button-attention-active-gradient: linear-gradient(135deg, #DC2626, #F97316);
+ --theme-button-attention-hover-shadow: 0 8px 24px rgba(236, 72, 153, 0.3);
+ --theme-button-attention-active-shadow: 0 4px 12px rgba(236, 72, 153, 0.5);
+ --theme-button-attention-focus-shadow: 0 0 0 3px rgba(236, 72, 153, 0.2);
+
--theme-refinput-divider: rgba(0, 0, 0, .07);
--theme-refinput-border: rgba(0, 0, 0, .1);
diff --git a/packages/theme/styles/button.scss b/packages/theme/styles/button.scss
index ebef04acfb4..1a39f047cc3 100644
--- a/packages/theme/styles/button.scss
+++ b/packages/theme/styles/button.scss
@@ -169,6 +169,65 @@
}
}
+ &.attention {
+ position: relative;
+ overflow: hidden;
+ font-weight: 600;
+ border: 2px solid var(--theme-button-attention-border);
+ background: var(--theme-button-attention-gradient);
+ animation: attention-pulse 2s ease-in-out infinite;
+
+ .icon { color: var(--button-accent-IconColor); }
+ span { color: var(--button-accent-LabelColor); }
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: var(--theme-button-attention-shine);
+ transition: left 0.6s ease;
+ }
+
+ &:not(.disabled, :disabled):hover {
+ background: var(--theme-button-attention-hover-gradient);
+ border-color: var(--theme-button-attention-hover-border);
+ transform: translateY(-2px);
+ box-shadow: var(--theme-button-attention-hover-shadow);
+
+ &::before { left: 100%; }
+ }
+
+ &:not(.disabled, :disabled):active,
+ &.pressed:not(.disabled, :disabled) {
+ transform: translateY(0) scale(0.98);
+ box-shadow: var(--theme-button-attention-active-shadow);
+ }
+
+ &:not(.no-focus):focus {
+ box-shadow: var(--theme-button-attention-focus-shadow);
+ }
+
+ &:disabled:not(.loading),
+ &.disabled:not(.loading) {
+ background: var(--button-disabled-BackgroundColor);
+ border-color: var(--button-disabled-BackgroundColor);
+ animation: none;
+ transform: none;
+ box-shadow: none;
+
+ &::before { display: none; }
+ }
+
+ &.loading {
+ background: var(--theme-button-attention-active-gradient);
+
+ span { color: var(--button-accent-LabelColor); }
+ }
+ }
+
& > * { pointer-events: none; }
}
@@ -532,6 +591,63 @@
background-color: var(--negative-button-disabled);
}
}
+ &.attention {
+ position: relative;
+ overflow: hidden;
+ font-weight: 600;
+ color: var(--primary-button-color);
+ background: var(--theme-button-attention-gradient);
+ border: 2px solid var(--theme-button-attention-border);
+ animation: attention-pulse 2s ease-in-out infinite;
+
+ .btn-icon,
+ .btn-right-icon { color: var(--primary-button-color); }
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: var(--theme-button-attention-shine);
+ transition: left 0.6s ease;
+ }
+
+ &:hover {
+ background: var(--theme-button-attention-hover-gradient);
+ border-color: var(--theme-button-attention-hover-border);
+ transform: translateY(-2px);
+ box-shadow: var(--theme-button-attention-hover-shadow);
+
+ &::before { left: 100%; }
+ }
+
+ &:active,
+ &.pressed,
+ &.pressed:hover {
+ transform: translateY(0) scale(0.98);
+ box-shadow: var(--theme-button-attention-active-shadow);
+ }
+
+ &:not(.no-focus):focus {
+ box-shadow: var(--theme-button-attention-focus-shadow);
+ }
+
+ &:disabled {
+ color: var(--primary-button-disabled-color);
+ background: var(--primary-button-disabled);
+ border-color: var(--primary-button-disabled);
+ animation: none;
+ transform: none;
+ box-shadow: none;
+
+ &::before { display: none; }
+
+ .btn-icon,
+ .btn-right-icon { color: var(--primary-button-disabled-color); }
+ }
+ }
&.contrast {
padding: .75rem 1rem;
font-weight: 500;
@@ -902,4 +1018,15 @@
content: none;
}
}
+
+ @keyframes attention-pulse {
+ 0%, 100% {
+ box-shadow: var(--theme-button-attention-active-shadow), 0 0 0 0 var(--theme-button-attention-border);
+ transform: scale(1);
+ }
+ 50% {
+ box-shadow: var(--theme-button-attention-hover-shadow), 0 0 0 4px rgba(124, 58, 237, 0.1);
+ transform: scale(1.02);
+ }
+ }
}
diff --git a/packages/ui/src/components/Button.svelte b/packages/ui/src/components/Button.svelte
index 571554a8747..b29c11a479d 100644
--- a/packages/ui/src/components/Button.svelte
+++ b/packages/ui/src/components/Button.svelte
@@ -79,7 +79,7 @@
label === undefined &&
$$slots.content === undefined &&
(icon !== undefined || iconRight !== undefined || $$slots.icon || $$slots.iconRight)
- $: primary = ['primary', 'secondary', 'positive', 'negative'].some((p) => p === kind)
+ $: primary = ['primary', 'secondary', 'positive', 'negative', 'attention'].some((p) => p === kind)
$: devSize = $deviceInfo.size
$: adaptive = adaptiveShrink !== null ? checkAdaptiveMatching(devSize, adaptiveShrink) : false
diff --git a/packages/ui/src/components/ModernDialog.svelte b/packages/ui/src/components/ModernDialog.svelte
index 5d31fd060e7..1518a64e27b 100644
--- a/packages/ui/src/components/ModernDialog.svelte
+++ b/packages/ui/src/components/ModernDialog.svelte
@@ -174,6 +174,10 @@
max-height: unset;
border-radius: 0;
}
+
+ &.extendedHeight {
+ max-height: 90vh;
+ }
}
.shadow {
diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts
index b87e52f9cf6..c45f2af0412 100644
--- a/packages/ui/src/types.ts
+++ b/packages/ui/src/types.ts
@@ -174,6 +174,7 @@ export type ButtonKind =
| 'list-header'
| 'contrast'
| 'stepper'
+ | 'attention'
export type ButtonSize = 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
export type ButtonShape =
| 'rectangle'
diff --git a/plugins/billing-assets/lang/cs.json b/plugins/billing-assets/lang/cs.json
index 78f4991b367..e3f855d264e 100644
--- a/plugins/billing-assets/lang/cs.json
+++ b/plugins/billing-assets/lang/cs.json
@@ -53,6 +53,9 @@
"StorageUsage": "Úložiště",
"TrafficUsage": "Video/audio provoz",
"Usage": "Využití",
- "Of": "z"
+ "Of": "z",
+ "UpgradePlan": "Upgradovat plán",
+ "LimitReached": "Dosažen limit pracovního prostoru, některé funkce mohou být zakázány. Upgradujte pro obnovení plného přístupu.",
+ "AskBillingAdmin": "Kontaktujte prosím svého správce fakturace pro upgrade plánu."
}
}
diff --git a/plugins/billing-assets/lang/de.json b/plugins/billing-assets/lang/de.json
index 653198348c0..12b08e7899c 100644
--- a/plugins/billing-assets/lang/de.json
+++ b/plugins/billing-assets/lang/de.json
@@ -53,6 +53,9 @@
"StorageUsage": "Speicher",
"TrafficUsage": "Video/Audio-Traffic",
"Usage": "Nutzung",
- "Of": "von"
+ "Of": "von",
+ "UpgradePlan": "Plan upgraden",
+ "LimitReached": "Arbeitsbereich-Limit erreicht, einige Funktionen könnten deaktiviert sein. Upgraden Sie für vollen Zugriff.",
+ "AskBillingAdmin": "Bitte kontaktieren Sie Ihren Abrechnungsadministrator, um den Plan zu upgraden."
}
}
diff --git a/plugins/billing-assets/lang/en.json b/plugins/billing-assets/lang/en.json
index aa96ce2c122..a50044cdbc4 100644
--- a/plugins/billing-assets/lang/en.json
+++ b/plugins/billing-assets/lang/en.json
@@ -53,6 +53,9 @@
"StorageUsage": "Storage",
"TrafficUsage": "Video/Audio traffic",
"Usage": "Usage",
- "Of": "of"
+ "Of": "of",
+ "UpgradePlan": "Upgrade Plan",
+ "LimitReached": "Workspace limit reached, some functionality may be disabled. Upgrade to restore full access.",
+ "AskBillingAdmin": "Please contact your billing administrator to upgrade the plan."
}
}
diff --git a/plugins/billing-assets/lang/es.json b/plugins/billing-assets/lang/es.json
index 4760188bd11..5d1d65e6112 100644
--- a/plugins/billing-assets/lang/es.json
+++ b/plugins/billing-assets/lang/es.json
@@ -53,6 +53,9 @@
"StorageUsage": "Almacenamiento",
"TrafficUsage": "Tráfico de vídeo/audio",
"Usage": "Uso",
- "Of": "de"
+ "Of": "de",
+ "UpgradePlan": "Actualizar Plan",
+ "LimitReached": "Límite del espacio de trabajo alcanzado, algunas funciones pueden estar deshabilitadas. Actualiza para restaurar acceso completo.",
+ "AskBillingAdmin": "Por favor, contacta a tu administrador de facturación para actualizar el plan."
}
}
diff --git a/plugins/billing-assets/lang/fr.json b/plugins/billing-assets/lang/fr.json
index 37745ab6d00..176970c60bf 100644
--- a/plugins/billing-assets/lang/fr.json
+++ b/plugins/billing-assets/lang/fr.json
@@ -53,6 +53,9 @@
"StorageUsage": "Stockage",
"TrafficUsage": "Trafic vidéo/audio",
"Usage": "Utilisation",
- "Of": "de"
+ "Of": "de",
+ "UpgradePlan": "Mettre à niveau le plan",
+ "LimitReached": "Limite de l'espace de travail atteinte, certaines fonctionnalités peuvent être désactivées. Mettez à niveau pour restaurer l'accès complet.",
+ "AskBillingAdmin": "Veuillez contacter votre administrateur de facturation pour mettre à niveau le plan."
}
}
diff --git a/plugins/billing-assets/lang/it.json b/plugins/billing-assets/lang/it.json
index 4fa4bbe0287..08312702bfd 100644
--- a/plugins/billing-assets/lang/it.json
+++ b/plugins/billing-assets/lang/it.json
@@ -53,6 +53,9 @@
"StorageUsage": "Archiviazione",
"TrafficUsage": "Traffico video/audio",
"Usage": "Utilizzo",
- "Of": "di"
+ "Of": "di",
+ "UpgradePlan": "Aggiorna Piano",
+ "LimitReached": "Limite workspace raggiunto, alcune funzionalità potrebbero essere disabilitate. Aggiorna per ripristinare l'accesso completo.",
+ "AskBillingAdmin": "Contatta il tuo amministratore di fatturazione per aggiornare il piano."
}
}
diff --git a/plugins/billing-assets/lang/ja.json b/plugins/billing-assets/lang/ja.json
index ee2ea89a55c..5adad966742 100644
--- a/plugins/billing-assets/lang/ja.json
+++ b/plugins/billing-assets/lang/ja.json
@@ -53,6 +53,9 @@
"StorageUsage": "ストレージ",
"TrafficUsage": "ビデオ/オーディオトラフィック",
"Usage": "使用状況",
- "Of": "/"
+ "Of": "/",
+ "UpgradePlan": "プランをアップグレード",
+ "LimitReached": "ワークスペースの制限に達しました。一部の機能が無効になる場合があります。アップグレードして完全アクセスを復元してください。",
+ "AskBillingAdmin": "プランをアップグレードするには、請求管理者にお問い合わせください。"
}
}
diff --git a/plugins/billing-assets/lang/pt.json b/plugins/billing-assets/lang/pt.json
index 22324145fb5..c7bc9cade93 100644
--- a/plugins/billing-assets/lang/pt.json
+++ b/plugins/billing-assets/lang/pt.json
@@ -53,6 +53,9 @@
"StorageUsage": "Armazenamento",
"TrafficUsage": "Tráfego de vídeo/áudio",
"Usage": "Uso",
- "Of": "de"
+ "Of": "de",
+ "UpgradePlan": "Atualizar Plano",
+ "LimitReached": "Limite do workspace atingido, algumas funcionalidades podem estar desabilitadas. Atualize para restaurar acesso completo.",
+ "AskBillingAdmin": "Por favor, contate seu administrador de faturamento para atualizar o plano."
}
}
diff --git a/plugins/billing-assets/lang/ru.json b/plugins/billing-assets/lang/ru.json
index 594cd3a1dbf..da7db87db50 100644
--- a/plugins/billing-assets/lang/ru.json
+++ b/plugins/billing-assets/lang/ru.json
@@ -53,6 +53,9 @@
"StorageUsage": "Хранилище",
"TrafficUsage": "Видео/аудио трафик",
"Usage": "Использование",
- "Of": "из"
+ "Of": "из",
+ "UpgradePlan": "Обновить план",
+ "LimitReached": "Достигнут лимит рабочего пространства, некоторые функции могут быть отключены. Обновите план для восстановления полного доступа.",
+ "AskBillingAdmin": "Пожалуйста, свяжитесь с вашим администратором биллинга для обновления плана."
}
}
diff --git a/plugins/billing-assets/lang/tr.json b/plugins/billing-assets/lang/tr.json
index 8c63ab1000d..176b84de45a 100644
--- a/plugins/billing-assets/lang/tr.json
+++ b/plugins/billing-assets/lang/tr.json
@@ -53,6 +53,9 @@
"StorageUsage": "Depolama",
"TrafficUsage": "Video/ses trafiği",
"Usage": "Kullanım",
- "Of": "/"
+ "Of": "/",
+ "UpgradePlan": "Planı Yükselt",
+ "LimitReached": "Çalışma alanı limiti aşıldı, bazı işlevler devre dışı bırakılabilir. Tam erişimi geri yüklemek için yükseltin.",
+ "AskBillingAdmin": "Lütfen planı yükseltmek için faturalama yöneticinizle iletişime geçin."
}
}
diff --git a/plugins/billing-assets/lang/zh.json b/plugins/billing-assets/lang/zh.json
index 09df476a372..3755b8170f5 100644
--- a/plugins/billing-assets/lang/zh.json
+++ b/plugins/billing-assets/lang/zh.json
@@ -53,6 +53,9 @@
"StorageUsage": "存储",
"TrafficUsage": "视频/音频流量",
"Usage": "使用情况",
- "Of": "/"
+ "Of": "/",
+ "UpgradePlan": "升级计划",
+ "LimitReached": "已达到工作空间限制,某些功能可能被禁用。请升级以恢复完全访问权限。",
+ "AskBillingAdmin": "请联系您的计费管理员以升级计划。"
}
}
diff --git a/plugins/billing-resources/src/components/SubscriptionsModal.svelte b/plugins/billing-resources/src/components/SubscriptionsModal.svelte
new file mode 100644
index 00000000000..b3b9dc2a4d2
--- /dev/null
+++ b/plugins/billing-resources/src/components/SubscriptionsModal.svelte
@@ -0,0 +1,23 @@
+
+
+
+