@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
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
class="sa-pv-header__cmp-btn"
|
|
16
16
|
@click="emit('clearCompare')"
|
|
17
17
|
>
|
|
18
|
-
<q-icon name="close" size="14px" />
|
|
18
|
+
<q-icon name="close" size="14px" /> {{ msg.compareEnd }}
|
|
19
19
|
</button>
|
|
20
20
|
</template>
|
|
21
21
|
</div>
|
|
@@ -28,23 +28,21 @@
|
|
|
28
28
|
class="sa-pv-header__meta-item sa-pv-header__meta-item--ok"
|
|
29
29
|
>
|
|
30
30
|
<q-icon name="rocket_launch" size="14px" />
|
|
31
|
-
|
|
31
|
+
{{ publishedOnLabel }}
|
|
32
32
|
</span>
|
|
33
33
|
<span
|
|
34
34
|
v-if="snapshot.kind === 'drafts'"
|
|
35
35
|
class="sa-pv-header__meta-item sa-pv-header__meta-item--warn"
|
|
36
36
|
>
|
|
37
37
|
<q-icon name="edit_note" size="14px" />
|
|
38
|
-
<strong>{{ snapshot.draftCount }}</strong>
|
|
38
|
+
<strong>{{ snapshot.draftCount }}</strong> {{ msg.header.openDrafts }}
|
|
39
39
|
</span>
|
|
40
40
|
<span
|
|
41
41
|
v-if="snapshot.regressionCount > 0"
|
|
42
42
|
class="sa-pv-header__meta-item sa-pv-header__meta-item--bad"
|
|
43
43
|
>
|
|
44
44
|
<q-icon name="trending_down" size="14px" />
|
|
45
|
-
<strong>{{ snapshot.regressionCount }}</strong>
|
|
46
|
-
snapshot.regressionCount === 1 ? '' : 'en'
|
|
47
|
-
}}
|
|
45
|
+
<strong>{{ snapshot.regressionCount }}</strong> {{ regressionLabel }}
|
|
48
46
|
</span>
|
|
49
47
|
</div>
|
|
50
48
|
</div>
|
|
@@ -57,7 +55,7 @@
|
|
|
57
55
|
@click="emit('publish')"
|
|
58
56
|
>
|
|
59
57
|
<q-icon name="rocket_launch" size="16px" />
|
|
60
|
-
|
|
58
|
+
{{ msg.header.startPublishFlow }}
|
|
61
59
|
</button>
|
|
62
60
|
</div>
|
|
63
61
|
</div>
|
|
@@ -68,7 +66,7 @@
|
|
|
68
66
|
:class="{ 'sa-pv-header__switcher--disabled': !!compareSnapshot }"
|
|
69
67
|
>
|
|
70
68
|
<button
|
|
71
|
-
v-for="m in
|
|
69
|
+
v-for="m in resolvedModes"
|
|
72
70
|
:key="m.id"
|
|
73
71
|
type="button"
|
|
74
72
|
class="sa-pv-header__mode-btn"
|
|
@@ -81,7 +79,7 @@
|
|
|
81
79
|
</div>
|
|
82
80
|
<span v-if="compareSnapshot" class="sa-pv-header__cmp-hint">
|
|
83
81
|
<q-icon name="compare_arrows" size="13px" />
|
|
84
|
-
|
|
82
|
+
{{ msg.header.compareModeHint }}
|
|
85
83
|
</span>
|
|
86
84
|
</div>
|
|
87
85
|
</header>
|
|
@@ -90,25 +88,19 @@
|
|
|
90
88
|
<script setup lang="ts">
|
|
91
89
|
import { computed } from 'vue';
|
|
92
90
|
import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
|
|
93
|
-
import {
|
|
91
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
92
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
93
|
+
import { formatDate } from './format.js';
|
|
94
94
|
import PlanVersionStatusBadge from './PlanVersionStatusBadge.vue';
|
|
95
95
|
import type { PlanVersionViewMode } from './types.js';
|
|
96
96
|
|
|
97
|
-
const props =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{
|
|
105
|
-
modes: () => [
|
|
106
|
-
{ id: 'list' as const, label: 'Plan-Liste', icon: 'list' },
|
|
107
|
-
{ id: 'matrix' as const, label: 'Feature-Matrix', icon: 'grid_view' },
|
|
108
|
-
{ id: 'audit' as const, label: 'Aktivität', icon: 'history' },
|
|
109
|
-
],
|
|
110
|
-
},
|
|
111
|
-
);
|
|
97
|
+
const props = defineProps<{
|
|
98
|
+
snapshot: CatalogSnapshot;
|
|
99
|
+
viewMode: PlanVersionViewMode;
|
|
100
|
+
compareSnapshot: CatalogSnapshot | null;
|
|
101
|
+
/** Overrides the localized default view switcher. */
|
|
102
|
+
modes?: ReadonlyArray<{ id: PlanVersionViewMode; label: string; icon: string }>;
|
|
103
|
+
}>();
|
|
112
104
|
|
|
113
105
|
const emit = defineEmits<{
|
|
114
106
|
(e: 'viewChange', mode: PlanVersionViewMode): void;
|
|
@@ -116,9 +108,33 @@ const emit = defineEmits<{
|
|
|
116
108
|
(e: 'clearCompare'): void;
|
|
117
109
|
}>();
|
|
118
110
|
|
|
111
|
+
const msg = useSaMessages('planVersions');
|
|
112
|
+
const { locale } = useSuperAdminI18n();
|
|
113
|
+
|
|
119
114
|
const canPublish = computed(
|
|
120
115
|
() => props.snapshot.kind === 'drafts' && props.snapshot.draftCount > 0,
|
|
121
116
|
);
|
|
117
|
+
|
|
118
|
+
const publishedOnLabel = computed(() =>
|
|
119
|
+
formatMessage(msg.value.header.publishedOn, {
|
|
120
|
+
date: formatDate(props.snapshot.publishedAt ?? undefined, locale.value),
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const regressionLabel = computed(() =>
|
|
125
|
+
props.snapshot.regressionCount === 1
|
|
126
|
+
? msg.value.header.regressionOne
|
|
127
|
+
: msg.value.header.regressionMany,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const resolvedModes = computed(
|
|
131
|
+
() =>
|
|
132
|
+
props.modes ?? [
|
|
133
|
+
{ id: 'list' as const, label: msg.value.header.modeList, icon: 'list' },
|
|
134
|
+
{ id: 'matrix' as const, label: msg.value.header.modeMatrix, icon: 'grid_view' },
|
|
135
|
+
{ id: 'audit' as const, label: msg.value.header.modeAudit, icon: 'history' },
|
|
136
|
+
],
|
|
137
|
+
);
|
|
122
138
|
</script>
|
|
123
139
|
|
|
124
140
|
<style scoped>
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
<div class="sa-pv-audit__card">
|
|
4
4
|
<header class="sa-pv-audit__head">
|
|
5
5
|
<q-icon name="history" size="18px" class="sa-pv-audit__head-icon" />
|
|
6
|
-
<h3>
|
|
7
|
-
<span class="sa-pv-audit__count">{{
|
|
6
|
+
<h3>{{ msg.audit.title }}</h3>
|
|
7
|
+
<span class="sa-pv-audit__count">{{ eventCountLabel }}</span>
|
|
8
8
|
<q-space />
|
|
9
9
|
<button v-if="!loading" type="button" class="sa-pv-audit__refresh" @click="reload">
|
|
10
|
-
<q-icon name="refresh" size="14px" />
|
|
10
|
+
<q-icon name="refresh" size="14px" /> {{ common.reload }}
|
|
11
11
|
</button>
|
|
12
12
|
</header>
|
|
13
13
|
<div v-if="loading" class="sa-pv-audit__loading">
|
|
14
|
-
<q-spinner size="20px" />
|
|
14
|
+
<q-spinner size="20px" /> {{ msg.audit.loading }}
|
|
15
15
|
</div>
|
|
16
16
|
<div v-else-if="events.length === 0" class="sa-pv-audit__empty">
|
|
17
|
-
|
|
17
|
+
{{ msg.audit.empty }}
|
|
18
18
|
</div>
|
|
19
19
|
<div v-else class="sa-pv-audit__list">
|
|
20
20
|
<div
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<div class="sa-pv-audit__meta">
|
|
43
43
|
<span
|
|
44
44
|
><q-icon name="schedule" size="12px" />
|
|
45
|
-
{{
|
|
45
|
+
{{ formatTimestamp(e.createdAt, locale) }}</span
|
|
46
46
|
>
|
|
47
47
|
<span v-if="actorEmail(e)">
|
|
48
48
|
<q-icon name="person" size="12px" /> {{ actorEmail(e) }}
|
|
@@ -56,9 +56,11 @@
|
|
|
56
56
|
</template>
|
|
57
57
|
|
|
58
58
|
<script setup lang="ts">
|
|
59
|
-
import { onMounted, ref, watch } from 'vue';
|
|
59
|
+
import { computed, onMounted, ref, watch } from 'vue';
|
|
60
60
|
import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
|
|
61
|
-
import {
|
|
61
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
62
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
63
|
+
import { formatTimestamp } from './format.js';
|
|
62
64
|
|
|
63
65
|
// PlanVersionsAudit — data-agnostic. Consumers pass in a `loadAudit` loader
|
|
64
66
|
// that supplies events; the component filters them to match the current
|
|
@@ -100,34 +102,49 @@ const props = withDefaults(
|
|
|
100
102
|
const loading = ref(false);
|
|
101
103
|
const events = ref<AuditRow[]>([]);
|
|
102
104
|
|
|
103
|
-
const
|
|
105
|
+
const msg = useSaMessages('planVersions');
|
|
106
|
+
const common = useSaMessages('common');
|
|
107
|
+
const { locale } = useSuperAdminI18n();
|
|
108
|
+
|
|
109
|
+
const eventCountLabel = computed(() =>
|
|
110
|
+
formatMessage(msg.value.audit.eventCount, { count: events.value.length }),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const ACTION_ICONS: Record<string, { icon: string; color: string }> = {
|
|
114
|
+
PLAN_VERSION_PUBLISH: { icon: 'rocket_launch', color: '#047857' },
|
|
115
|
+
PLAN_VERSION_DRAFT_CREATE: { icon: 'edit_note', color: '#b45309' },
|
|
116
|
+
PLAN_VERSION_DRAFT_UPDATE: { icon: 'edit', color: '#3f6bff' },
|
|
117
|
+
PLAN_VERSION_DRAFT_DELETE: { icon: 'delete', color: '#dc2626' },
|
|
118
|
+
PLAN_CATALOG_UPDATE: { icon: 'rocket_launch', color: '#047857' },
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const defaultActionMeta = computed<Record<string, ActionMeta>>(() => ({
|
|
104
122
|
PLAN_VERSION_PUBLISH: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
label: 'Plan publiziert',
|
|
123
|
+
...ACTION_ICONS.PLAN_VERSION_PUBLISH,
|
|
124
|
+
label: msg.value.audit.actionPlanPublished,
|
|
108
125
|
},
|
|
109
126
|
PLAN_VERSION_DRAFT_CREATE: {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
...ACTION_ICONS.PLAN_VERSION_DRAFT_CREATE,
|
|
128
|
+
label: msg.value.audit.actionPlanDraftCreated,
|
|
129
|
+
},
|
|
130
|
+
PLAN_VERSION_DRAFT_UPDATE: {
|
|
131
|
+
...ACTION_ICONS.PLAN_VERSION_DRAFT_UPDATE,
|
|
132
|
+
label: msg.value.audit.actionPlanDraftUpdated,
|
|
113
133
|
},
|
|
114
|
-
PLAN_VERSION_DRAFT_UPDATE: { icon: 'edit', color: '#3f6bff', label: 'Plan-Draft geändert' },
|
|
115
134
|
PLAN_VERSION_DRAFT_DELETE: {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
label: 'Plan-Draft gelöscht',
|
|
135
|
+
...ACTION_ICONS.PLAN_VERSION_DRAFT_DELETE,
|
|
136
|
+
label: msg.value.audit.actionPlanDraftDeleted,
|
|
119
137
|
},
|
|
120
138
|
PLAN_CATALOG_UPDATE: {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
label: 'Catalog publiziert',
|
|
139
|
+
...ACTION_ICONS.PLAN_CATALOG_UPDATE,
|
|
140
|
+
label: msg.value.audit.actionCatalogPublished,
|
|
124
141
|
},
|
|
125
|
-
};
|
|
142
|
+
}));
|
|
126
143
|
|
|
127
144
|
function meta(action: string): ActionMeta {
|
|
128
145
|
return (
|
|
129
146
|
props.actionMeta[action] ??
|
|
130
|
-
|
|
147
|
+
defaultActionMeta.value[action] ?? {
|
|
131
148
|
icon: 'circle',
|
|
132
149
|
color: '#64748b',
|
|
133
150
|
label: action,
|
|
@@ -156,8 +173,10 @@ function detail(e: AuditRow): string {
|
|
|
156
173
|
changes?: unknown;
|
|
157
174
|
};
|
|
158
175
|
if (c.changeNote) return c.changeNote;
|
|
159
|
-
if (c.nonRegressive === false) return
|
|
160
|
-
if (Array.isArray(c.changes))
|
|
176
|
+
if (c.nonRegressive === false) return msg.value.audit.detailRegression;
|
|
177
|
+
if (Array.isArray(c.changes)) {
|
|
178
|
+
return formatMessage(msg.value.audit.detailFieldsChanged, { count: c.changes.length });
|
|
179
|
+
}
|
|
161
180
|
return e.action;
|
|
162
181
|
}
|
|
163
182
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<q-icon name="compare_arrows" size="22px" color="white" />
|
|
6
6
|
</div>
|
|
7
7
|
<div>
|
|
8
|
-
<div class="sa-pv-diff__legend">
|
|
8
|
+
<div class="sa-pv-diff__legend">{{ msg.diff.legend }}</div>
|
|
9
9
|
<div class="sa-pv-diff__title">
|
|
10
10
|
{{ from.label }} <span class="sa-pv-diff__sep">→</span> {{ to.label }}
|
|
11
11
|
</div>
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
<div class="sa-pv-diff__spacer" />
|
|
14
14
|
<div class="sa-pv-diff__stats">
|
|
15
15
|
<div class="sa-pv-diff__stat">
|
|
16
|
-
<div class="sa-pv-diff__stat-label">
|
|
16
|
+
<div class="sa-pv-diff__stat-label">{{ msg.diff.plansChanged }}</div>
|
|
17
17
|
<div class="sa-pv-diff__stat-value sa-pv-diff__stat-value--warn">
|
|
18
18
|
{{ planChangedCount }}
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
<div v-if="regressionCount > 0" class="sa-pv-diff__stat">
|
|
22
|
-
<div class="sa-pv-diff__stat-label">
|
|
22
|
+
<div class="sa-pv-diff__stat-label">{{ msg.diff.regressions }}</div>
|
|
23
23
|
<div class="sa-pv-diff__stat-value sa-pv-diff__stat-value--bad">
|
|
24
24
|
{{ regressionCount }}
|
|
25
25
|
</div>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
|
-
<h2 class="sa-pv-diff__section">
|
|
30
|
+
<h2 class="sa-pv-diff__section">{{ msg.diff.sectionPlans }}</h2>
|
|
31
31
|
<PlanDiffCard
|
|
32
32
|
v-for="d in planDiffs"
|
|
33
33
|
:key="d.id"
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
:changes="d.changes"
|
|
39
39
|
:field-labels="fieldLabels"
|
|
40
40
|
/>
|
|
41
|
-
|
|
42
41
|
</div>
|
|
43
42
|
</template>
|
|
44
43
|
|
|
@@ -46,6 +45,7 @@
|
|
|
46
45
|
import { computed } from 'vue';
|
|
47
46
|
import type { VersionChange } from '@saasicat/types';
|
|
48
47
|
import type { CatalogSnapshot, ResolvedPlan } from '../../client/plan-versions-catalog.js';
|
|
48
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
49
49
|
import PlanDiffCard from './PlanDiffCard.vue';
|
|
50
50
|
|
|
51
51
|
interface SnapshotEntityDiff {
|
|
@@ -64,6 +64,8 @@ const props = defineProps<{
|
|
|
64
64
|
fieldLabels?: Record<string, string>;
|
|
65
65
|
}>();
|
|
66
66
|
|
|
67
|
+
const msg = useSaMessages('planVersions');
|
|
68
|
+
|
|
67
69
|
function planAccent(planId: string): string {
|
|
68
70
|
return props.planAccents?.[planId] ?? '#3f6bff';
|
|
69
71
|
}
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="sa-pv-list">
|
|
3
3
|
<div class="sa-pv-list__kpis">
|
|
4
|
-
<PlanVersionsKpi label="Pakete" :value="snapshot.plans.length" icon="inventory_2" />
|
|
5
4
|
<PlanVersionsKpi
|
|
6
|
-
label="
|
|
5
|
+
:label="msg.list.kpiPlans"
|
|
6
|
+
:value="snapshot.plans.length"
|
|
7
|
+
icon="inventory_2"
|
|
8
|
+
/>
|
|
9
|
+
<PlanVersionsKpi
|
|
10
|
+
:label="msg.list.kpiSelfService"
|
|
7
11
|
:value="marketedCount"
|
|
8
12
|
icon="storefront"
|
|
9
|
-
:sub="
|
|
13
|
+
:sub="totalPlansLabel"
|
|
14
|
+
/>
|
|
15
|
+
<PlanVersionsKpi
|
|
16
|
+
:label="msg.list.kpiFeaturesTotal"
|
|
17
|
+
:value="totalFeatures"
|
|
18
|
+
icon="extension"
|
|
10
19
|
/>
|
|
11
|
-
<PlanVersionsKpi label="Features gesamt" :value="totalFeatures" icon="extension" />
|
|
12
20
|
</div>
|
|
13
21
|
|
|
14
22
|
<div v-if="missingPlans.length > 0" class="sa-pv-list__missing">
|
|
15
23
|
<q-icon name="info" size="16px" />
|
|
16
24
|
<div>
|
|
17
|
-
<strong>
|
|
18
|
-
|
|
25
|
+
<strong>{{ msg.list.missingPlansLabel }}</strong> {{ missingPlans.join(', ') }}
|
|
26
|
+
{{ msg.list.missingPlansHint }}
|
|
19
27
|
<template v-if="canEdit">
|
|
20
28
|
<button
|
|
21
29
|
v-for="planId in missingPlans"
|
|
@@ -24,7 +32,7 @@
|
|
|
24
32
|
class="sa-pv-list__missing-btn"
|
|
25
33
|
@click="emit('createPlanDraft', planId)"
|
|
26
34
|
>
|
|
27
|
-
|
|
35
|
+
{{ createDraftLabel(planId) }}
|
|
28
36
|
</button>
|
|
29
37
|
</template>
|
|
30
38
|
</div>
|
|
@@ -36,8 +44,8 @@
|
|
|
36
44
|
class="sa-pv-list__head sa-pv-list__row sa-pv-list__row--default"
|
|
37
45
|
:style="rowGridStyle"
|
|
38
46
|
>
|
|
39
|
-
<div>
|
|
40
|
-
<div class="sa-pv-list__th--num">
|
|
47
|
+
<div>{{ msg.list.colPlan }}</div>
|
|
48
|
+
<div class="sa-pv-list__th--num">{{ msg.list.colPriceNet }}</div>
|
|
41
49
|
<div
|
|
42
50
|
v-for="col in quotaColumns"
|
|
43
51
|
:key="`hd-${col.key}`"
|
|
@@ -45,7 +53,7 @@
|
|
|
45
53
|
>
|
|
46
54
|
{{ col.label }}
|
|
47
55
|
</div>
|
|
48
|
-
<div class="sa-pv-list__th--num">
|
|
56
|
+
<div class="sa-pv-list__th--num">{{ msg.list.colFeatures }}</div>
|
|
49
57
|
</div>
|
|
50
58
|
</slot>
|
|
51
59
|
|
|
@@ -65,7 +73,9 @@
|
|
|
65
73
|
<div class="sa-pv-list__default-name">
|
|
66
74
|
<strong>{{ plan.planId }}</strong>
|
|
67
75
|
<span class="sa-pv-list__default-version">v{{ plan.version }}</span>
|
|
68
|
-
<span v-if="plan.isDraft" class="sa-pv-list__default-chip">
|
|
76
|
+
<span v-if="plan.isDraft" class="sa-pv-list__default-chip">{{
|
|
77
|
+
msg.status.draft
|
|
78
|
+
}}</span>
|
|
69
79
|
</div>
|
|
70
80
|
<div class="sa-pv-list__th--num">
|
|
71
81
|
{{ formatEuro(plan.monthlyNet) }}
|
|
@@ -86,10 +96,10 @@
|
|
|
86
96
|
<div v-if="snapshot.kind === 'drafts'" class="sa-pv-list__draft-hint">
|
|
87
97
|
<q-icon name="info" size="18px" />
|
|
88
98
|
<div>
|
|
89
|
-
<strong>
|
|
90
|
-
|
|
91
|
-
<strong>
|
|
92
|
-
|
|
99
|
+
<strong>{{ msg.list.draftHintLabel }}</strong> {{ msg.list.draftHintBefore }}
|
|
100
|
+
<em>{{ msg.list.draftHintEditButton }}</em> {{ msg.list.draftHintMiddle }}
|
|
101
|
+
<strong>{{ msg.list.draftHintPublishFlow }}</strong>
|
|
102
|
+
{{ msg.list.draftHintAfter }}
|
|
93
103
|
</div>
|
|
94
104
|
</div>
|
|
95
105
|
</div>
|
|
@@ -98,6 +108,8 @@
|
|
|
98
108
|
<script setup lang="ts">
|
|
99
109
|
import { computed, ref } from 'vue';
|
|
100
110
|
import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
|
|
111
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
112
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
101
113
|
import PlanVersionsKpi from './PlanVersionsKpi.vue';
|
|
102
114
|
import { fmtEuro } from './format.js';
|
|
103
115
|
|
|
@@ -136,9 +148,16 @@ const emit = defineEmits<{
|
|
|
136
148
|
(e: 'createPlanDraft', planId: string): void;
|
|
137
149
|
}>();
|
|
138
150
|
|
|
151
|
+
const msg = useSaMessages('planVersions');
|
|
152
|
+
const { locale } = useSuperAdminI18n();
|
|
153
|
+
|
|
139
154
|
const openId = ref<string | null>(null);
|
|
140
155
|
const canEdit = computed(() => props.snapshot.kind === 'drafts');
|
|
141
156
|
|
|
157
|
+
const totalPlansLabel = computed(() =>
|
|
158
|
+
formatMessage(msg.value.list.kpiOfTotal, { count: props.snapshot.plans.length }),
|
|
159
|
+
);
|
|
160
|
+
|
|
142
161
|
const marketedCount = computed(() => props.snapshot.plans.filter((p) => p.marketed).length);
|
|
143
162
|
const totalFeatures = computed(() => new Set(props.snapshot.plans.flatMap((p) => p.features)).size);
|
|
144
163
|
|
|
@@ -163,8 +182,12 @@ function onToggle(id: string): void {
|
|
|
163
182
|
openId.value = openId.value === id ? null : id;
|
|
164
183
|
}
|
|
165
184
|
|
|
185
|
+
function createDraftLabel(planId: string): string {
|
|
186
|
+
return formatMessage(msg.value.list.createDraftFor, { planId });
|
|
187
|
+
}
|
|
188
|
+
|
|
166
189
|
function formatEuro(n: number): string {
|
|
167
|
-
return fmtEuro(n);
|
|
190
|
+
return fmtEuro(n, locale.value);
|
|
168
191
|
}
|
|
169
192
|
|
|
170
193
|
function formatQuotaValue(value: number | undefined, col: QuotaColumnConfig): string {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<aside class="sa-pv-timeline">
|
|
3
3
|
<div class="sa-pv-timeline__head">
|
|
4
4
|
<div class="sa-pv-timeline__row">
|
|
5
|
-
<div class="sa-pv-timeline__title">{{ title ??
|
|
5
|
+
<div class="sa-pv-timeline__title">{{ title ?? msg.timeline.title }}</div>
|
|
6
6
|
</div>
|
|
7
|
-
<div class="sa-pv-timeline__count">{{
|
|
7
|
+
<div class="sa-pv-timeline__count">{{ snapshotCountLabel }}</div>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<div class="sa-pv-timeline__list">
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
<div class="sa-pv-timeline__foot">
|
|
57
57
|
<div class="sa-pv-timeline__hint">
|
|
58
58
|
<q-icon name="info" size="13px" />
|
|
59
|
-
<span>
|
|
59
|
+
<span>{{ msg.timeline.compareHint }}</span>
|
|
60
60
|
</div>
|
|
61
61
|
<button
|
|
62
62
|
v-if="compareId"
|
|
@@ -64,17 +64,20 @@
|
|
|
64
64
|
class="sa-pv-timeline__clear-btn"
|
|
65
65
|
@click="emit('clearCompare')"
|
|
66
66
|
>
|
|
67
|
-
|
|
67
|
+
{{ msg.compareEnd }}
|
|
68
68
|
</button>
|
|
69
69
|
</div>
|
|
70
70
|
</aside>
|
|
71
71
|
</template>
|
|
72
72
|
|
|
73
73
|
<script setup lang="ts">
|
|
74
|
+
import { computed } from 'vue';
|
|
74
75
|
import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
|
|
75
|
-
import {
|
|
76
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
77
|
+
import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
78
|
+
import { formatRelative } from './format.js';
|
|
76
79
|
|
|
77
|
-
defineProps<{
|
|
80
|
+
const props = defineProps<{
|
|
78
81
|
snapshots: CatalogSnapshot[];
|
|
79
82
|
selectedId: string;
|
|
80
83
|
compareId: string | null;
|
|
@@ -87,18 +90,27 @@ const emit = defineEmits<{
|
|
|
87
90
|
(e: 'clearCompare'): void;
|
|
88
91
|
}>();
|
|
89
92
|
|
|
93
|
+
const msg = useSaMessages('planVersions');
|
|
94
|
+
const { locale } = useSuperAdminI18n();
|
|
95
|
+
|
|
96
|
+
const snapshotCountLabel = computed(() =>
|
|
97
|
+
formatMessage(msg.value.timeline.snapshotCount, { count: props.snapshots.length }),
|
|
98
|
+
);
|
|
99
|
+
|
|
90
100
|
function statusLabel(status: CatalogSnapshot['status']): string {
|
|
91
|
-
if (status === 'DRAFT') return
|
|
92
|
-
if (status === 'ACTIVE') return
|
|
93
|
-
return
|
|
101
|
+
if (status === 'DRAFT') return msg.value.status.draft;
|
|
102
|
+
if (status === 'ACTIVE') return msg.value.status.active;
|
|
103
|
+
return msg.value.status.archived;
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
function metaText(s: CatalogSnapshot): string {
|
|
97
107
|
if (s.kind === 'drafts') {
|
|
98
|
-
return s.draftCount === 0
|
|
108
|
+
return s.draftCount === 0
|
|
109
|
+
? msg.value.timeline.noOpenDrafts
|
|
110
|
+
: formatMessage(msg.value.timeline.openCount, { count: s.draftCount });
|
|
99
111
|
}
|
|
100
|
-
if (s.publishedAt) return
|
|
101
|
-
return
|
|
112
|
+
if (s.publishedAt) return formatRelative(s.publishedAt, locale.value);
|
|
113
|
+
return msg.value.timeline.unknown;
|
|
102
114
|
}
|
|
103
115
|
</script>
|
|
104
116
|
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
// Formatting helpers for the plan-versions views.
|
|
2
2
|
//
|
|
3
3
|
// Phase 2c: Ported from a consumer admin.
|
|
4
|
-
// The time reference point for `
|
|
4
|
+
// The time reference point for `formatRelative` is the moment of the call,
|
|
5
5
|
// not a hard-coded demo date (the ported template had `2026-05-04` —
|
|
6
6
|
// the platform must work in production).
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { formatCurrency } from '../../client/i18n/currency.js';
|
|
9
|
+
import { formatMessage } from '../../client/i18n/format.js';
|
|
10
|
+
import { DEFAULT_SA_LOCALE, SA_INTL_LOCALES, type SaLocale } from '../../client/i18n/locale.js';
|
|
11
|
+
import { planVersionsMessages } from '../../client/i18n/messages/plan-versions.js';
|
|
12
|
+
|
|
13
|
+
const EMPTY_VALUE = '—';
|
|
14
|
+
|
|
15
|
+
function texts(locale: SaLocale) {
|
|
16
|
+
return planVersionsMessages[locale].format;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function fmtEuro(n: number, locale: SaLocale = DEFAULT_SA_LOCALE): string {
|
|
20
|
+
if (n === 0) return texts(locale).priceIndividual;
|
|
21
|
+
return formatCurrency(n, locale);
|
|
11
22
|
}
|
|
12
23
|
|
|
13
24
|
export function fmtStorage(gb: number): string {
|
|
@@ -16,34 +27,39 @@ export function fmtStorage(gb: number): string {
|
|
|
16
27
|
return `${gb} GB`;
|
|
17
28
|
}
|
|
18
29
|
|
|
19
|
-
export function
|
|
20
|
-
|
|
30
|
+
export function formatRelative(
|
|
31
|
+
iso: string | undefined,
|
|
32
|
+
locale: SaLocale = DEFAULT_SA_LOCALE,
|
|
33
|
+
now: Date = new Date(),
|
|
34
|
+
): string {
|
|
35
|
+
if (!iso) return EMPTY_VALUE;
|
|
36
|
+
const msg = texts(locale);
|
|
21
37
|
const d = new Date(iso);
|
|
22
38
|
const diffMs = now.getTime() - d.getTime();
|
|
23
39
|
const days = Math.floor(diffMs / 86_400_000);
|
|
24
|
-
if (days === 0) return
|
|
25
|
-
if (days === 1) return
|
|
26
|
-
if (days < 7) return
|
|
40
|
+
if (days === 0) return msg.today;
|
|
41
|
+
if (days === 1) return msg.yesterday;
|
|
42
|
+
if (days < 7) return formatMessage(msg.daysAgo, { count: days });
|
|
27
43
|
if (days < 30) {
|
|
28
44
|
const w = Math.floor(days / 7);
|
|
29
|
-
return
|
|
45
|
+
return formatMessage(w > 1 ? msg.weeksAgoMany : msg.weeksAgoOne, { count: w });
|
|
30
46
|
}
|
|
31
|
-
if (days < 365) return
|
|
47
|
+
if (days < 365) return formatMessage(msg.monthsAgo, { count: Math.floor(days / 30) });
|
|
32
48
|
const y = Math.floor(days / 365);
|
|
33
|
-
return
|
|
49
|
+
return formatMessage(y > 1 ? msg.yearsAgoMany : msg.yearsAgoOne, { count: y });
|
|
34
50
|
}
|
|
35
51
|
|
|
36
|
-
export function
|
|
37
|
-
if (!iso) return
|
|
38
|
-
return new Date(iso).toLocaleDateString(
|
|
52
|
+
export function formatDate(iso: string | undefined, locale: SaLocale = DEFAULT_SA_LOCALE): string {
|
|
53
|
+
if (!iso) return EMPTY_VALUE;
|
|
54
|
+
return new Date(iso).toLocaleDateString(SA_INTL_LOCALES[locale], {
|
|
39
55
|
day: '2-digit',
|
|
40
56
|
month: 'short',
|
|
41
57
|
year: 'numeric',
|
|
42
58
|
});
|
|
43
59
|
}
|
|
44
60
|
|
|
45
|
-
export function
|
|
46
|
-
return new Date(iso).toLocaleString(
|
|
61
|
+
export function formatTimestamp(iso: string, locale: SaLocale = DEFAULT_SA_LOCALE): string {
|
|
62
|
+
return new Date(iso).toLocaleString(SA_INTL_LOCALES[locale], {
|
|
47
63
|
day: '2-digit',
|
|
48
64
|
month: 'short',
|
|
49
65
|
year: 'numeric',
|
|
@@ -6,25 +6,25 @@
|
|
|
6
6
|
>
|
|
7
7
|
<q-card style="min-width: 440px">
|
|
8
8
|
<q-card-section>
|
|
9
|
-
<div class="text-h6">
|
|
9
|
+
<div class="text-h6">{{ msg.archiveDialog.title }}</div>
|
|
10
10
|
<div class="text-body2 q-mt-sm">
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
{{ msg.archiveDialog.bodyLead }} <code>{{ target?.plan.planKey }}</code>
|
|
12
|
+
{{ msg.archiveDialog.bodyVerb }}
|
|
13
|
+
<b>{{ msg.archiveDialog.bodyEmphasis }}</b
|
|
14
|
+
>{{ msg.archiveDialog.bodyTail }}
|
|
14
15
|
</div>
|
|
15
16
|
<div class="text-caption text-grey-7 q-mt-sm">
|
|
16
|
-
|
|
17
|
-
gelöscht werden — das Backend würde 422 antworten.
|
|
17
|
+
{{ msg.archiveDialog.contractProtectionNote }}
|
|
18
18
|
</div>
|
|
19
19
|
</q-card-section>
|
|
20
20
|
<q-banner v-if="error" class="bg-warning q-mx-md q-mb-md" rounded>
|
|
21
21
|
{{ error }}
|
|
22
22
|
</q-banner>
|
|
23
23
|
<q-card-actions align="right">
|
|
24
|
-
<q-btn flat label="
|
|
24
|
+
<q-btn flat :label="common.cancel" @click="$emit('update:modelValue', false)" />
|
|
25
25
|
<q-btn
|
|
26
26
|
color="negative"
|
|
27
|
-
label="
|
|
27
|
+
:label="common.delete"
|
|
28
28
|
:loading="archiving"
|
|
29
29
|
@click="$emit('execute')"
|
|
30
30
|
/>
|
|
@@ -34,8 +34,12 @@
|
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
36
|
<script setup lang="ts">
|
|
37
|
+
import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
|
|
37
38
|
import type { PlanArchiveTarget } from './types.js';
|
|
38
39
|
|
|
40
|
+
const msg = useSaMessages('plans');
|
|
41
|
+
const common = useSaMessages('common');
|
|
42
|
+
|
|
39
43
|
defineProps<{
|
|
40
44
|
modelValue: boolean;
|
|
41
45
|
target: PlanArchiveTarget | null;
|