@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
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Default i18n map for the tenant plan section. Consumers override individual
|
|
2
2
|
// keys via the `i18n` prop or pass their own map through (build a vue-i18n
|
|
3
|
-
// resolver on top of this shape).
|
|
3
|
+
// resolver on top of this shape). The map that a component falls back to is
|
|
4
|
+
// picked from the active SuperAdmin locale via
|
|
5
|
+
// `defaultTenantPlanSectionI18n()`.
|
|
6
|
+
|
|
7
|
+
import type { SaLocale } from '../client/i18n/locale.js';
|
|
4
8
|
|
|
5
9
|
export interface TenantPlanSectionI18n {
|
|
6
10
|
sectionTitle: string;
|
|
@@ -139,6 +143,29 @@ export interface TenantPlanSectionI18n {
|
|
|
139
143
|
packageSnapshotNone: string;
|
|
140
144
|
packageSnapshotShowRaw: string;
|
|
141
145
|
packageSnapshotHideRaw: string;
|
|
146
|
+
/** Inline error prefix (`Fehler: …`). */
|
|
147
|
+
errorLabel: string;
|
|
148
|
+
/** Tenant self-service page "Meine Bundles" (MySubscriptionBundlesPage). */
|
|
149
|
+
myBundlesTitle: string;
|
|
150
|
+
myBundlesSubtitle: string;
|
|
151
|
+
myBundlesEmptyPrefix: string;
|
|
152
|
+
myBundlesEmptySuffix: string;
|
|
153
|
+
myBundlesBookedSince: string;
|
|
154
|
+
myBundlesCanceledAt: string;
|
|
155
|
+
myBundlesRunsUntil: string;
|
|
156
|
+
myBundlesCancelInProgress: string;
|
|
157
|
+
myBundlesBookInProgress: string;
|
|
158
|
+
myBundlesCancelConfirm: string;
|
|
159
|
+
myBundlesStatusCanceledPending: string;
|
|
160
|
+
myBundlesStatusEnded: string;
|
|
161
|
+
myBundlesAddBundleLabel: string;
|
|
162
|
+
myBundlesAddSelectPlaceholder: string;
|
|
163
|
+
myBundlesPricePerMonthShort: string;
|
|
164
|
+
myBundlesHiddenIncompatible: string;
|
|
165
|
+
myBundlesBundleVersionIdLabel: string;
|
|
166
|
+
myBundlesBundleVersionIdPlaceholder: string;
|
|
167
|
+
myBundlesMinimumTermLabel: string;
|
|
168
|
+
myBundlesMinimumTermPlaceholder: string;
|
|
142
169
|
}
|
|
143
170
|
|
|
144
171
|
/** German default strings — apps can override them selectively. */
|
|
@@ -277,4 +304,193 @@ export const DEFAULT_I18N_DE: TenantPlanSectionI18n = {
|
|
|
277
304
|
packageSnapshotNone: 'Diese Subscription wurde nicht über ein Webseiten-Angebot abgeschlossen.',
|
|
278
305
|
packageSnapshotShowRaw: 'Rohdaten anzeigen',
|
|
279
306
|
packageSnapshotHideRaw: 'Rohdaten ausblenden',
|
|
307
|
+
errorLabel: 'Fehler',
|
|
308
|
+
myBundlesTitle: 'Meine Bundles',
|
|
309
|
+
myBundlesSubtitle:
|
|
310
|
+
'Eigenständig gebuchte Add-On-Pakete zu deinem Plan. Mindestlaufzeit + Kündigungs- Termin pro Bundle.',
|
|
311
|
+
myBundlesEmptyPrefix: 'Du hast noch kein Bundle gebucht. Über',
|
|
312
|
+
myBundlesEmptySuffix: 'kannst du dein Paket um zusätzliche Features & Quotas erweitern.',
|
|
313
|
+
myBundlesBookedSince: 'Gebucht seit',
|
|
314
|
+
myBundlesCanceledAt: 'Gekündigt am',
|
|
315
|
+
myBundlesRunsUntil: 'läuft bis',
|
|
316
|
+
myBundlesCancelInProgress: 'Kündige …',
|
|
317
|
+
myBundlesBookInProgress: 'Buche …',
|
|
318
|
+
myBundlesCancelConfirm:
|
|
319
|
+
'Bundle wirklich kündigen? Die Kündigung wird zum nächstmöglichen Termin wirksam.',
|
|
320
|
+
myBundlesStatusCanceledPending: 'Kündigung wirksam ab …',
|
|
321
|
+
myBundlesStatusEnded: 'Beendet',
|
|
322
|
+
myBundlesAddBundleLabel: 'Bundle',
|
|
323
|
+
myBundlesAddSelectPlaceholder: '— bitte wählen —',
|
|
324
|
+
myBundlesPricePerMonthShort: '€ / Mo',
|
|
325
|
+
myBundlesHiddenIncompatible: 'weitere Bundle(s) ausgeblendet — nicht kompatibel mit Plan',
|
|
326
|
+
myBundlesBundleVersionIdLabel: 'BundleVersion-ID',
|
|
327
|
+
myBundlesBundleVersionIdPlaceholder: 'UUID der gewünschten Bundle-Version',
|
|
328
|
+
myBundlesMinimumTermLabel: 'Mindestlaufzeit (Monate, optional)',
|
|
329
|
+
myBundlesMinimumTermPlaceholder: 'Default: 12',
|
|
280
330
|
};
|
|
331
|
+
|
|
332
|
+
/** English default strings — mirror of {@link DEFAULT_I18N_DE}. */
|
|
333
|
+
export const DEFAULT_I18N_EN: TenantPlanSectionI18n = {
|
|
334
|
+
sectionTitle: 'Plan & usage',
|
|
335
|
+
sectionSubtitle: 'Current plan, usage and bundles.',
|
|
336
|
+
loading: 'Loading …',
|
|
337
|
+
noSubscription: 'No subscription found for this tenant.',
|
|
338
|
+
activePlan: 'Current plan',
|
|
339
|
+
cycleMonthly: 'Monthly',
|
|
340
|
+
cycleYearly: 'Yearly',
|
|
341
|
+
statusActive: 'Active',
|
|
342
|
+
statusTrial: 'Trial',
|
|
343
|
+
statusPastDue: 'Payment overdue',
|
|
344
|
+
statusCanceled: 'Canceled',
|
|
345
|
+
statusPendingSales: 'Sales review',
|
|
346
|
+
trialEndsAt: 'Trial ends on',
|
|
347
|
+
pilotEndsAt: 'Pilot ends on',
|
|
348
|
+
nextBillingDate: 'Next billing date',
|
|
349
|
+
pendingChange: 'Pending plan change',
|
|
350
|
+
changeFromTo: 'Change to',
|
|
351
|
+
changeEffectiveAt: 'effective as of',
|
|
352
|
+
changePlanButton: 'Change plan',
|
|
353
|
+
cancelSubscriptionButton: 'Cancel subscription',
|
|
354
|
+
usageTitle: 'Usage',
|
|
355
|
+
featuresOverviewTitle: 'Features',
|
|
356
|
+
featuresActive: 'Included',
|
|
357
|
+
featuresLocked: 'Not included',
|
|
358
|
+
bundlesStoreTitle: 'Bundles',
|
|
359
|
+
bundlesBookedTitle: 'Booked bundles',
|
|
360
|
+
bundlesAvailableTitle: 'Available bundles',
|
|
361
|
+
bundlesAvailableEmpty: 'There are currently no additional bundles available.',
|
|
362
|
+
bundlesPerMonth: 'net/month',
|
|
363
|
+
bundleBookAction: 'Book bundle',
|
|
364
|
+
bundleBookInProgress: 'Booking …',
|
|
365
|
+
bundleCancelAction: 'Cancel',
|
|
366
|
+
bundleReactivateAction: 'Reactivate',
|
|
367
|
+
bundleReactivateConfirmTitle: 'Reactivate bundle',
|
|
368
|
+
bundleReactivateConfirmBody:
|
|
369
|
+
'The cancellation will be reverted. The bundle stays booked, continues to run normally and will be billed again.',
|
|
370
|
+
bundleCanceledAt: 'Canceled effective',
|
|
371
|
+
bundleMinimumTermUntil: 'Minimum term until',
|
|
372
|
+
bundleIncludesLabel: 'Includes',
|
|
373
|
+
bundleAlreadyBooked: 'Already booked',
|
|
374
|
+
bundleIncompatible: 'Not compatible with the current plan',
|
|
375
|
+
bundleMissingRequires: 'Requires',
|
|
376
|
+
bundlePreviewAddTitle: 'Book bundle',
|
|
377
|
+
bundlePreviewCancelTitle: 'Cancel bundle',
|
|
378
|
+
bundlePreviewLoading: 'Calculating preview …',
|
|
379
|
+
bundlePreviewProrationTitle: 'Prorated billing',
|
|
380
|
+
bundlePreviewProratedNow: 'Prorated amount due today',
|
|
381
|
+
bundlePreviewProrationDays: 'days',
|
|
382
|
+
bundlePreviewNextPeriod: 'Regular price from the next period',
|
|
383
|
+
bundlePreviewTrialNote:
|
|
384
|
+
'Nothing is charged during the trial — billing starts with the first paid period.',
|
|
385
|
+
bundlePreviewNoPrice: 'No list price is configured for the current billing cycle.',
|
|
386
|
+
bundlePreviewMinimumTermLabel: 'Minimum term',
|
|
387
|
+
bundlePreviewMinimumTermMonths: 'months, until',
|
|
388
|
+
bundlePreviewMinimumTermNone: 'No minimum term',
|
|
389
|
+
bundlePreviewRedundantTitle: 'Features already included (would be paid for twice)',
|
|
390
|
+
bundlePreviewRedundantCoveredByPlan: 'already in the plan',
|
|
391
|
+
bundlePreviewRedundantCoveredByBundle: 'already in bundle',
|
|
392
|
+
bundlePreviewMissingRequiresTitle: 'Missing prerequisites',
|
|
393
|
+
bundlePreviewBlockersTitle: 'Booking not possible',
|
|
394
|
+
bundlePreviewWarningsTitle: 'Notes',
|
|
395
|
+
bundlePreviewEffectiveAt: 'Cancellation effective as of',
|
|
396
|
+
bundlePreviewSavings: 'Savings per period once effective',
|
|
397
|
+
bundlePreviewConfirmAdd: 'Book (chargeable)',
|
|
398
|
+
bundlePreviewConfirmCancel: 'Confirm cancellation',
|
|
399
|
+
bundlePreviewInProgress: 'Processing …',
|
|
400
|
+
bundlePreviewClose: 'Cancel',
|
|
401
|
+
pendingVersionTitle: 'Upcoming plan change',
|
|
402
|
+
pendingVersionChipNonRegressive: 'Improvement',
|
|
403
|
+
pendingVersionChipRegressive: 'Confirmation required',
|
|
404
|
+
pendingVersionEffectiveAt: 'Effective as of',
|
|
405
|
+
pendingVersionAcceptAction: 'Accept changes',
|
|
406
|
+
pendingVersionAcceptInProgress: 'Accepting …',
|
|
407
|
+
pendingVersionAcceptedAt: 'Accepted on',
|
|
408
|
+
wizardTitle: 'Change plan',
|
|
409
|
+
wizardClose: 'Close',
|
|
410
|
+
wizardCurrent: 'Current',
|
|
411
|
+
wizardBadgeCurrent: 'active',
|
|
412
|
+
wizardBadgePopular: 'popular',
|
|
413
|
+
wizardPriceUnitMonthly: 'net/month',
|
|
414
|
+
wizardPriceUnitYearly: 'net/year',
|
|
415
|
+
wizardPriceOnRequest: 'on request',
|
|
416
|
+
wizardStepChoose: 'Choose plan',
|
|
417
|
+
wizardStepChooseIntro:
|
|
418
|
+
'Choose your target plan and the billing cycle. In the next step we show the usage check and the feature diff.',
|
|
419
|
+
wizardStepPreview: 'Preview',
|
|
420
|
+
wizardStepConfirm: 'Confirm',
|
|
421
|
+
wizardNext: 'Next',
|
|
422
|
+
wizardBack: 'Back',
|
|
423
|
+
wizardPreviewLoading: 'Calculating preview …',
|
|
424
|
+
wizardEffectiveAtLabel: 'Effective as of',
|
|
425
|
+
wizardEffectiveImmediate: 'Effective immediately',
|
|
426
|
+
wizardProrationTitle: 'Prorated billing',
|
|
427
|
+
wizardProrationLine: 'Additional amount until the end of the period:',
|
|
428
|
+
wizardProrationDays: 'days',
|
|
429
|
+
wizardLimitsTitle: 'Limit comparison',
|
|
430
|
+
wizardLimitsUsed: 'Usage',
|
|
431
|
+
wizardLimitsCurrent: 'Current',
|
|
432
|
+
wizardLimitsTarget: 'Target',
|
|
433
|
+
wizardFeaturesGained: 'Newly unlocked',
|
|
434
|
+
wizardFeaturesLost: 'Features you lose',
|
|
435
|
+
wizardBlockersTitle: 'Blockers',
|
|
436
|
+
wizardConfirmImmediate: 'The change takes effect immediately.',
|
|
437
|
+
wizardConfirmScheduled: 'The change takes effect on',
|
|
438
|
+
wizardConfirmAction: 'Confirm change',
|
|
439
|
+
wizardConfirmInProgress: 'Changing …',
|
|
440
|
+
wizardConfirmPriceTitle: 'Price overview',
|
|
441
|
+
wizardConfirmProratedNow: 'Prorated amount due today',
|
|
442
|
+
wizardConfirmRecurringNext: 'Regular price from the next period',
|
|
443
|
+
wizardConfirmRecurringFrom: 'Regular price due from',
|
|
444
|
+
wizardConfirmPerCycleMonthly: 'per month',
|
|
445
|
+
wizardConfirmPerCycleYearly: 'per year',
|
|
446
|
+
wizardConfirmTrialNote: 'Nothing is charged during the trial.',
|
|
447
|
+
wizardConfirmRecurringTrialEnd: 'Regular price from the end of the trial',
|
|
448
|
+
wizardChangeTypeUpgrade: 'Upgrade',
|
|
449
|
+
wizardChangeTypeDowngrade: 'Downgrade',
|
|
450
|
+
wizardChangeTypeCycle: 'Cycle change',
|
|
451
|
+
wizardChangeTypeNoop: 'No change',
|
|
452
|
+
packageSnapshotTitle: 'Booked plan (snapshot)',
|
|
453
|
+
packageSnapshotSubtitle:
|
|
454
|
+
'Read-only copy of the plan as it was marketed at the time of purchase.',
|
|
455
|
+
packageSnapshotCapturedAt: 'Captured on',
|
|
456
|
+
packageSnapshotOfferRef: 'Offer reference',
|
|
457
|
+
packageSnapshotPlanLabel: 'Plan',
|
|
458
|
+
packageSnapshotPlanVersionLabel: 'Plan version',
|
|
459
|
+
packageSnapshotCycleLabel: 'Billing cycle',
|
|
460
|
+
packageSnapshotBundlesLabel: 'Included bundles',
|
|
461
|
+
packageSnapshotBundlesEmpty: 'No bundles in the plan.',
|
|
462
|
+
packageSnapshotPriceMonthly: 'Monthly price',
|
|
463
|
+
packageSnapshotPriceYearly: 'Yearly price',
|
|
464
|
+
packageSnapshotPriceTotal: 'Total price',
|
|
465
|
+
packageSnapshotNone: 'This subscription was not created through a website offer.',
|
|
466
|
+
packageSnapshotShowRaw: 'Show raw data',
|
|
467
|
+
packageSnapshotHideRaw: 'Hide raw data',
|
|
468
|
+
errorLabel: 'Error',
|
|
469
|
+
myBundlesTitle: 'My bundles',
|
|
470
|
+
myBundlesSubtitle:
|
|
471
|
+
'Add-on packages booked independently on top of your plan. Minimum term + cancellation date per bundle.',
|
|
472
|
+
myBundlesEmptyPrefix: 'You have not booked a bundle yet. Use',
|
|
473
|
+
myBundlesEmptySuffix: 'to extend your plan with additional features & quotas.',
|
|
474
|
+
myBundlesBookedSince: 'Booked since',
|
|
475
|
+
myBundlesCanceledAt: 'Canceled on',
|
|
476
|
+
myBundlesRunsUntil: 'runs until',
|
|
477
|
+
myBundlesCancelInProgress: 'Canceling …',
|
|
478
|
+
myBundlesBookInProgress: 'Booking …',
|
|
479
|
+
myBundlesCancelConfirm:
|
|
480
|
+
'Really cancel this bundle? The cancellation takes effect on the next possible date.',
|
|
481
|
+
myBundlesStatusCanceledPending: 'Cancellation effective as of …',
|
|
482
|
+
myBundlesStatusEnded: 'Ended',
|
|
483
|
+
myBundlesAddBundleLabel: 'Bundle',
|
|
484
|
+
myBundlesAddSelectPlaceholder: '— please select —',
|
|
485
|
+
myBundlesPricePerMonthShort: '€ / mo',
|
|
486
|
+
myBundlesHiddenIncompatible: 'more bundle(s) hidden — not compatible with plan',
|
|
487
|
+
myBundlesBundleVersionIdLabel: 'BundleVersion ID',
|
|
488
|
+
myBundlesBundleVersionIdPlaceholder: 'UUID of the desired bundle version',
|
|
489
|
+
myBundlesMinimumTermLabel: 'Minimum term (months, optional)',
|
|
490
|
+
myBundlesMinimumTermPlaceholder: 'Default: 12',
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
/** Default map for the given UI locale — fallback layer under the `i18n` prop. */
|
|
494
|
+
export function defaultTenantPlanSectionI18n(locale: SaLocale): TenantPlanSectionI18n {
|
|
495
|
+
return locale === 'en' ? DEFAULT_I18N_EN : DEFAULT_I18N_DE;
|
|
496
|
+
}
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
|
|
24
24
|
<template v-else-if="preview">
|
|
25
25
|
<!-- Blocker: booking/cancellation not possible -->
|
|
26
|
-
<q-card-section
|
|
26
|
+
<q-card-section
|
|
27
|
+
v-if="preview.blockers.length > 0"
|
|
28
|
+
class="sp-bundle-preview__blockers"
|
|
29
|
+
>
|
|
27
30
|
<div class="sp-bundle-preview__block-title">
|
|
28
31
|
{{ i18n.bundlePreviewBlockersTitle }}
|
|
29
32
|
</div>
|
|
@@ -77,7 +80,9 @@
|
|
|
77
80
|
</div>
|
|
78
81
|
<div class="sp-bundle-preview__price-row">
|
|
79
82
|
<span>{{ i18n.bundlePreviewMinimumTermLabel }}</span>
|
|
80
|
-
<span
|
|
83
|
+
<span
|
|
84
|
+
v-if="addPreview.minimumTermMonths > 0 && addPreview.minimumTermEndsAt"
|
|
85
|
+
>
|
|
81
86
|
{{ addPreview.minimumTermMonths }}
|
|
82
87
|
{{ i18n.bundlePreviewMinimumTermMonths }}
|
|
83
88
|
{{ formatDate(addPreview.minimumTermEndsAt) }}
|
|
@@ -123,10 +128,7 @@
|
|
|
123
128
|
</q-card-section>
|
|
124
129
|
|
|
125
130
|
<!-- Warnings (e.g. MINIMUM_TERM_BINDS) -->
|
|
126
|
-
<q-card-section
|
|
127
|
-
v-if="otherWarnings.length > 0"
|
|
128
|
-
class="sp-bundle-preview__warnings"
|
|
129
|
-
>
|
|
131
|
+
<q-card-section v-if="otherWarnings.length > 0" class="sp-bundle-preview__warnings">
|
|
130
132
|
<div class="sp-bundle-preview__block-title">
|
|
131
133
|
{{ i18n.bundlePreviewWarningsTitle }}
|
|
132
134
|
</div>
|
|
@@ -9,18 +9,13 @@
|
|
|
9
9
|
<li v-for="row in bookedRows" :key="row.id" class="sp-plan-section__item">
|
|
10
10
|
<div>
|
|
11
11
|
<span class="sp-plan-section__item-label">{{ row.label }}</span>
|
|
12
|
-
<span
|
|
13
|
-
v-if="row.canceledAt"
|
|
14
|
-
class="sp-plan-section__item-canceled"
|
|
15
|
-
>
|
|
12
|
+
<span v-if="row.canceledAt" class="sp-plan-section__item-canceled">
|
|
16
13
|
{{ i18n.bundleCanceledAt }}
|
|
17
14
|
{{ formatDate(row.canceledEffectiveAt ?? row.canceledAt) }}
|
|
18
15
|
</span>
|
|
19
|
-
<span
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
>
|
|
23
|
-
{{ i18n.bundleMinimumTermUntil }} {{ formatDate(row.minimumTermEndsAt) }}
|
|
16
|
+
<span v-else-if="row.minimumTermEndsAt" class="sp-plan-section__item-price">
|
|
17
|
+
{{ i18n.bundleMinimumTermUntil }}
|
|
18
|
+
{{ formatDate(row.minimumTermEndsAt) }}
|
|
24
19
|
</span>
|
|
25
20
|
</div>
|
|
26
21
|
<div class="sp-bundle-store__booked-actions">
|
|
@@ -114,7 +109,11 @@
|
|
|
114
109
|
color="primary"
|
|
115
110
|
unelevated
|
|
116
111
|
class="sp-bundle-store__card-action"
|
|
117
|
-
:label="
|
|
112
|
+
:label="
|
|
113
|
+
buyingId === row.bundle.bundleVersionId
|
|
114
|
+
? i18n.bundleBookInProgress
|
|
115
|
+
: i18n.bundleBookAction
|
|
116
|
+
"
|
|
118
117
|
:loading="buyingId === row.bundle.bundleVersionId"
|
|
119
118
|
:disable="buyingId !== null"
|
|
120
119
|
@click="emit('buy', row.bundle.bundleVersionId)"
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
<script setup lang="ts">
|
|
39
39
|
import { computed } from 'vue';
|
|
40
40
|
import type { FeatureUiRegistry } from '@saasicat/types';
|
|
41
|
+
import { useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
|
|
41
42
|
import type { TenantPlanSectionI18n } from '../default-i18n.js';
|
|
42
43
|
|
|
43
44
|
// TenantFeatureMatrix — complete feature-scope overview (#18):
|
|
@@ -54,6 +55,8 @@ const props = defineProps<{
|
|
|
54
55
|
i18n: TenantPlanSectionI18n;
|
|
55
56
|
}>();
|
|
56
57
|
|
|
58
|
+
const { intlLocale } = useSuperAdminI18n();
|
|
59
|
+
|
|
57
60
|
interface FeatureRow {
|
|
58
61
|
key: string;
|
|
59
62
|
active: boolean;
|
|
@@ -81,7 +84,7 @@ const features = computed<FeatureRow[]>(() => {
|
|
|
81
84
|
// Included first, then alphabetically by label.
|
|
82
85
|
return rows.sort((a, b) => {
|
|
83
86
|
if (a.active !== b.active) return a.active ? -1 : 1;
|
|
84
|
-
return a.label.localeCompare(b.label,
|
|
87
|
+
return a.label.localeCompare(b.label, intlLocale.value);
|
|
85
88
|
});
|
|
86
89
|
});
|
|
87
90
|
</script>
|
|
@@ -43,6 +43,12 @@ import {
|
|
|
43
43
|
type SuperAdminLoginAdapter,
|
|
44
44
|
} from '../vue/super-admin-context.js';
|
|
45
45
|
import { SUPER_ADMIN_NOTIFY_KEY, type UiNotify } from '../vue/ui-notify.js';
|
|
46
|
+
import {
|
|
47
|
+
SUPER_ADMIN_I18N_KEY,
|
|
48
|
+
createSuperAdminI18n,
|
|
49
|
+
type SuperAdminI18n,
|
|
50
|
+
type SuperAdminI18nOptions,
|
|
51
|
+
} from '../vue/use-super-admin-i18n.js';
|
|
46
52
|
import { quasarNotify } from './notify.js';
|
|
47
53
|
|
|
48
54
|
export interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
|
|
@@ -98,12 +104,21 @@ export interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
|
|
|
98
104
|
* including for the setup wizard. Consumed via `useSuperAdminHttp()`.
|
|
99
105
|
*/
|
|
100
106
|
http?: HttpClient;
|
|
107
|
+
/**
|
|
108
|
+
* Optional: UI locale + string overrides. Default is German. The created
|
|
109
|
+
* context is returned on the handle (`handle.i18n`) — set
|
|
110
|
+
* `handle.i18n.locale.value = 'en'` (or pass a `Ref` here) to switch at
|
|
111
|
+
* runtime. Consumed via `useSuperAdminI18n()` / `useSaMessages()`.
|
|
112
|
+
*/
|
|
113
|
+
i18n?: SuperAdminI18nOptions;
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
export interface SuperAdminAppHandle {
|
|
104
117
|
app: App;
|
|
105
118
|
router: Router;
|
|
106
119
|
pinia: Pinia;
|
|
120
|
+
/** i18n context of the shell — switch locale via `i18n.locale.value`. */
|
|
121
|
+
i18n: SuperAdminI18n;
|
|
107
122
|
/** Mounts the app on a selector. Returns the root component instance. */
|
|
108
123
|
mount: (selector: string | Element) => ReturnType<App['mount']>;
|
|
109
124
|
}
|
|
@@ -147,7 +162,10 @@ export function createSuperAdminApp(options: CreateSuperAdminAppOptions): SuperA
|
|
|
147
162
|
options.endpoints.manifestEndpoint ?? `${options.endpoints.apiBase}/manifest`,
|
|
148
163
|
};
|
|
149
164
|
|
|
165
|
+
const i18n = createSuperAdminI18n(options.i18n);
|
|
166
|
+
|
|
150
167
|
app.provide(SUPER_ADMIN_BRAND_KEY, { tag: 'SuperAdmin', ...options.brand });
|
|
168
|
+
app.provide(SUPER_ADMIN_I18N_KEY, i18n);
|
|
151
169
|
app.provide(SUPER_ADMIN_ENDPOINTS_KEY, endpoints);
|
|
152
170
|
app.provide(SUPER_ADMIN_EXTENSIONS_KEY, options.extensions ?? {});
|
|
153
171
|
app.provide(SUPER_ADMIN_ACTIONS_KEY, options.actions ?? {});
|
|
@@ -168,6 +186,7 @@ export function createSuperAdminApp(options: CreateSuperAdminAppOptions): SuperA
|
|
|
168
186
|
app,
|
|
169
187
|
router,
|
|
170
188
|
pinia,
|
|
189
|
+
i18n,
|
|
171
190
|
mount: (selector) => app.mount(selector),
|
|
172
191
|
};
|
|
173
192
|
}
|
|
@@ -109,7 +109,7 @@ export function runAdminPagesSuite(
|
|
|
109
109
|
|
|
110
110
|
test.describe(`${config.appName}: SuperAdmin-Pages Smoke`, () => {
|
|
111
111
|
for (const pageDef of config.pages) {
|
|
112
|
-
test(`${pageDef.name}
|
|
112
|
+
test(`${pageDef.name} renders without errors`, async ({ page }) => {
|
|
113
113
|
const errors = attachListeners(
|
|
114
114
|
page,
|
|
115
115
|
config.consoleErrorAllowlist,
|
|
@@ -127,19 +127,19 @@ export function runAdminPagesSuite(
|
|
|
127
127
|
timeout: 5_000,
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
-
expect(errors.pageErrors, `pageerror
|
|
130
|
+
expect(errors.pageErrors, `pageerror events on ${pageDef.path}`).toHaveLength(0);
|
|
131
131
|
expect(
|
|
132
132
|
errors.consoleErrors,
|
|
133
|
-
`console.error
|
|
133
|
+
`console.error events on ${pageDef.path}`,
|
|
134
134
|
).toHaveLength(0);
|
|
135
135
|
expect(
|
|
136
136
|
errors.networkErrors,
|
|
137
|
-
`HTTP
|
|
137
|
+
`HTTP errors on /api/ during ${pageDef.path}`,
|
|
138
138
|
).toHaveLength(0);
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
test('Dashboard
|
|
142
|
+
test('Dashboard shows the expected KPIs, distributions and shortcuts', async ({ page }) => {
|
|
143
143
|
attachListeners(page, config.consoleErrorAllowlist);
|
|
144
144
|
await loginIfNeeded(page, config);
|
|
145
145
|
const origin = new URL(config.loginUrl).origin;
|
|
@@ -151,7 +151,9 @@ export function runAdminPagesSuite(
|
|
|
151
151
|
const kpiLabels = await page.locator('.sa-kpi__label').allTextContents();
|
|
152
152
|
const normalizedKpis = kpiLabels.map((s) => s.trim());
|
|
153
153
|
for (const expected of config.expectedKpiLabels) {
|
|
154
|
-
expect(normalizedKpis, `KPI '${expected}'
|
|
154
|
+
expect(normalizedKpis, `KPI '${expected}' missing on the dashboard`).toContain(
|
|
155
|
+
expected,
|
|
156
|
+
);
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
if (config.expectedDistributionTitles?.length) {
|
|
@@ -162,7 +164,7 @@ export function runAdminPagesSuite(
|
|
|
162
164
|
for (const expected of config.expectedDistributionTitles) {
|
|
163
165
|
expect(
|
|
164
166
|
normalizedDist,
|
|
165
|
-
`Distribution '${expected}'
|
|
167
|
+
`Distribution '${expected}' missing on the dashboard`,
|
|
166
168
|
).toContain(expected);
|
|
167
169
|
}
|
|
168
170
|
}
|
|
@@ -172,14 +174,15 @@ export function runAdminPagesSuite(
|
|
|
172
174
|
.allTextContents();
|
|
173
175
|
const normalizedShortcuts = shortcutTitles.map((s) => s.trim());
|
|
174
176
|
for (const expected of config.expectedShortcutTitles) {
|
|
175
|
-
expect(
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
expect(
|
|
178
|
+
normalizedShortcuts,
|
|
179
|
+
`Shortcut '${expected}' missing on the dashboard`,
|
|
180
|
+
).toContain(expected);
|
|
178
181
|
}
|
|
179
182
|
for (const forbidden of config.forbiddenShortcutTitles ?? []) {
|
|
180
183
|
expect(
|
|
181
184
|
normalizedShortcuts,
|
|
182
|
-
`Shortcut '${forbidden}'
|
|
185
|
+
`Shortcut '${forbidden}' must not be on the dashboard`,
|
|
183
186
|
).not.toContain(forbidden);
|
|
184
187
|
}
|
|
185
188
|
});
|
|
@@ -60,13 +60,15 @@ export const ProjectPageHost = defineComponent({
|
|
|
60
60
|
const page = matchingPage.value;
|
|
61
61
|
const cmp = resolvedComponent.value;
|
|
62
62
|
if (page && cmp) return h(cmp);
|
|
63
|
+
// Misconfiguration diagnostics — developer-facing, therefore not
|
|
64
|
+
// part of the localized catalog.
|
|
63
65
|
return h('div', { class: 'sa-project-page-host__missing', role: 'alert' }, [
|
|
64
|
-
h('h2', '
|
|
66
|
+
h('h2', 'Page not available'),
|
|
65
67
|
h(
|
|
66
68
|
'p',
|
|
67
69
|
page
|
|
68
|
-
? `componentKey "${page.componentKey}"
|
|
69
|
-
: `
|
|
70
|
+
? `componentKey "${page.componentKey}" is not registered in the extensions: map. Apps must register the component in createSuperAdminApp({ extensions }).`
|
|
71
|
+
: `No manifest definition for ${route.path}. Either the ProjectPage is missing from the manifest, or the capability is not active.`,
|
|
70
72
|
),
|
|
71
73
|
]);
|
|
72
74
|
};
|
|
@@ -29,9 +29,9 @@ export interface UseAuditEntriesResult extends UseApiListResult<AuditEntry> {
|
|
|
29
29
|
export function useAuditEntries(options: UseAuditEntriesOptions): UseAuditEntriesResult {
|
|
30
30
|
if (!options?.endpoint) {
|
|
31
31
|
throw new Error(
|
|
32
|
-
'useAuditEntries: `endpoint`
|
|
33
|
-
'
|
|
34
|
-
'
|
|
32
|
+
'useAuditEntries: `endpoint` is required (e.g. "/api/admin/audit" ' +
|
|
33
|
+
'or "/api/v1/admin/audit"). The platform has no default because ' +
|
|
34
|
+
'apps use different globalPrefix conventions.',
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
const filter = options.filter ?? ref<AuditQuery>({});
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { computed, ref, type ComputedRef, type Ref } from 'vue';
|
|
14
14
|
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
15
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
15
16
|
|
|
16
17
|
export type BulkItemKind = 'plan';
|
|
17
18
|
|
|
@@ -62,11 +63,12 @@ export interface UseBulkPublishResult {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export function useBulkPublish(options: UseBulkPublishOptions): UseBulkPublishResult {
|
|
66
|
+
const msg = useSaMessages('planVersions');
|
|
65
67
|
if (!options?.endpoints) {
|
|
66
68
|
throw new Error(
|
|
67
|
-
'useBulkPublish: `endpoints`
|
|
68
|
-
'
|
|
69
|
-
'globalPrefix
|
|
69
|
+
'useBulkPublish: `endpoints` is required (mapping plan → URL builder). ' +
|
|
70
|
+
'The platform has no default because apps use different ' +
|
|
71
|
+
'globalPrefix conventions.',
|
|
70
72
|
);
|
|
71
73
|
}
|
|
72
74
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -128,7 +130,7 @@ export function useBulkPublish(options: UseBulkPublishOptions): UseBulkPublishRe
|
|
|
128
130
|
// Mark all items as failed with a clear reason.
|
|
129
131
|
for (const item of items.value) {
|
|
130
132
|
item.status = 'failed';
|
|
131
|
-
item.error =
|
|
133
|
+
item.error = msg.value.bulkPublish.changeNoteRequired;
|
|
132
134
|
}
|
|
133
135
|
return;
|
|
134
136
|
}
|
|
@@ -36,10 +36,10 @@ export function useBundleVersionsMap(
|
|
|
36
36
|
options: UseBundleVersionsMapOptions,
|
|
37
37
|
): UseBundleVersionsMapResult {
|
|
38
38
|
if (!options?.adminEndpoint) {
|
|
39
|
-
throw new Error('useBundleVersionsMap: `adminEndpoint`
|
|
39
|
+
throw new Error('useBundleVersionsMap: `adminEndpoint` is required.');
|
|
40
40
|
}
|
|
41
41
|
if (!options?.bundles) {
|
|
42
|
-
throw new Error('useBundleVersionsMap: `bundles`
|
|
42
|
+
throw new Error('useBundleVersionsMap: `bundles` is required.');
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -58,7 +58,9 @@ export function useBundleVersionsMap(
|
|
|
58
58
|
headers: { 'content-type': 'application/json', ...authHeaders() },
|
|
59
59
|
});
|
|
60
60
|
if (res.status >= 400) {
|
|
61
|
-
throw new Error(
|
|
61
|
+
throw new Error(
|
|
62
|
+
`HTTP ${res.status} while loading the versions for bundle '${bundleId}'`,
|
|
63
|
+
);
|
|
62
64
|
}
|
|
63
65
|
return ((await res.json().catch(() => null)) as BundleVersionRow[] | null) ?? [];
|
|
64
66
|
}
|
|
@@ -74,7 +76,7 @@ export function useBundleVersionsMap(
|
|
|
74
76
|
return [b.id, versions] as const;
|
|
75
77
|
} catch (err) {
|
|
76
78
|
console.warn(
|
|
77
|
-
`useBundleVersionsMap:
|
|
79
|
+
`useBundleVersionsMap: loading versions for bundle '${b.bundleKey}' failed`,
|
|
78
80
|
err,
|
|
79
81
|
);
|
|
80
82
|
return [b.id, []] as const;
|
package/src/vue/use-bundles.ts
CHANGED
|
@@ -58,13 +58,13 @@ export interface UseBundlesResult {
|
|
|
58
58
|
export function useBundles(options: UseBundlesOptions): UseBundlesResult {
|
|
59
59
|
if (!options?.adminEndpoint) {
|
|
60
60
|
throw new Error(
|
|
61
|
-
'useBundles: `adminEndpoint`
|
|
62
|
-
'"/api/v1/admin").
|
|
63
|
-
'
|
|
61
|
+
'useBundles: `adminEndpoint` is required (e.g. "/api/admin" or ' +
|
|
62
|
+
'"/api/v1/admin"). The platform has no default, because apps use ' +
|
|
63
|
+
'different globalPrefix conventions.',
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
if (!options?.projectKey) {
|
|
67
|
-
throw new Error('useBundles: `projectKey`
|
|
67
|
+
throw new Error('useBundles: `projectKey` is required.');
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -91,7 +91,7 @@ export function useBundles(options: UseBundlesOptions): UseBundlesResult {
|
|
|
91
91
|
throw new BundlesApiError(
|
|
92
92
|
res.status,
|
|
93
93
|
body,
|
|
94
|
-
`Bundles
|
|
94
|
+
`Bundles API responded with HTTP ${res.status}`,
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
return body as T;
|
|
@@ -117,7 +117,7 @@ export function useBundles(options: UseBundlesOptions): UseBundlesResult {
|
|
|
117
117
|
method: 'POST',
|
|
118
118
|
body: JSON.stringify(data),
|
|
119
119
|
});
|
|
120
|
-
if (!created) throw new BundlesApiError(0, null, 'Create
|
|
120
|
+
if (!created) throw new BundlesApiError(0, null, 'Create returned no body');
|
|
121
121
|
bundles.value = [...bundles.value, created];
|
|
122
122
|
return created;
|
|
123
123
|
}
|
|
@@ -127,7 +127,7 @@ export function useBundles(options: UseBundlesOptions): UseBundlesResult {
|
|
|
127
127
|
method: 'PATCH',
|
|
128
128
|
body: JSON.stringify(data),
|
|
129
129
|
});
|
|
130
|
-
if (!updated) throw new BundlesApiError(0, null, 'Update
|
|
130
|
+
if (!updated) throw new BundlesApiError(0, null, 'Update returned no body');
|
|
131
131
|
bundles.value = bundles.value.map((b) => (b.id === bundleId ? updated : b));
|
|
132
132
|
return updated;
|
|
133
133
|
}
|
|
@@ -189,10 +189,10 @@ export interface UseBundleVersionsResult {
|
|
|
189
189
|
|
|
190
190
|
export function useBundleVersions(options: UseBundleVersionsOptions): UseBundleVersionsResult {
|
|
191
191
|
if (!options?.adminEndpoint) {
|
|
192
|
-
throw new Error('useBundleVersions: `adminEndpoint`
|
|
192
|
+
throw new Error('useBundleVersions: `adminEndpoint` is required.');
|
|
193
193
|
}
|
|
194
194
|
if (!options?.bundleId) {
|
|
195
|
-
throw new Error('useBundleVersions: `bundleId`
|
|
195
|
+
throw new Error('useBundleVersions: `bundleId` is required.');
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -220,7 +220,7 @@ export function useBundleVersions(options: UseBundleVersionsOptions): UseBundleV
|
|
|
220
220
|
throw new BundlesApiError(
|
|
221
221
|
res.status,
|
|
222
222
|
body,
|
|
223
|
-
`BundleVersions
|
|
223
|
+
`BundleVersions API responded with HTTP ${res.status}`,
|
|
224
224
|
);
|
|
225
225
|
}
|
|
226
226
|
return body as T;
|
|
@@ -246,7 +246,7 @@ export function useBundleVersions(options: UseBundleVersionsOptions): UseBundleV
|
|
|
246
246
|
method: 'POST',
|
|
247
247
|
body: JSON.stringify(data),
|
|
248
248
|
});
|
|
249
|
-
if (!result) throw new BundlesApiError(0, null, 'CreateDraft
|
|
249
|
+
if (!result) throw new BundlesApiError(0, null, 'CreateDraft returned no body');
|
|
250
250
|
versions.value = [...versions.value, result.bundleVersion];
|
|
251
251
|
return result;
|
|
252
252
|
}
|
|
@@ -259,7 +259,7 @@ export function useBundleVersions(options: UseBundleVersionsOptions): UseBundleV
|
|
|
259
259
|
`${versionUrlBase}/${versionId}`,
|
|
260
260
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
261
261
|
);
|
|
262
|
-
if (!result) throw new BundlesApiError(0, null, 'UpdateDraft
|
|
262
|
+
if (!result) throw new BundlesApiError(0, null, 'UpdateDraft returned no body');
|
|
263
263
|
versions.value = versions.value.map((v) => (v.id === versionId ? result.bundleVersion : v));
|
|
264
264
|
return result;
|
|
265
265
|
}
|
|
@@ -277,7 +277,7 @@ export function useBundleVersions(options: UseBundleVersionsOptions): UseBundleV
|
|
|
277
277
|
`${versionUrlBase}/${versionId}/publish`,
|
|
278
278
|
{ method: 'POST', body: JSON.stringify(opts) },
|
|
279
279
|
);
|
|
280
|
-
if (!result) throw new BundlesApiError(0, null, 'Publish
|
|
280
|
+
if (!result) throw new BundlesApiError(0, null, 'Publish returned no body');
|
|
281
281
|
// Reload versions, because publishing may mark another version as
|
|
282
282
|
// superseded — the local cache would otherwise be inconsistent.
|
|
283
283
|
await load();
|