@saasicat/ui-vue 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/{chunk-EH7TOD4H.js → chunk-A3W2N26K.js} +73 -77
- package/dist/{chunk-3YP2ZAOD.js → chunk-QZOSDCNP.js} +36 -1
- package/dist/chunk-X5SQ5HMB.js +3231 -0
- package/dist/client/index.cjs +3279 -76
- package/dist/client/index.d.cts +31 -5
- package/dist/client/index.d.ts +31 -5
- package/dist/client/index.js +23 -5
- package/dist/index.cjs +3709 -465
- package/dist/index.d.cts +37 -54
- package/dist/index.d.ts +37 -54
- package/dist/index.js +347 -311
- package/dist/messages-7b0P8W75.d.cts +1652 -0
- package/dist/messages-7b0P8W75.d.ts +1652 -0
- package/dist/quasar/index.cjs +3185 -4
- package/dist/quasar/index.d.cts +11 -2
- package/dist/quasar/index.d.ts +11 -2
- package/dist/quasar/index.js +8 -3
- package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
- package/dist/testing-e2e/admin-pages-suite.js +14 -11
- package/dist/{ui-notify-COUzXEQ4.d.ts → use-super-admin-i18n-B3v3-SWZ.d.ts} +35 -3
- package/dist/{ui-notify-D_eAAwRh.d.cts → use-super-admin-i18n-DMktRVEt.d.cts} +35 -3
- package/package.json +2 -2
- package/src/client/action-registry.ts +4 -4
- package/src/client/batch-column-fetcher.ts +4 -4
- package/src/client/boot-loader.ts +3 -3
- package/src/client/i18n/currency.ts +42 -0
- package/src/client/i18n/define.ts +59 -0
- package/src/client/i18n/format.ts +12 -0
- package/src/client/i18n/index.ts +14 -0
- package/src/client/i18n/locale.ts +15 -0
- package/src/client/i18n/messages/audit.ts +42 -0
- package/src/client/i18n/messages/bundles.ts +459 -0
- package/src/client/i18n/messages/common.ts +147 -0
- package/src/client/i18n/messages/dashboard.ts +16 -0
- package/src/client/i18n/messages/discovery.ts +229 -0
- package/src/client/i18n/messages/email.ts +125 -0
- package/src/client/i18n/messages/marketing.ts +270 -0
- package/src/client/i18n/messages/nav.ts +72 -0
- package/src/client/i18n/messages/pilots.ts +192 -0
- package/src/client/i18n/messages/plan-detail.ts +266 -0
- package/src/client/i18n/messages/plan-editor.ts +177 -0
- package/src/client/i18n/messages/plan-versions.ts +251 -0
- package/src/client/i18n/messages/plans.ts +503 -0
- package/src/client/i18n/messages/promos.ts +202 -0
- package/src/client/i18n/messages/shell.ts +145 -0
- package/src/client/i18n/messages/tenants.ts +104 -0
- package/src/client/i18n/messages/users.ts +78 -0
- package/src/client/i18n/messages.ts +84 -0
- package/src/client/index.ts +2 -0
- package/src/client/manifest-loader.ts +4 -4
- package/src/client/nav-builder.ts +44 -51
- package/src/client/plan-versions-catalog.ts +42 -30
- package/src/components/BundleVersionPublishDialog.vue +35 -24
- package/src/components/MarketingPromotionsTab.vue +112 -59
- package/src/components/MfaPromptDialog.vue +11 -11
- package/src/components/TenantActionConfirmDialog.vue +19 -17
- package/src/components/VersionDiffPreview.vue +72 -43
- package/src/components/bundle-editor/BundleCreatePanel.vue +76 -63
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +13 -6
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +19 -14
- package/src/components/bundle-editor/BundleQuotasEditor.vue +7 -4
- package/src/components/bundle-editor/BundleStatusBanner.vue +36 -19
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +51 -35
- package/src/components/bundle-editor/BundleVersionStrip.vue +24 -12
- package/src/components/bundle-editor/bundle-version-status.ts +29 -29
- package/src/components/dialogs/PilotCreateDialog.vue +58 -63
- package/src/components/dialogs/PilotEditDialog.vue +40 -34
- package/src/components/dialogs/PromoCodeCreateDialog.vue +89 -63
- package/src/components/dialogs/PromoCodeEditDialog.vue +98 -66
- package/src/components/dialogs/types.ts +3 -13
- package/src/components/plan/PlanCycleToggle.vue +20 -9
- package/src/components/plan-cockpit/PlanCockpit.vue +34 -15
- package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +13 -6
- package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +18 -9
- package/src/components/plan-cockpit/PlanCockpitHeader.vue +9 -6
- package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +24 -11
- package/src/components/plan-cockpit/PlanCockpitKpis.vue +28 -17
- package/src/components/plan-cockpit/PlanCockpitVersions.vue +50 -25
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +45 -35
- package/src/components/plan-detail/PlanAuditLog.vue +11 -6
- package/src/components/plan-detail/PlanDetail.vue +21 -23
- package/src/components/plan-detail/PlanDetailHeader.vue +20 -11
- package/src/components/plan-detail/PlanDetailKpis.vue +30 -17
- package/src/components/plan-detail/PlanTerminateDialog.vue +22 -9
- package/src/components/plan-detail/PlanVersionDiffPanel.vue +61 -27
- package/src/components/plan-detail/PlanVersionsPanel.vue +71 -36
- package/src/components/plan-list/PlanList.vue +99 -57
- package/src/components/plan-matrix/PlanMatrix.vue +85 -38
- package/src/components/plan-review/PlanReview.vue +105 -80
- package/src/components/plan-version-editor/PlanCatalogPreview.vue +43 -20
- package/src/components/plan-version-editor/PlanComponentPool.vue +15 -7
- package/src/components/plan-version-editor/PlanVersionBasket.vue +45 -24
- package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +8 -7
- package/src/components/plan-version-editor/PlanVersionEditor.vue +74 -40
- package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +24 -12
- package/src/index.ts +1 -1
- package/src/pages-standard/AdminLayout.vue +42 -17
- package/src/pages-standard/AdminManifestErrorPage.vue +10 -10
- package/src/pages-standard/AuditPage.vue +58 -19
- package/src/pages-standard/BundlesPage.vue +29 -18
- package/src/pages-standard/DashboardPage.vue +29 -15
- package/src/pages-standard/DiscoveryPage.vue +40 -28
- package/src/pages-standard/EmailHistoryPage.vue +92 -59
- package/src/pages-standard/MarketingCatalogPage.vue +35 -16
- package/src/pages-standard/PilotsPage.vue +57 -41
- package/src/pages-standard/PlanVersionsPage.vue +7 -3
- package/src/pages-standard/PlansPage.vue +89 -57
- package/src/pages-standard/PlatformEmailPage.vue +115 -50
- package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
- package/src/pages-standard/PromoCodesPage.vue +46 -35
- package/src/pages-standard/SubscriptionsPage.vue +14 -9
- package/src/pages-standard/SuperAdminLoginPage.vue +16 -13
- package/src/pages-standard/SuperAdminSetupWizard.vue +51 -47
- package/src/pages-standard/TenantDetailPage.vue +50 -36
- package/src/pages-standard/TenantsPage.vue +54 -41
- package/src/pages-standard/UsersPage.vue +66 -42
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -8
- package/src/pages-standard/bundles-page/BundleDetailPanel.vue +28 -18
- package/src/pages-standard/bundles-page/BundlesFilterBar.vue +4 -1
- package/src/pages-standard/bundles-page/BundlesHeader.vue +9 -8
- package/src/pages-standard/bundles-page/BundlesKpis.vue +29 -11
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +20 -8
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -3
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +43 -24
- package/src/pages-standard/discovery-page/DiscoveryHeader.vue +7 -4
- package/src/pages-standard/discovery-page/DiscoveryKpis.vue +28 -15
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +20 -10
- package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +9 -6
- package/src/pages-standard/discovery-page/discovery-ui.ts +40 -52
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +81 -49
- package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +13 -10
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +24 -20
- package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +6 -3
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -6
- package/src/pages-standard/plan-versions/PlanVersionHeader.vue +41 -25
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +45 -26
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +7 -5
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +39 -16
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +24 -12
- package/src/pages-standard/plan-versions/format.ts +33 -17
- package/src/pages-standard/plans-page/PlanArchiveDialog.vue +12 -8
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +15 -6
- package/src/pages-standard/plans-page/PlanDiscardDraftDialog.vue +18 -7
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +23 -12
- package/src/pages-standard/tenants/format.ts +3 -2
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +72 -37
- package/src/pages-tenant/PlanChangeWizard.vue +8 -4
- package/src/pages-tenant/TenantPlanSection.vue +17 -13
- package/src/pages-tenant/default-i18n.ts +217 -1
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +8 -6
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +9 -10
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
- package/src/quasar/create-super-admin-app.ts +19 -0
- package/src/testing-e2e/admin-pages-suite.ts +14 -11
- package/src/vue/project-page-host.ts +5 -3
- package/src/vue/use-audit-entries.ts +3 -3
- package/src/vue/use-bulk-publish.ts +6 -4
- package/src/vue/use-bundle-versions-map.ts +6 -4
- package/src/vue/use-bundles.ts +13 -13
- package/src/vue/use-catalog-entries.ts +13 -10
- package/src/vue/use-discovery.ts +8 -5
- package/src/vue/use-entitlement.ts +3 -3
- package/src/vue/use-live-plan-versions.ts +4 -4
- package/src/vue/use-marketing-projections.ts +9 -6
- package/src/vue/use-nav.ts +8 -2
- package/src/vue/use-plan-editor.ts +2 -2
- package/src/vue/use-plan-versions.ts +3 -3
- package/src/vue/use-plans.ts +12 -12
- package/src/vue/use-platform-tenant-actions.ts +9 -6
- package/src/vue/use-promotions.ts +9 -10
- package/src/vue/use-subscription-draft.ts +2 -3
- package/src/vue/use-super-admin-context.ts +3 -3
- package/src/vue/use-super-admin-i18n.ts +82 -0
- package/src/vue/use-tenant-action-flow.ts +11 -6
- package/src/vue/use-tenant-manifest.ts +1 -3
- package/src/vue/use-tenant-subscription-bundles.ts +4 -4
- package/src/vue/use-tenants.ts +3 -3
- package/dist/action-registry-CQ2wL3R-.d.cts +0 -85
- package/dist/action-registry-CQ2wL3R-.d.ts +0 -85
- package/dist/chunk-LVGUSD3T.js +0 -26
- package/src/components/BusinessTypeVersionEditorDialog.vue +0 -417
- package/src/components/BusinessTypeVersionPublishDialog.vue +0 -258
- package/src/pages-standard/BusinessTypesPage.vue +0 -662
- package/src/pages-standard/plan-versions/VersionDiffPreview.vue +0 -167
- package/src/vue/use-business-types.ts +0 -269
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
<section class="pd-panel pd-audit">
|
|
3
3
|
<div class="pd-panel-head">
|
|
4
4
|
<div style="min-width: 0">
|
|
5
|
-
<h3 class="pd-panel-title">
|
|
6
|
-
<div class="pd-panel-sub">
|
|
5
|
+
<h3 class="pd-panel-title">{{ msg.auditLog.title }}</h3>
|
|
6
|
+
<div class="pd-panel-sub">{{ msg.auditLog.subtitle }}</div>
|
|
7
7
|
</div>
|
|
8
8
|
</div>
|
|
9
9
|
<div class="pd-audit-body">
|
|
10
|
-
<div v-if="loadingAudit" class="pd-diff-empty">
|
|
10
|
+
<div v-if="loadingAudit" class="pd-diff-empty">{{ msg.auditLog.loading }}</div>
|
|
11
11
|
<div v-for="a in auditRows" :key="a.id" class="pd-audit-row">
|
|
12
12
|
<span :class="['pd-audit-dot', `pd-audit-${auditKind(a.action)}`]" />
|
|
13
13
|
<span class="pd-audit-when">{{ formatAuditDate(a.createdAt) }}</span>
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
22
|
<script setup lang="ts">
|
|
23
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
24
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
23
25
|
import type { AuditRow } from './types.js';
|
|
24
26
|
|
|
25
27
|
defineProps<{
|
|
@@ -27,6 +29,9 @@ defineProps<{
|
|
|
27
29
|
loadingAudit: boolean;
|
|
28
30
|
}>();
|
|
29
31
|
|
|
32
|
+
const msg = useSaMessages('planDetail');
|
|
33
|
+
const { intlLocale } = useSuperAdminI18n();
|
|
34
|
+
|
|
30
35
|
function auditKind(action: string): string {
|
|
31
36
|
const a = action.toLowerCase();
|
|
32
37
|
if (a.includes('publish')) return 'publish';
|
|
@@ -51,9 +56,9 @@ function formatAuditDate(iso: string): string {
|
|
|
51
56
|
const d = new Date(iso);
|
|
52
57
|
if (Number.isNaN(d.getTime())) return iso;
|
|
53
58
|
const isToday = d.toDateString() === new Date().toDateString();
|
|
54
|
-
const time = d.toLocaleTimeString(
|
|
59
|
+
const time = d.toLocaleTimeString(intlLocale.value, { hour: '2-digit', minute: '2-digit' });
|
|
55
60
|
return isToday
|
|
56
|
-
?
|
|
57
|
-
: `${d.toLocaleDateString(
|
|
61
|
+
? formatMessage(msg.value.auditLog.today, { time })
|
|
62
|
+
: `${d.toLocaleDateString(intlLocale.value, { day: '2-digit', month: 'short' })} · ${time}`;
|
|
58
63
|
}
|
|
59
64
|
</script>
|
|
@@ -77,11 +77,9 @@
|
|
|
77
77
|
|
|
78
78
|
<script setup lang="ts">
|
|
79
79
|
import { computed, ref, watch } from 'vue';
|
|
80
|
-
import {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
type PlanVersionRow,
|
|
84
|
-
} from '@saasicat/types';
|
|
80
|
+
import { isVersionEditable, type PlanRow, type PlanVersionRow } from '@saasicat/types';
|
|
81
|
+
import { formatCurrency } from '../../client/i18n/currency.js';
|
|
82
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
85
83
|
import PlanAuditLog from './PlanAuditLog.vue';
|
|
86
84
|
import PlanDetailHeader from './PlanDetailHeader.vue';
|
|
87
85
|
import PlanDetailKpis from './PlanDetailKpis.vue';
|
|
@@ -143,6 +141,9 @@ const emit = defineEmits<{
|
|
|
143
141
|
(e: 'terminate', versionId: string, endsAt: string): void;
|
|
144
142
|
}>();
|
|
145
143
|
|
|
144
|
+
const msg = useSaMessages('planDetail');
|
|
145
|
+
const { locale, intlLocale } = useSuperAdminI18n();
|
|
146
|
+
|
|
146
147
|
// ── Status / Selection ──────────────────────────────────────────────
|
|
147
148
|
function statusOf(v: PlanVersionRow): PlanVersionStatus {
|
|
148
149
|
if (v.publishedAt === null) return 'draft';
|
|
@@ -201,7 +202,7 @@ const timelineTicks = computed(() => {
|
|
|
201
202
|
for (const v of chronological.value) {
|
|
202
203
|
if (v.validFrom) ticks.push(v.validFrom.slice(0, 7));
|
|
203
204
|
}
|
|
204
|
-
ticks.push(
|
|
205
|
+
ticks.push(msg.value.versions.timelineNow);
|
|
205
206
|
return ticks;
|
|
206
207
|
});
|
|
207
208
|
|
|
@@ -209,9 +210,7 @@ const timelineTicks = computed(() => {
|
|
|
209
210
|
function formatMoney(raw: string | number): string {
|
|
210
211
|
const num = typeof raw === 'string' ? Number(raw) : raw;
|
|
211
212
|
if (!Number.isFinite(num)) return String(raw);
|
|
212
|
-
|
|
213
|
-
if (Number.isInteger(num)) return `${num} €`;
|
|
214
|
-
return `${num.toFixed(2).replace('.', ',')} €`;
|
|
213
|
+
return formatCurrency(num, locale.value);
|
|
215
214
|
}
|
|
216
215
|
function quotasOf(v: PlanVersionRow): Record<string, number> {
|
|
217
216
|
if (v.quotas && Object.keys(v.quotas).length > 0) return v.quotas;
|
|
@@ -290,7 +289,7 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
290
289
|
id: 'af-' + f,
|
|
291
290
|
kind: 'add',
|
|
292
291
|
sign: '+',
|
|
293
|
-
tag:
|
|
292
|
+
tag: msg.value.diff.tagNew,
|
|
294
293
|
label: featureLabel(f),
|
|
295
294
|
key: f,
|
|
296
295
|
});
|
|
@@ -299,7 +298,7 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
299
298
|
id: 'rf-' + f,
|
|
300
299
|
kind: 'rm',
|
|
301
300
|
sign: '−',
|
|
302
|
-
tag:
|
|
301
|
+
tag: msg.value.diff.tagRemoved,
|
|
303
302
|
label: featureLabel(f),
|
|
304
303
|
key: f,
|
|
305
304
|
});
|
|
@@ -309,7 +308,7 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
309
308
|
id: 'cq-' + q.key,
|
|
310
309
|
kind: 'mod',
|
|
311
310
|
sign: '~',
|
|
312
|
-
tag:
|
|
311
|
+
tag: msg.value.diff.tagChanged,
|
|
313
312
|
label: quotaLabel(q.key),
|
|
314
313
|
key: q.key,
|
|
315
314
|
from: `${q.from} ${u}`.trim(),
|
|
@@ -322,7 +321,7 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
322
321
|
id: 'aq-' + q.key,
|
|
323
322
|
kind: 'add',
|
|
324
323
|
sign: '+',
|
|
325
|
-
tag:
|
|
324
|
+
tag: msg.value.diff.tagNew,
|
|
326
325
|
label: quotaLabel(q.key),
|
|
327
326
|
key: q.key,
|
|
328
327
|
from: '—',
|
|
@@ -335,7 +334,7 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
335
334
|
id: 'rq-' + q.key,
|
|
336
335
|
kind: 'rm',
|
|
337
336
|
sign: '−',
|
|
338
|
-
tag:
|
|
337
|
+
tag: msg.value.diff.tagRemoved,
|
|
339
338
|
label: quotaLabel(q.key),
|
|
340
339
|
key: q.key,
|
|
341
340
|
from: `${q.value} ${u}`.trim(),
|
|
@@ -347,8 +346,8 @@ const diffRows = computed<DiffRow[]>(() => {
|
|
|
347
346
|
id: 'price',
|
|
348
347
|
kind: 'mod',
|
|
349
348
|
sign: '~',
|
|
350
|
-
tag:
|
|
351
|
-
label:
|
|
349
|
+
tag: msg.value.diff.tagChanged,
|
|
350
|
+
label: msg.value.diff.priceLabel,
|
|
352
351
|
key: 'pricing',
|
|
353
352
|
from: `${formatMoney(predecessor.value.monthlyNet)} / ${formatMoney(predecessor.value.yearlyNet)}`,
|
|
354
353
|
to: `${formatMoney(selectedVersion.value.monthlyNet)} / ${formatMoney(selectedVersion.value.yearlyNet)}`,
|
|
@@ -375,7 +374,7 @@ function formatDate(iso: string | null | undefined): string {
|
|
|
375
374
|
if (!iso) return '—';
|
|
376
375
|
const d = new Date(iso);
|
|
377
376
|
if (Number.isNaN(d.getTime())) return iso;
|
|
378
|
-
return d.toLocaleDateString(
|
|
377
|
+
return d.toLocaleDateString(intlLocale.value, {
|
|
379
378
|
day: '2-digit',
|
|
380
379
|
month: '2-digit',
|
|
381
380
|
year: 'numeric',
|
|
@@ -401,17 +400,16 @@ async function executeTerminate(): Promise<void> {
|
|
|
401
400
|
const e = err as { status?: number; body?: { code?: string; message?: string } };
|
|
402
401
|
const code = e?.body?.code;
|
|
403
402
|
if (code === 'PLAN_TERMINATE_DATE_NOT_FUTURE') {
|
|
404
|
-
terminateError.value =
|
|
403
|
+
terminateError.value = msg.value.terminateDialog.errorDateNotFuture;
|
|
405
404
|
} else if (code === 'PLAN_VERSION_NOT_LIVE') {
|
|
406
|
-
terminateError.value =
|
|
407
|
-
'Diese Version ist nicht live (draft oder superseded) und kann nicht terminiert werden.';
|
|
405
|
+
terminateError.value = msg.value.terminateDialog.errorVersionNotLive;
|
|
408
406
|
} else if (code === 'PLAN_TERMINATE_NOT_IMPLEMENTED') {
|
|
409
|
-
terminateError.value =
|
|
410
|
-
'Backend unterstützt Terminate noch nicht — bitte API-Server neu bauen.';
|
|
407
|
+
terminateError.value = msg.value.terminateDialog.errorNotImplemented;
|
|
411
408
|
} else if (e?.body?.message) {
|
|
412
409
|
terminateError.value = e.body.message;
|
|
413
410
|
} else {
|
|
414
|
-
terminateError.value =
|
|
411
|
+
terminateError.value =
|
|
412
|
+
err instanceof Error ? err.message : msg.value.terminateDialog.errorFailed;
|
|
415
413
|
}
|
|
416
414
|
} finally {
|
|
417
415
|
terminating.value = false;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
@keydown.escape="cancelName"
|
|
14
14
|
@blur="commitName"
|
|
15
15
|
/>
|
|
16
|
-
<span class="pd-title-hint">
|
|
16
|
+
<span class="pd-title-hint">{{ msg.header.nameEditHint }}</span>
|
|
17
17
|
</template>
|
|
18
18
|
<template v-else>
|
|
19
19
|
<h1 class="pd-title">{{ plan.label }}</h1>
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
v-if="draftVersion"
|
|
22
22
|
class="pd-title-edit-btn"
|
|
23
23
|
type="button"
|
|
24
|
-
title="
|
|
25
|
-
aria-label="
|
|
24
|
+
:title="msg.header.editNameTitle"
|
|
25
|
+
:aria-label="msg.header.editNameAria"
|
|
26
26
|
@click="startEditName"
|
|
27
27
|
>
|
|
28
28
|
<svg
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
</button>
|
|
41
41
|
</template>
|
|
42
42
|
</div>
|
|
43
|
-
<div class="pd-desc">{{ plan.description ||
|
|
43
|
+
<div class="pd-desc">{{ plan.description || msg.header.noDescription }}</div>
|
|
44
44
|
</div>
|
|
45
45
|
</div>
|
|
46
46
|
<div class="pd-actions">
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
<path d="M5 12h14M13 5l7 7-7 7" />
|
|
58
58
|
</svg>
|
|
59
59
|
</span>
|
|
60
|
-
<span>
|
|
60
|
+
<span>{{ common.back }}</span>
|
|
61
61
|
</button>
|
|
62
62
|
<button
|
|
63
63
|
v-if="tenantTotal === 0 && !draftVersion && publishedCount === 0"
|
|
64
64
|
class="btn danger"
|
|
65
65
|
type="button"
|
|
66
|
-
title="
|
|
66
|
+
:title="msg.header.deletePlanTitle"
|
|
67
67
|
@click="$emit('deletePlan')"
|
|
68
68
|
>
|
|
69
69
|
<svg
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"
|
|
79
79
|
/>
|
|
80
80
|
</svg>
|
|
81
|
-
<span>
|
|
81
|
+
<span>{{ msg.header.deletePlan }}</span>
|
|
82
82
|
</button>
|
|
83
83
|
<button class="btn" type="button" @click="$emit('clonePlan')">
|
|
84
84
|
<svg
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<rect x="9" y="9" width="11" height="11" rx="2" />
|
|
93
93
|
<path d="M5 15V5a2 2 0 012-2h10" />
|
|
94
94
|
</svg>
|
|
95
|
-
<span>
|
|
95
|
+
<span>{{ msg.header.clonePlan }}</span>
|
|
96
96
|
</button>
|
|
97
97
|
<button
|
|
98
98
|
v-if="!draftVersion"
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
>
|
|
111
111
|
<path d="M12 5v14M5 12h14" />
|
|
112
112
|
</svg>
|
|
113
|
-
<span>
|
|
113
|
+
<span>{{ msg.header.newDraftVersion }}</span>
|
|
114
114
|
</button>
|
|
115
115
|
<button
|
|
116
116
|
v-else
|
|
@@ -128,15 +128,17 @@
|
|
|
128
128
|
>
|
|
129
129
|
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />
|
|
130
130
|
</svg>
|
|
131
|
-
<span>
|
|
131
|
+
<span>{{ publishDraftLabel }}</span>
|
|
132
132
|
</button>
|
|
133
133
|
</div>
|
|
134
134
|
</div>
|
|
135
135
|
</template>
|
|
136
136
|
|
|
137
137
|
<script setup lang="ts">
|
|
138
|
-
import { nextTick, ref, watch } from 'vue';
|
|
138
|
+
import { computed, nextTick, ref, watch } from 'vue';
|
|
139
139
|
import type { PlanRow, PlanVersionRow } from '@saasicat/types';
|
|
140
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
141
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
140
142
|
|
|
141
143
|
const props = defineProps<{
|
|
142
144
|
plan: PlanRow;
|
|
@@ -154,6 +156,13 @@ const emit = defineEmits<{
|
|
|
154
156
|
(e: 'updatePlan', patch: { label: string }): void;
|
|
155
157
|
}>();
|
|
156
158
|
|
|
159
|
+
const msg = useSaMessages('planDetail');
|
|
160
|
+
const common = useSaMessages('common');
|
|
161
|
+
|
|
162
|
+
const publishDraftLabel = computed(() =>
|
|
163
|
+
formatMessage(msg.value.header.publishDraft, { version: props.draftVersion?.version ?? '' }),
|
|
164
|
+
);
|
|
165
|
+
|
|
157
166
|
const editingName = ref(false);
|
|
158
167
|
const nameDraft = ref(props.plan.label);
|
|
159
168
|
const nameInput = ref<HTMLInputElement | null>(null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="pd-kpis">
|
|
3
3
|
<div class="pd-kpi">
|
|
4
|
-
<div class="pd-kpi-label">
|
|
4
|
+
<div class="pd-kpi-label">{{ msg.kpis.activeVersion }}</div>
|
|
5
5
|
<div class="pd-kpi-big">
|
|
6
6
|
<template v-if="liveVersion">
|
|
7
7
|
v{{ liveVersion.version }}
|
|
@@ -9,49 +9,62 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
<template v-else>—</template>
|
|
11
11
|
</div>
|
|
12
|
-
<div class="pd-kpi-sub">
|
|
13
|
-
{{
|
|
14
|
-
liveVersion?.validFrom
|
|
15
|
-
? `seit ${liveVersion.validFrom.slice(0, 10)}`
|
|
16
|
-
: 'keine veröffentlichte Version'
|
|
17
|
-
}}
|
|
18
|
-
</div>
|
|
12
|
+
<div class="pd-kpi-sub">{{ activeVersionSub }}</div>
|
|
19
13
|
</div>
|
|
20
14
|
|
|
21
15
|
<div class="pd-kpi">
|
|
22
|
-
<div class="pd-kpi-label">
|
|
16
|
+
<div class="pd-kpi-label">{{ msg.kpis.tenantImpact }}</div>
|
|
23
17
|
<div class="pd-kpi-big">{{ tenantTotal }}</div>
|
|
24
|
-
<div class="pd-kpi-sub">
|
|
18
|
+
<div class="pd-kpi-sub">{{ msg.kpis.tenantsOnPlan }}</div>
|
|
25
19
|
</div>
|
|
26
20
|
|
|
27
21
|
<div class="pd-kpi">
|
|
28
|
-
<div class="pd-kpi-label">
|
|
22
|
+
<div class="pd-kpi-label">{{ msg.kpis.versions }}</div>
|
|
29
23
|
<div class="pd-kpi-big">{{ versionCount }}</div>
|
|
30
|
-
<div class="pd-kpi-sub">
|
|
31
|
-
{{ publishedCount }} live/superseded{{ draftVersion ? ' · 1 Draft' : '' }}
|
|
32
|
-
</div>
|
|
24
|
+
<div class="pd-kpi-sub">{{ versionsSummary }}</div>
|
|
33
25
|
</div>
|
|
34
26
|
|
|
35
27
|
<div :class="['pd-kpi', draftVersion ? 'draft' : '']">
|
|
36
|
-
<div class="pd-kpi-label">
|
|
28
|
+
<div class="pd-kpi-label">{{ msg.kpis.openDraft }}</div>
|
|
37
29
|
<div class="pd-kpi-big" :style="draftVersion ? '' : 'color:#cbd5e1'">
|
|
38
30
|
{{ draftVersion ? `v${draftVersion.version}` : '—' }}
|
|
39
31
|
</div>
|
|
40
32
|
<div class="pd-kpi-sub">
|
|
41
|
-
{{ draftVersion ?
|
|
33
|
+
{{ draftVersion ? msg.kpis.readyToEdit : msg.kpis.noOpenDraft }}
|
|
42
34
|
</div>
|
|
43
35
|
</div>
|
|
44
36
|
</div>
|
|
45
37
|
</template>
|
|
46
38
|
|
|
47
39
|
<script setup lang="ts">
|
|
40
|
+
import { computed } from 'vue';
|
|
48
41
|
import type { PlanVersionRow } from '@saasicat/types';
|
|
42
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
43
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
49
44
|
|
|
50
|
-
defineProps<{
|
|
45
|
+
const props = defineProps<{
|
|
51
46
|
liveVersion: PlanVersionRow | null;
|
|
52
47
|
draftVersion: PlanVersionRow | null;
|
|
53
48
|
tenantTotal: number;
|
|
54
49
|
versionCount: number;
|
|
55
50
|
publishedCount: number;
|
|
56
51
|
}>();
|
|
52
|
+
|
|
53
|
+
const msg = useSaMessages('planDetail');
|
|
54
|
+
|
|
55
|
+
const activeVersionSub = computed(() => {
|
|
56
|
+
const validFrom = props.liveVersion?.validFrom;
|
|
57
|
+
return validFrom
|
|
58
|
+
? formatMessage(msg.value.kpis.activeSince, { date: validFrom.slice(0, 10) })
|
|
59
|
+
: msg.value.kpis.noPublishedVersion;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const versionsSummary = computed(() =>
|
|
63
|
+
props.draftVersion
|
|
64
|
+
? formatMessage(msg.value.kpis.versionsSummaryWithDrafts, {
|
|
65
|
+
published: props.publishedCount,
|
|
66
|
+
drafts: 1,
|
|
67
|
+
})
|
|
68
|
+
: formatMessage(msg.value.kpis.versionsSummary, { published: props.publishedCount }),
|
|
69
|
+
);
|
|
57
70
|
</script>
|
|
@@ -7,17 +7,20 @@
|
|
|
7
7
|
<q-card style="min-width: 420px">
|
|
8
8
|
<q-card-section>
|
|
9
9
|
<div class="text-h6">
|
|
10
|
-
{{
|
|
10
|
+
{{
|
|
11
|
+
target?.endsAt
|
|
12
|
+
? msg.terminateDialog.titleChangeEndDate
|
|
13
|
+
: msg.terminateDialog.titleTerminate
|
|
14
|
+
}}
|
|
11
15
|
</div>
|
|
12
16
|
<div class="text-body2 q-mt-sm">
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
ab diesem Datum nicht mehr möglich.
|
|
17
|
+
{{ msg.terminateDialog.bodyPlanPrefix }} <code>{{ plan.planKey }}</code>
|
|
18
|
+
{{ bodyExpiry }} <b>{{ msg.terminateDialog.bodyWithout }}</b>
|
|
19
|
+
{{ msg.terminateDialog.bodySuffix }}
|
|
17
20
|
</div>
|
|
18
21
|
<q-input
|
|
19
22
|
:model-value="dateInput"
|
|
20
|
-
label="
|
|
23
|
+
:label="msg.terminateDialog.dateLabel"
|
|
21
24
|
type="text"
|
|
22
25
|
class="q-mt-md"
|
|
23
26
|
mask="####-##-##"
|
|
@@ -43,10 +46,10 @@
|
|
|
43
46
|
{{ error }}
|
|
44
47
|
</q-banner>
|
|
45
48
|
<q-card-actions align="right">
|
|
46
|
-
<q-btn flat label="
|
|
49
|
+
<q-btn flat :label="common.cancel" @click="$emit('update:modelValue', false)" />
|
|
47
50
|
<q-btn
|
|
48
51
|
color="primary"
|
|
49
|
-
label="
|
|
52
|
+
:label="msg.terminateDialog.submit"
|
|
50
53
|
:loading="terminating"
|
|
51
54
|
:disable="!dateInput"
|
|
52
55
|
@click="$emit('execute')"
|
|
@@ -57,9 +60,12 @@
|
|
|
57
60
|
</template>
|
|
58
61
|
|
|
59
62
|
<script setup lang="ts">
|
|
63
|
+
import { computed } from 'vue';
|
|
60
64
|
import type { PlanRow, PlanVersionRow } from '@saasicat/types';
|
|
65
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
66
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
61
67
|
|
|
62
|
-
defineProps<{
|
|
68
|
+
const props = defineProps<{
|
|
63
69
|
modelValue: boolean;
|
|
64
70
|
plan: PlanRow;
|
|
65
71
|
target: PlanVersionRow | null;
|
|
@@ -68,6 +74,13 @@ defineProps<{
|
|
|
68
74
|
terminating: boolean;
|
|
69
75
|
}>();
|
|
70
76
|
|
|
77
|
+
const msg = useSaMessages('planDetail');
|
|
78
|
+
const common = useSaMessages('common');
|
|
79
|
+
|
|
80
|
+
const bodyExpiry = computed(() =>
|
|
81
|
+
formatMessage(msg.value.terminateDialog.bodyExpiry, { version: props.target?.version ?? '' }),
|
|
82
|
+
);
|
|
83
|
+
|
|
71
84
|
defineEmits<{
|
|
72
85
|
(e: 'update:modelValue', value: boolean): void;
|
|
73
86
|
(e: 'update:dateInput', value: string): void;
|
|
@@ -2,22 +2,8 @@
|
|
|
2
2
|
<section class="pd-panel">
|
|
3
3
|
<div class="pd-panel-head">
|
|
4
4
|
<div style="min-width: 0">
|
|
5
|
-
<h3 class="pd-panel-title">
|
|
6
|
-
|
|
7
|
-
Diff v{{ predecessor.version }} → v{{ selectedVersion?.version }}
|
|
8
|
-
</template>
|
|
9
|
-
<template v-else>Komponenten · v{{ selectedVersion?.version }}</template>
|
|
10
|
-
</h3>
|
|
11
|
-
<div class="pd-panel-sub">
|
|
12
|
-
<template v-if="predecessor && selectedVersion">
|
|
13
|
-
{{
|
|
14
|
-
statusOf(selectedVersion) === 'draft'
|
|
15
|
-
? 'Was sich beim Publish ändert'
|
|
16
|
-
: `Änderungen v${predecessor.version} → v${selectedVersion.version}`
|
|
17
|
-
}}
|
|
18
|
-
</template>
|
|
19
|
-
<template v-else>Initialversion · kein Vorgänger zum Vergleich</template>
|
|
20
|
-
</div>
|
|
5
|
+
<h3 class="pd-panel-title">{{ panelTitle }}</h3>
|
|
6
|
+
<div class="pd-panel-sub">{{ panelSubtitle }}</div>
|
|
21
7
|
</div>
|
|
22
8
|
<div class="pd-panel-head-right pd-diff-chips">
|
|
23
9
|
<template v-if="predecessor">
|
|
@@ -39,10 +25,10 @@
|
|
|
39
25
|
<span class="pd-diff-kind">
|
|
40
26
|
{{
|
|
41
27
|
d.kind === 'add'
|
|
42
|
-
?
|
|
28
|
+
? msg.diff.kindAdded
|
|
43
29
|
: d.kind === 'rm'
|
|
44
|
-
?
|
|
45
|
-
:
|
|
30
|
+
? msg.diff.kindRemoved
|
|
31
|
+
: msg.diff.kindChanged
|
|
46
32
|
}}
|
|
47
33
|
</span>
|
|
48
34
|
<span class="pd-diff-label">{{ d.label }}</span>
|
|
@@ -56,8 +42,8 @@
|
|
|
56
42
|
</div>
|
|
57
43
|
</div>
|
|
58
44
|
<div v-if="diffRows.length === 0" class="pd-diff-empty">
|
|
59
|
-
<b>
|
|
60
|
-
|
|
45
|
+
<b>{{ common.noChanges }}</b>
|
|
46
|
+
{{ emptyText }}
|
|
61
47
|
</div>
|
|
62
48
|
</div>
|
|
63
49
|
|
|
@@ -66,13 +52,17 @@
|
|
|
66
52
|
v-if="selectedVersion.features.length === 0 && quotaCount(selectedVersion) === 0"
|
|
67
53
|
class="pd-diff-empty"
|
|
68
54
|
>
|
|
69
|
-
<b>
|
|
70
|
-
|
|
55
|
+
<b>{{ msg.diff.noComponentsTitle }}</b>
|
|
56
|
+
{{ msg.diff.noComponentsText }}
|
|
71
57
|
</div>
|
|
72
58
|
<template v-if="selectedVersion.features.length > 0">
|
|
73
59
|
<div class="pd-diff-section">
|
|
74
60
|
<hr />
|
|
75
|
-
<span>
|
|
61
|
+
<span>{{
|
|
62
|
+
formatMessage(msg.diff.sectionFeatures, {
|
|
63
|
+
count: selectedVersion.features.length,
|
|
64
|
+
})
|
|
65
|
+
}}</span>
|
|
76
66
|
<hr />
|
|
77
67
|
</div>
|
|
78
68
|
<div
|
|
@@ -90,7 +80,11 @@
|
|
|
90
80
|
<template v-if="quotaCount(selectedVersion) > 0">
|
|
91
81
|
<div class="pd-diff-section">
|
|
92
82
|
<hr />
|
|
93
|
-
<span>
|
|
83
|
+
<span>{{
|
|
84
|
+
formatMessage(msg.diff.sectionQuotas, {
|
|
85
|
+
count: quotaCount(selectedVersion),
|
|
86
|
+
})
|
|
87
|
+
}}</span>
|
|
94
88
|
<hr />
|
|
95
89
|
</div>
|
|
96
90
|
<div
|
|
@@ -109,7 +103,11 @@
|
|
|
109
103
|
<template v-if="(selectedVersion.bundles ?? []).length > 0">
|
|
110
104
|
<div class="pd-diff-section">
|
|
111
105
|
<hr />
|
|
112
|
-
<span>
|
|
106
|
+
<span>{{
|
|
107
|
+
formatMessage(msg.diff.sectionBundles, {
|
|
108
|
+
count: (selectedVersion.bundles ?? []).length,
|
|
109
|
+
})
|
|
110
|
+
}}</span>
|
|
113
111
|
<hr />
|
|
114
112
|
</div>
|
|
115
113
|
<div
|
|
@@ -129,10 +127,13 @@
|
|
|
129
127
|
</template>
|
|
130
128
|
|
|
131
129
|
<script setup lang="ts">
|
|
130
|
+
import { computed } from 'vue';
|
|
132
131
|
import type { PlanVersionRow } from '@saasicat/types';
|
|
132
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
133
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
133
134
|
import type { DiffRow, PlanVersionDiff, StatusOf } from './types.js';
|
|
134
135
|
|
|
135
|
-
defineProps<{
|
|
136
|
+
const props = defineProps<{
|
|
136
137
|
selectedVersion: PlanVersionRow | null;
|
|
137
138
|
predecessor: PlanVersionRow | null;
|
|
138
139
|
diff: PlanVersionDiff;
|
|
@@ -146,4 +147,37 @@ defineProps<{
|
|
|
146
147
|
quotaUnit: (key: string) => string;
|
|
147
148
|
bundleLabel: (key: string) => string;
|
|
148
149
|
}>();
|
|
150
|
+
|
|
151
|
+
const msg = useSaMessages('planDetail');
|
|
152
|
+
const common = useSaMessages('common');
|
|
153
|
+
|
|
154
|
+
const panelTitle = computed(() =>
|
|
155
|
+
props.predecessor
|
|
156
|
+
? formatMessage(msg.value.diff.titleCompare, {
|
|
157
|
+
from: props.predecessor.version,
|
|
158
|
+
to: props.selectedVersion?.version ?? '',
|
|
159
|
+
})
|
|
160
|
+
: formatMessage(msg.value.diff.titleComponents, {
|
|
161
|
+
version: props.selectedVersion?.version ?? '',
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const panelSubtitle = computed(() => {
|
|
166
|
+
const predecessor = props.predecessor;
|
|
167
|
+
const selected = props.selectedVersion;
|
|
168
|
+
if (!predecessor || !selected) return msg.value.diff.subInitialVersion;
|
|
169
|
+
return props.statusOf(selected) === 'draft'
|
|
170
|
+
? msg.value.diff.subOnPublish
|
|
171
|
+
: formatMessage(msg.value.diff.subChanges, {
|
|
172
|
+
from: predecessor.version,
|
|
173
|
+
to: selected.version,
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const emptyText = computed(() =>
|
|
178
|
+
formatMessage(msg.value.diff.emptyText, {
|
|
179
|
+
selected: props.selectedVersion?.version ?? '',
|
|
180
|
+
predecessor: props.predecessor?.version ?? '',
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
149
183
|
</script>
|