@saasicat/ui-vue 0.4.0 → 0.6.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 +64 -4
- package/dist/chunk-A3W2N26K.js +714 -0
- package/dist/chunk-QZOSDCNP.js +98 -0
- package/dist/chunk-X5SQ5HMB.js +3231 -0
- package/dist/client/index.cjs +3988 -0
- package/dist/client/index.d.cts +321 -0
- package/dist/client/index.d.ts +321 -0
- package/dist/client/index.js +70 -0
- package/dist/index.cjs +4446 -1249
- package/dist/index.d.cts +297 -888
- package/dist/index.d.ts +297 -888
- package/dist/index.js +609 -1348
- package/dist/messages-7b0P8W75.d.cts +1652 -0
- package/dist/messages-7b0P8W75.d.ts +1652 -0
- package/dist/quasar/index.cjs +3340 -0
- package/dist/quasar/index.d.cts +95 -0
- package/dist/quasar/index.d.ts +95 -0
- package/dist/quasar/index.js +96 -0
- package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
- package/dist/testing-e2e/admin-pages-suite.js +14 -11
- package/dist/use-super-admin-i18n-B3v3-SWZ.d.ts +210 -0
- package/dist/use-super-admin-i18n-DMktRVEt.d.cts +210 -0
- package/package.json +23 -3
- package/src/{action-registry.ts → client/action-registry.ts} +4 -4
- package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +4 -4
- package/src/{boot-loader.ts → 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 +27 -0
- package/src/{manifest-loader.ts → client/manifest-loader.ts} +4 -4
- package/src/{nav-builder.ts → client/nav-builder.ts} +44 -51
- package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +42 -30
- package/src/components/BundleVersionPublishDialog.vue +35 -24
- package/src/components/FeatureGate.vue +1 -1
- 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 +21 -10
- package/src/components/plan/PlanGrid.vue +2 -2
- package/src/components/plan/PriceSummary.vue +1 -1
- package/src/components/plan/PromoCodeInput.vue +1 -1
- package/src/components/plan/PublicBundleGrid.vue +1 -1
- 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 +82 -79
- package/src/pages-standard/AdminLayout.vue +43 -18
- 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 +31 -17
- package/src/pages-standard/DiscoveryPage.vue +40 -28
- package/src/pages-standard/EmailHistoryPage.vue +98 -69
- package/src/pages-standard/MarketingCatalogPage.vue +40 -21
- package/src/pages-standard/PilotsPage.vue +64 -52
- package/src/pages-standard/PlanVersionsPage.vue +9 -5
- package/src/pages-standard/PlansPage.vue +91 -59
- package/src/pages-standard/PlatformEmailPage.vue +120 -53
- package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
- package/src/pages-standard/PromoCodesPage.vue +51 -54
- package/src/pages-standard/SubscriptionsPage.vue +14 -9
- package/src/pages-standard/SuperAdminLoginPage.vue +19 -16
- package/src/pages-standard/SuperAdminSetupWizard.vue +53 -49
- package/src/pages-standard/TenantDetailPage.vue +54 -40
- package/src/pages-standard/TenantsPage.vue +57 -44
- package/src/pages-standard/UsersPage.vue +70 -52
- 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 +42 -26
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +46 -27
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +8 -6
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +40 -17
- package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +25 -13
- 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 +73 -38
- package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/PlanChangeWizard.vue +10 -6
- package/src/pages-tenant/TenantPlanSection.vue +20 -16
- package/src/pages-tenant/default-i18n.ts +217 -1
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +9 -7
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +11 -12
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
- package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
- package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
- package/src/quasar/create-super-admin-app.ts +192 -0
- package/src/quasar/index.ts +11 -0
- package/src/quasar/notify.ts +30 -0
- package/src/testing-e2e/admin-pages-suite.ts +14 -11
- package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
- package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
- package/src/{project-page-host.ts → vue/project-page-host.ts} +6 -4
- package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
- package/src/vue/ui-notify.ts +30 -0
- package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
- package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
- package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +3 -3
- package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
- package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +7 -5
- package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +7 -5
- package/src/{use-bundles.ts → vue/use-bundles.ts} +14 -14
- package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +14 -11
- package/src/{use-discovery.ts → vue/use-discovery.ts} +9 -6
- package/src/{use-entitlement.ts → vue/use-entitlement.ts} +4 -4
- package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +5 -5
- package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
- package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +10 -7
- package/src/{use-nav.ts → vue/use-nav.ts} +9 -3
- package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +2 -2
- package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +3 -3
- package/src/{use-plans.ts → vue/use-plans.ts} +13 -13
- package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +9 -6
- package/src/{use-promotions.ts → vue/use-promotions.ts} +10 -11
- package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
- package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +2 -3
- package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +5 -5
- package/src/vue/use-super-admin-i18n.ts +82 -0
- package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +12 -7
- package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
- package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
- package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +2 -4
- package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +5 -5
- package/src/{use-tenants.ts → vue/use-tenants.ts} +3 -3
- package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
- package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
- 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/use-business-types.ts +0 -269
- /package/src/{http-json.ts → client/http-json.ts} +0 -0
- /package/src/{types.ts → client/types.ts} +0 -0
- /package/src/{version.ts → client/version.ts} +0 -0
- /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
- /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
- /package/src/{feature-router-guard.ts → vue/feature-router-guard.ts} +0 -0
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
</template>
|
|
7
7
|
{{ error.message }}
|
|
8
8
|
<template #action>
|
|
9
|
-
<q-btn flat label="
|
|
9
|
+
<q-btn flat :label="common.reload" @click="load" />
|
|
10
10
|
</template>
|
|
11
11
|
</q-banner>
|
|
12
12
|
|
|
13
13
|
<div v-if="loading && plans.length === 0" class="sa-plans__loading">
|
|
14
14
|
<q-spinner size="32px" />
|
|
15
|
-
<span>
|
|
15
|
+
<span>{{ msg.page.loading }}</span>
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
18
|
<template v-else>
|
|
@@ -177,8 +177,11 @@ import {
|
|
|
177
177
|
usePlanVersions,
|
|
178
178
|
type UsePlansResult,
|
|
179
179
|
type UsePlanVersionsResult,
|
|
180
|
-
} from '../use-plans.js';
|
|
181
|
-
import type { HttpClient } from '../types.js';
|
|
180
|
+
} from '../vue/use-plans.js';
|
|
181
|
+
import type { HttpClient } from '../client/types.js';
|
|
182
|
+
import type { SaMessages } from '../client/i18n/index.js';
|
|
183
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
184
|
+
import { useSaMessages } from '../vue/use-super-admin-i18n.js';
|
|
182
185
|
import PlanVersionEditor from '../components/plan-version-editor/PlanVersionEditor.vue';
|
|
183
186
|
import PlanMatrix from '../components/plan-matrix/PlanMatrix.vue';
|
|
184
187
|
import PlanDetail from '../components/plan-detail/PlanDetail.vue';
|
|
@@ -247,6 +250,9 @@ const props = defineProps<{
|
|
|
247
250
|
loadPlanAudit?: (planId: string) => Promise<AuditRow[]>;
|
|
248
251
|
}>();
|
|
249
252
|
|
|
253
|
+
const msg = useSaMessages('plans');
|
|
254
|
+
const common = useSaMessages('common');
|
|
255
|
+
|
|
250
256
|
const composable: UsePlansResult = usePlans({
|
|
251
257
|
adminEndpoint: props.adminEndpoint,
|
|
252
258
|
projectKey: props.projectKey,
|
|
@@ -390,7 +396,7 @@ async function onCreateSubmit(payload: PlanCreateSubmit): Promise<void> {
|
|
|
390
396
|
|
|
391
397
|
await reloadAllVersions();
|
|
392
398
|
flashHighlight(created.planKey);
|
|
393
|
-
flashToast(
|
|
399
|
+
flashToast(formatMessage(msg.value.page.toastPlanCreated, { planKey: created.planKey }));
|
|
394
400
|
await onOpenPlan(created);
|
|
395
401
|
openCreateDraftWithPrefill({
|
|
396
402
|
features: payload.initialFeatures,
|
|
@@ -550,7 +556,7 @@ async function onUpdatePlanFromDetail(patch: { label: string }): Promise<void> {
|
|
|
550
556
|
selectedPlan.value = updated;
|
|
551
557
|
} catch (err: unknown) {
|
|
552
558
|
// eslint-disable-next-line no-console
|
|
553
|
-
console.error('[PlansPage] Plan
|
|
559
|
+
console.error('[PlansPage] Plan rename failed', err);
|
|
554
560
|
}
|
|
555
561
|
}
|
|
556
562
|
|
|
@@ -564,7 +570,10 @@ const availableBundles = ref<BundleEntry[]>([]);
|
|
|
564
570
|
// all consumer admin UIs label things identically.
|
|
565
571
|
const featureCatalogEntries = ref<FeatureCatalogEntryRow[]>([]);
|
|
566
572
|
const featureRegistry = computed<Record<string, { label?: string; group?: string }>>(() => ({
|
|
567
|
-
...buildFeatureRegistry(
|
|
573
|
+
...buildFeatureRegistry(
|
|
574
|
+
featureCatalogEntries.value,
|
|
575
|
+
props.displayLocale ?? CATALOG_DEFAULT_LOCALE,
|
|
576
|
+
),
|
|
568
577
|
...props.featureRegistry,
|
|
569
578
|
}));
|
|
570
579
|
|
|
@@ -659,28 +668,32 @@ function describeDraftSaveError(err: unknown): string {
|
|
|
659
668
|
const body = e?.body;
|
|
660
669
|
const code = body?.code;
|
|
661
670
|
if (status === 401 || status === 403) {
|
|
662
|
-
return
|
|
671
|
+
return msg.value.page.errorSessionExpiredSave;
|
|
663
672
|
}
|
|
664
673
|
if (status === 422 && code === 'STRICT_MODE_VIOLATIONS') {
|
|
665
674
|
const list = (body?.warnings ?? [])
|
|
666
675
|
.map((w) => w.message)
|
|
667
676
|
.filter(Boolean)
|
|
668
677
|
.join(' · ');
|
|
669
|
-
return
|
|
678
|
+
return formatMessage(msg.value.page.errorStrictMode, {
|
|
679
|
+
details: list || msg.value.page.errorStrictModeFallback,
|
|
680
|
+
});
|
|
670
681
|
}
|
|
671
682
|
if (status === 422 && code === 'PLAN_VERSION_REGRESSION') {
|
|
672
|
-
return
|
|
683
|
+
return msg.value.page.errorDraftRegression;
|
|
673
684
|
}
|
|
674
685
|
if (status === 422 && body?.message) {
|
|
675
686
|
// e.g. "Plan 'BASIC' hat bereits eine Draft-Version v4 …"
|
|
676
687
|
return body.message;
|
|
677
688
|
}
|
|
678
689
|
if (status !== undefined) {
|
|
679
|
-
return
|
|
690
|
+
return (
|
|
691
|
+
body?.message ?? formatMessage(msg.value.page.errorSaveFailedHttp, { status: status })
|
|
692
|
+
);
|
|
680
693
|
}
|
|
681
694
|
return err instanceof Error
|
|
682
|
-
?
|
|
683
|
-
:
|
|
695
|
+
? formatMessage(msg.value.page.errorSaveFailedDetail, { message: err.message })
|
|
696
|
+
: msg.value.page.errorSaveFailedConsole;
|
|
684
697
|
}
|
|
685
698
|
const draftEditing = ref<{
|
|
686
699
|
editingId: string | null;
|
|
@@ -903,13 +916,18 @@ async function onReviewSaveExit(): Promise<void> {
|
|
|
903
916
|
if (!saved) return;
|
|
904
917
|
const planKey = selectedPlan.value?.planKey ?? '';
|
|
905
918
|
flashHighlight(planKey);
|
|
906
|
-
flashToast(
|
|
919
|
+
flashToast(
|
|
920
|
+
formatMessage(msg.value.page.toastDraftSaved, {
|
|
921
|
+
version: saved.version,
|
|
922
|
+
planKey,
|
|
923
|
+
}),
|
|
924
|
+
);
|
|
907
925
|
reviewDraft.value = null;
|
|
908
926
|
draftEditing.value = null;
|
|
909
927
|
mode.value = selectedPlan.value ? 'cockpit' : 'list';
|
|
910
928
|
} catch (err: unknown) {
|
|
911
929
|
// eslint-disable-next-line no-console
|
|
912
|
-
console.error('[PlansPage]
|
|
930
|
+
console.error('[PlansPage] Saving the draft failed', err);
|
|
913
931
|
reviewError.value = describeDraftSaveError(err);
|
|
914
932
|
} finally {
|
|
915
933
|
draftSaving.value = false;
|
|
@@ -936,14 +954,17 @@ async function onReviewPublish(payload: {
|
|
|
936
954
|
const planKey = selectedPlan.value.planKey;
|
|
937
955
|
flashHighlight(planKey);
|
|
938
956
|
flashToast(
|
|
939
|
-
|
|
957
|
+
formatMessage(msg.value.page.toastPlanPublished, {
|
|
958
|
+
planKey,
|
|
959
|
+
version: result.planVersion.version,
|
|
960
|
+
}),
|
|
940
961
|
);
|
|
941
962
|
reviewDraft.value = null;
|
|
942
963
|
draftEditing.value = null;
|
|
943
964
|
mode.value = 'cockpit';
|
|
944
965
|
} catch (err: unknown) {
|
|
945
966
|
// eslint-disable-next-line no-console
|
|
946
|
-
console.error('[PlansPage]
|
|
967
|
+
console.error('[PlansPage] Publishing failed', err);
|
|
947
968
|
reviewError.value = describePublishError(err);
|
|
948
969
|
} finally {
|
|
949
970
|
publishing.value = false;
|
|
@@ -974,31 +995,29 @@ async function executeArchive(): Promise<void> {
|
|
|
974
995
|
await hardDelete(plan.id);
|
|
975
996
|
await reloadAllVersions();
|
|
976
997
|
archiveOpen.value = false;
|
|
977
|
-
flashToast(
|
|
998
|
+
flashToast(formatMessage(msg.value.page.toastPlanDeleted, { planKey: plan.planKey }));
|
|
978
999
|
} catch (err: unknown) {
|
|
979
1000
|
// eslint-disable-next-line no-console
|
|
980
|
-
console.error('[PlansPage] Archive/
|
|
1001
|
+
console.error('[PlansPage] Archive/purge failed', err);
|
|
981
1002
|
const status = (err as { status?: number })?.status;
|
|
982
1003
|
const body = (err as { body?: { code?: string; message?: string } })?.body;
|
|
983
1004
|
const errMessage = err instanceof Error ? err.message : String(err);
|
|
984
1005
|
if (status === 422 && body?.code === 'PLAN_HAS_PUBLISHED_VERSIONS') {
|
|
985
|
-
archiveError.value =
|
|
986
|
-
body.message ??
|
|
987
|
-
'Plan hat published Versionen — kann nicht gelöscht werden (Vertragsschutz P1).';
|
|
1006
|
+
archiveError.value = body.message ?? msg.value.page.errorPlanHasPublishedVersions;
|
|
988
1007
|
} else if (status === 422 && body?.code === 'PLAN_HAS_DRAFTS') {
|
|
989
|
-
archiveError.value =
|
|
990
|
-
body.message ??
|
|
991
|
-
'Plan hat noch einen offenen Draft — bitte erst über das Mülleimer-Icon verwerfen.';
|
|
1008
|
+
archiveError.value = body.message ?? msg.value.page.errorPlanHasDrafts;
|
|
992
1009
|
} else if (status === 422 && body?.code === 'PLAN_HARD_DELETE_NOT_IMPLEMENTED') {
|
|
993
|
-
archiveError.value =
|
|
994
|
-
'Backend unterstützt Hard-Delete noch nicht — API-Server neu bauen + starten.';
|
|
1010
|
+
archiveError.value = msg.value.page.errorHardDeleteNotImplemented;
|
|
995
1011
|
} else if (status === 404) {
|
|
996
|
-
archiveError.value =
|
|
1012
|
+
archiveError.value = msg.value.page.errorPlanAlreadyRemoved;
|
|
997
1013
|
await reloadAllVersions();
|
|
998
1014
|
} else if (status !== undefined) {
|
|
999
|
-
archiveError.value =
|
|
1015
|
+
archiveError.value =
|
|
1016
|
+
body?.message ?? formatMessage(msg.value.page.errorOperationFailedHttp, { status });
|
|
1000
1017
|
} else {
|
|
1001
|
-
archiveError.value =
|
|
1018
|
+
archiveError.value = formatMessage(msg.value.page.errorOperationFailedDetail, {
|
|
1019
|
+
message: errMessage,
|
|
1020
|
+
});
|
|
1002
1021
|
}
|
|
1003
1022
|
} finally {
|
|
1004
1023
|
archiving.value = false;
|
|
@@ -1037,35 +1056,38 @@ async function executeDiscard(): Promise<void> {
|
|
|
1037
1056
|
await reloadAllVersions();
|
|
1038
1057
|
discardOpen.value = false;
|
|
1039
1058
|
flashToast(
|
|
1040
|
-
|
|
1059
|
+
formatMessage(msg.value.page.toastDraftDiscarded, {
|
|
1060
|
+
version: draft.version,
|
|
1061
|
+
planKey: plan.planKey,
|
|
1062
|
+
}),
|
|
1041
1063
|
);
|
|
1042
1064
|
} catch (err: unknown) {
|
|
1043
1065
|
// Full error object to the console — in the diagnostic case you can see
|
|
1044
1066
|
// e.g. CORS preflight errors or the real network stack there.
|
|
1045
1067
|
// eslint-disable-next-line no-console
|
|
1046
|
-
console.error('[PlansPage] Discard
|
|
1068
|
+
console.error('[PlansPage] Discard failed', err);
|
|
1047
1069
|
|
|
1048
1070
|
const status = (err as { status?: number })?.status;
|
|
1049
1071
|
const body = (err as { body?: { code?: string; message?: string } })?.body;
|
|
1050
1072
|
const errMessage = err instanceof Error ? err.message : String(err);
|
|
1051
1073
|
|
|
1052
1074
|
if (status === 422 && body?.code === 'PLAN_VERSION_ALREADY_PUBLISHED') {
|
|
1053
|
-
discardError.value =
|
|
1054
|
-
'Diese Version ist bereits published und kann nicht verworfen werden.';
|
|
1075
|
+
discardError.value = msg.value.page.errorVersionAlreadyPublished;
|
|
1055
1076
|
} else if (status === 422 && body?.code === 'PLAN_VERSION_DISCARD_NOT_IMPLEMENTED') {
|
|
1056
|
-
discardError.value =
|
|
1057
|
-
'Backend unterstützt das Verwerfen noch nicht — bitte API-Server neu bauen + starten.';
|
|
1077
|
+
discardError.value = msg.value.page.errorDiscardNotImplemented;
|
|
1058
1078
|
} else if (status === 404) {
|
|
1059
|
-
discardError.value =
|
|
1060
|
-
'Draft wurde bereits entfernt (404) — Liste wird gleich neu geladen.';
|
|
1079
|
+
discardError.value = msg.value.page.errorDraftAlreadyRemoved;
|
|
1061
1080
|
await reloadAllVersions();
|
|
1062
1081
|
} else if (status !== undefined) {
|
|
1063
|
-
discardError.value =
|
|
1082
|
+
discardError.value =
|
|
1083
|
+
body?.message ?? formatMessage(msg.value.page.errorDiscardFailedHttp, { status });
|
|
1064
1084
|
} else {
|
|
1065
1085
|
// No HTTP status → usually a network error / CORS preflight / failed
|
|
1066
1086
|
// caller-side (e.g. usePlanVersions construction). Show the real
|
|
1067
1087
|
// error message so the diagnostic path doesn't end at "HTTP ?".
|
|
1068
|
-
discardError.value =
|
|
1088
|
+
discardError.value = formatMessage(msg.value.page.errorDiscardFailedDetail, {
|
|
1089
|
+
message: errMessage,
|
|
1090
|
+
});
|
|
1069
1091
|
}
|
|
1070
1092
|
} finally {
|
|
1071
1093
|
discarding.value = false;
|
|
@@ -1078,13 +1100,15 @@ async function executeDiscard(): Promise<void> {
|
|
|
1078
1100
|
// consistent after the call.
|
|
1079
1101
|
async function onSubmitTerminate(versionId: string, endsAt: string): Promise<void> {
|
|
1080
1102
|
if (!planVersions.value) {
|
|
1081
|
-
throw new Error('PlanVersions
|
|
1103
|
+
throw new Error('PlanVersions composable is not initialized');
|
|
1082
1104
|
}
|
|
1083
1105
|
await planVersions.value.terminateVersion(versionId, endsAt);
|
|
1084
1106
|
await reloadCockpitVersions();
|
|
1085
1107
|
if (selectedPlan.value) {
|
|
1086
1108
|
flashToast(
|
|
1087
|
-
|
|
1109
|
+
formatMessage(msg.value.page.toastVersionTerminated, {
|
|
1110
|
+
version: versions.value.find((v) => v.id === versionId)?.version ?? '?',
|
|
1111
|
+
}),
|
|
1088
1112
|
);
|
|
1089
1113
|
}
|
|
1090
1114
|
}
|
|
@@ -1122,7 +1146,10 @@ async function executePublish(): Promise<void> {
|
|
|
1122
1146
|
if (selectedPlan.value) {
|
|
1123
1147
|
flashHighlight(selectedPlan.value.planKey);
|
|
1124
1148
|
flashToast(
|
|
1125
|
-
|
|
1149
|
+
formatMessage(msg.value.page.toastPlanPublished, {
|
|
1150
|
+
planKey: selectedPlan.value.planKey,
|
|
1151
|
+
version: result.planVersion.version,
|
|
1152
|
+
}),
|
|
1126
1153
|
);
|
|
1127
1154
|
}
|
|
1128
1155
|
} catch (err: unknown) {
|
|
@@ -1140,19 +1167,21 @@ async function executePublish(): Promise<void> {
|
|
|
1140
1167
|
}
|
|
1141
1168
|
}
|
|
1142
1169
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
'features.
|
|
1148
|
-
'
|
|
1149
|
-
'quotas.
|
|
1150
|
-
'
|
|
1151
|
-
'bundles.
|
|
1170
|
+
// API field path of a regression change → catalog key of its label.
|
|
1171
|
+
const REGRESSION_FIELD_KEYS: Record<string, keyof SaMessages['plans']['regressionFields']> = {
|
|
1172
|
+
monthlyNet: 'monthlyNet',
|
|
1173
|
+
yearlyNet: 'yearlyNet',
|
|
1174
|
+
'features.removed': 'featuresRemoved',
|
|
1175
|
+
'features.added': 'featuresAdded',
|
|
1176
|
+
'quotas.lowered': 'quotasLowered',
|
|
1177
|
+
'quotas.raised': 'quotasRaised',
|
|
1178
|
+
'bundles.removed': 'bundlesRemoved',
|
|
1179
|
+
'bundles.added': 'bundlesAdded',
|
|
1152
1180
|
};
|
|
1153
1181
|
|
|
1154
1182
|
function fieldLabel(field: string): string {
|
|
1155
|
-
|
|
1183
|
+
const key = REGRESSION_FIELD_KEYS[field];
|
|
1184
|
+
return key ? msg.value.regressionFields[key] : field;
|
|
1156
1185
|
}
|
|
1157
1186
|
|
|
1158
1187
|
function formatChangeValue(value: unknown): string {
|
|
@@ -1175,21 +1204,24 @@ function describePublishError(err: unknown): string {
|
|
|
1175
1204
|
const status = (err as { status?: number })?.status;
|
|
1176
1205
|
const body = (err as { body?: { code?: string; message?: string } })?.body;
|
|
1177
1206
|
if (status === 401 || status === 403) {
|
|
1178
|
-
return
|
|
1207
|
+
return msg.value.page.errorSessionExpiredPublish;
|
|
1179
1208
|
}
|
|
1180
1209
|
if (status === 422 && body?.code === 'PLAN_VERSION_REGRESSION') {
|
|
1181
|
-
return
|
|
1210
|
+
return msg.value.page.errorPublishRegression;
|
|
1182
1211
|
}
|
|
1183
1212
|
if (status === 422 && body?.code === 'PLAN_VERSION_VALID_FROM_REQUIRED') {
|
|
1184
|
-
return
|
|
1213
|
+
return msg.value.page.errorValidFromRequired;
|
|
1185
1214
|
}
|
|
1186
1215
|
if (status === 422 && body?.code === 'PLAN_VERSION_VALID_FROM_NOT_AFTER_PREVIOUS') {
|
|
1187
|
-
return
|
|
1216
|
+
return msg.value.page.errorValidFromNotAfterPrevious;
|
|
1188
1217
|
}
|
|
1189
1218
|
if (status === 422 && body?.code === 'PLAN_VERSION_ZERO_PRICE') {
|
|
1190
|
-
return
|
|
1219
|
+
return msg.value.page.errorZeroPrice;
|
|
1191
1220
|
}
|
|
1192
|
-
return
|
|
1221
|
+
return (
|
|
1222
|
+
body?.message ??
|
|
1223
|
+
formatMessage(msg.value.page.errorPublishFailedHttp, { status: status ?? '?' })
|
|
1224
|
+
);
|
|
1193
1225
|
}
|
|
1194
1226
|
|
|
1195
1227
|
watch(plans, async () => {
|