@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
|
@@ -19,7 +19,9 @@ import type {
|
|
|
19
19
|
SyncDiscoveryResult,
|
|
20
20
|
UpdateCatalogEntryBaseData,
|
|
21
21
|
} from '@saasicat/types';
|
|
22
|
-
import {
|
|
22
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
23
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
24
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
23
25
|
|
|
24
26
|
export interface UseCatalogEntriesOptions {
|
|
25
27
|
/** Admin endpoint prefix incl. globalPrefix (`/api/admin`, `/api/v1/admin`). */
|
|
@@ -75,12 +77,13 @@ export interface UseCatalogEntriesResult {
|
|
|
75
77
|
|
|
76
78
|
export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalogEntriesResult {
|
|
77
79
|
if (!options?.adminEndpoint) {
|
|
78
|
-
throw new Error('useCatalogEntries: `adminEndpoint`
|
|
80
|
+
throw new Error('useCatalogEntries: `adminEndpoint` is required.');
|
|
79
81
|
}
|
|
80
82
|
if (!options?.projectKey) {
|
|
81
|
-
throw new Error('useCatalogEntries: `projectKey`
|
|
83
|
+
throw new Error('useCatalogEntries: `projectKey` is required.');
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
const msg = useSaMessages('discovery');
|
|
84
87
|
const http = options.http ?? defaultHttpClient();
|
|
85
88
|
const capabilities = ref<CapabilityCatalogEntryRow[]>([]);
|
|
86
89
|
const features = ref<FeatureCatalogEntryRow[]>([]);
|
|
@@ -108,7 +111,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
108
111
|
throw new CatalogEntriesApiError(
|
|
109
112
|
res.status,
|
|
110
113
|
body,
|
|
111
|
-
|
|
114
|
+
formatMessage(msg.value.errorCatalogHttp, { status: res.status }),
|
|
112
115
|
);
|
|
113
116
|
}
|
|
114
117
|
return body as T;
|
|
@@ -141,7 +144,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
141
144
|
`${base}/features/${encodeURIComponent(featureKey)}/review?projectKey=${pk}`,
|
|
142
145
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
143
146
|
);
|
|
144
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'Review
|
|
147
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'Review returned no body');
|
|
145
148
|
features.value = features.value.map((f) => (f.featureKey === featureKey ? updated : f));
|
|
146
149
|
return updated;
|
|
147
150
|
}
|
|
@@ -154,7 +157,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
154
157
|
`${base}/quotas/${encodeURIComponent(quotaKey)}/review?projectKey=${pk}`,
|
|
155
158
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
156
159
|
);
|
|
157
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'Review
|
|
160
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'Review returned no body');
|
|
158
161
|
quotas.value = quotas.value.map((q) => (q.quotaKey === quotaKey ? updated : q));
|
|
159
162
|
return updated;
|
|
160
163
|
}
|
|
@@ -167,7 +170,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
167
170
|
`${base}/features/${encodeURIComponent(featureKey)}/i18n?projectKey=${pk}`,
|
|
168
171
|
{ method: 'PATCH', body: JSON.stringify({ i18n }) },
|
|
169
172
|
);
|
|
170
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'i18n
|
|
173
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'i18n returned no body');
|
|
171
174
|
features.value = features.value.map((f) => (f.featureKey === featureKey ? updated : f));
|
|
172
175
|
return updated;
|
|
173
176
|
}
|
|
@@ -180,7 +183,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
180
183
|
`${base}/quotas/${encodeURIComponent(quotaKey)}/i18n?projectKey=${pk}`,
|
|
181
184
|
{ method: 'PATCH', body: JSON.stringify({ i18n }) },
|
|
182
185
|
);
|
|
183
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'i18n
|
|
186
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'i18n returned no body');
|
|
184
187
|
quotas.value = quotas.value.map((q) => (q.quotaKey === quotaKey ? updated : q));
|
|
185
188
|
return updated;
|
|
186
189
|
}
|
|
@@ -193,7 +196,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
193
196
|
`${base}/features/${encodeURIComponent(featureKey)}?projectKey=${pk}`,
|
|
194
197
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
195
198
|
);
|
|
196
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'Base
|
|
199
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'Base returned no body');
|
|
197
200
|
features.value = features.value.map((f) => (f.featureKey === featureKey ? updated : f));
|
|
198
201
|
return updated;
|
|
199
202
|
}
|
|
@@ -206,7 +209,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
206
209
|
`${base}/quotas/${encodeURIComponent(quotaKey)}?projectKey=${pk}`,
|
|
207
210
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
208
211
|
);
|
|
209
|
-
if (!updated) throw new CatalogEntriesApiError(0, null, 'Base
|
|
212
|
+
if (!updated) throw new CatalogEntriesApiError(0, null, 'Base returned no body');
|
|
210
213
|
quotas.value = quotas.value.map((q) => (q.quotaKey === quotaKey ? updated : q));
|
|
211
214
|
return updated;
|
|
212
215
|
}
|
|
@@ -216,7 +219,7 @@ export function useCatalogEntries(options: UseCatalogEntriesOptions): UseCatalog
|
|
|
216
219
|
method: 'POST',
|
|
217
220
|
body: JSON.stringify({ snapshot }),
|
|
218
221
|
});
|
|
219
|
-
if (!result) throw new CatalogEntriesApiError(0, null, 'Sync
|
|
222
|
+
if (!result) throw new CatalogEntriesApiError(0, null, 'Sync returned no body');
|
|
220
223
|
await load();
|
|
221
224
|
return result;
|
|
222
225
|
}
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
import { ref, type Ref } from 'vue';
|
|
14
14
|
import type { DiscoverySnapshot } from '@saasicat/types';
|
|
15
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
15
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
16
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
17
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
16
18
|
|
|
17
19
|
export interface UseDiscoveryOptions {
|
|
18
20
|
/**
|
|
@@ -68,11 +70,12 @@ export interface UseDiscoveryResult {
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
export function useDiscovery(options: UseDiscoveryOptions): UseDiscoveryResult {
|
|
73
|
+
const msg = useSaMessages('discovery');
|
|
71
74
|
if (!options?.endpoint) {
|
|
72
75
|
throw new Error(
|
|
73
|
-
'useDiscovery: `endpoint`
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
+
'useDiscovery: `endpoint` is required (e.g. "/api/admin/discovery" ' +
|
|
77
|
+
'or "/api/v1/admin/discovery"). The platform has no default ' +
|
|
78
|
+
'because apps use different globalPrefix conventions.',
|
|
76
79
|
);
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -102,7 +105,7 @@ export function useDiscovery(options: UseDiscoveryOptions): UseDiscoveryResult {
|
|
|
102
105
|
if (res.status !== 200) {
|
|
103
106
|
throw new DiscoveryLoadError(
|
|
104
107
|
res.status,
|
|
105
|
-
|
|
108
|
+
formatMessage(msg.value.errorDiscoveryHttp, { status: res.status }),
|
|
106
109
|
);
|
|
107
110
|
}
|
|
108
111
|
|
|
@@ -137,7 +140,7 @@ export function useDiscovery(options: UseDiscoveryOptions): UseDiscoveryResult {
|
|
|
137
140
|
if (res.status !== 200 && res.status !== 201) {
|
|
138
141
|
throw new DiscoveryLoadError(
|
|
139
142
|
res.status,
|
|
140
|
-
|
|
143
|
+
formatMessage(msg.value.errorRescanHttp, { status: res.status }),
|
|
141
144
|
);
|
|
142
145
|
}
|
|
143
146
|
const body = (await res.json()) as DiscoverySnapshot;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// expose the snapshot (it lives in saas-platform-nest/entitlement).
|
|
13
13
|
|
|
14
14
|
import { ref, type Ref } from 'vue';
|
|
15
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
15
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
16
16
|
|
|
17
17
|
export interface EntitlementSnapshotShape {
|
|
18
18
|
plan: string;
|
|
@@ -44,9 +44,9 @@ export interface UseEntitlementResult {
|
|
|
44
44
|
export function useEntitlement(options: UseEntitlementOptions): UseEntitlementResult {
|
|
45
45
|
if (!options?.endpoint) {
|
|
46
46
|
throw new Error(
|
|
47
|
-
'useEntitlement: `endpoint`
|
|
48
|
-
'
|
|
49
|
-
'
|
|
47
|
+
'useEntitlement: `endpoint` is required (e.g. "/api/billing/entitlement" ' +
|
|
48
|
+
'or "/api/v1/billing/entitlement"). The platform has no default because ' +
|
|
49
|
+
'apps use different globalPrefix conventions.',
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
const endpoint = options.endpoint;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { ref, watch, type Ref } from 'vue';
|
|
12
12
|
import type { PlanRow, PlanVersionRow } from '@saasicat/types';
|
|
13
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
13
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
14
14
|
|
|
15
15
|
export interface UseLivePlanVersionsOptions {
|
|
16
16
|
adminEndpoint: string;
|
|
@@ -33,10 +33,10 @@ export function useLivePlanVersions(
|
|
|
33
33
|
options: UseLivePlanVersionsOptions,
|
|
34
34
|
): UseLivePlanVersionsResult {
|
|
35
35
|
if (!options?.adminEndpoint) {
|
|
36
|
-
throw new Error('useLivePlanVersions: `adminEndpoint`
|
|
36
|
+
throw new Error('useLivePlanVersions: `adminEndpoint` is required.');
|
|
37
37
|
}
|
|
38
38
|
if (!options?.plans) {
|
|
39
|
-
throw new Error('useLivePlanVersions: `plans`
|
|
39
|
+
throw new Error('useLivePlanVersions: `plans` is required.');
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -55,7 +55,7 @@ export function useLivePlanVersions(
|
|
|
55
55
|
headers: { 'content-type': 'application/json', ...authHeaders() },
|
|
56
56
|
});
|
|
57
57
|
if (res.status >= 400) {
|
|
58
|
-
throw new Error(`HTTP ${res.status}
|
|
58
|
+
throw new Error(`HTTP ${res.status} while loading the versions of plan '${planId}'`);
|
|
59
59
|
}
|
|
60
60
|
const versions = (await res.json().catch(() => null)) as PlanVersionRow[] | null;
|
|
61
61
|
if (!versions || versions.length === 0) return null;
|
|
@@ -75,7 +75,7 @@ export function useLivePlanVersions(
|
|
|
75
75
|
// Do not aggregate per-plan errors — the other plans
|
|
76
76
|
// should keep working; just set the mapping entry to null.
|
|
77
77
|
console.warn(
|
|
78
|
-
`useLivePlanVersions:
|
|
78
|
+
`useLivePlanVersions: loading the versions of plan '${plan.planKey}' failed`,
|
|
79
79
|
err,
|
|
80
80
|
);
|
|
81
81
|
return [plan.planKey, null] as const;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { ref, type Ref } from 'vue';
|
|
11
11
|
import type { AdminManifest } from '@saasicat/types';
|
|
12
|
-
import { ManifestLoader, type ManifestLoaderOptions } from '
|
|
12
|
+
import { ManifestLoader, type ManifestLoaderOptions } from '../client/manifest-loader.js';
|
|
13
13
|
|
|
14
14
|
export interface UseManifestResult {
|
|
15
15
|
manifest: Ref<AdminManifest | null>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// useMarketingProjections — Vue 3 composable over the
|
|
2
2
|
// MarketingProjectionsController (`/admin/catalog/marketing-projections`).
|
|
3
3
|
//
|
|
4
|
-
// Unlike
|
|
4
|
+
// Unlike bundles, **without versioning**: marketing edits
|
|
5
5
|
// go live directly. The composable does not cache the list per filter tuple,
|
|
6
6
|
// but reloads fresh on every `load()` — marketing maintenance is
|
|
7
7
|
// low-frequency and consistency matters more than performance.
|
|
@@ -13,7 +13,9 @@ import type {
|
|
|
13
13
|
MarketingProjectionRow,
|
|
14
14
|
UpdateMarketingProjectionData,
|
|
15
15
|
} from '@saasicat/types';
|
|
16
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
16
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
17
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
18
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
17
19
|
|
|
18
20
|
export interface UseMarketingProjectionsOptions {
|
|
19
21
|
adminEndpoint: string;
|
|
@@ -53,12 +55,13 @@ export function useMarketingProjections(
|
|
|
53
55
|
options: UseMarketingProjectionsOptions,
|
|
54
56
|
): UseMarketingProjectionsResult {
|
|
55
57
|
if (!options?.adminEndpoint) {
|
|
56
|
-
throw new Error('useMarketingProjections: `adminEndpoint`
|
|
58
|
+
throw new Error('useMarketingProjections: `adminEndpoint` is required.');
|
|
57
59
|
}
|
|
58
60
|
if (!options?.filter?.projectKey) {
|
|
59
|
-
throw new Error('useMarketingProjections: `filter.projectKey`
|
|
61
|
+
throw new Error('useMarketingProjections: `filter.projectKey` is required.');
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
const msg = useSaMessages('marketing');
|
|
62
65
|
const http = options.http ?? defaultHttpClient();
|
|
63
66
|
const projections = ref<MarketingProjectionRow[]>([]);
|
|
64
67
|
const filter = ref<MarketingProjectionFilter>({ ...options.filter });
|
|
@@ -94,7 +97,7 @@ export function useMarketingProjections(
|
|
|
94
97
|
throw new MarketingProjectionsApiError(
|
|
95
98
|
res.status,
|
|
96
99
|
body,
|
|
97
|
-
|
|
100
|
+
formatMessage(msg.value.errors.projectionsApi, { status: res.status }),
|
|
98
101
|
);
|
|
99
102
|
}
|
|
100
103
|
return body as T;
|
|
@@ -124,7 +127,7 @@ export function useMarketingProjections(
|
|
|
124
127
|
body: JSON.stringify(data),
|
|
125
128
|
});
|
|
126
129
|
if (!created) {
|
|
127
|
-
throw new MarketingProjectionsApiError(0, null, 'Create
|
|
130
|
+
throw new MarketingProjectionsApiError(0, null, 'Create returned no body');
|
|
128
131
|
}
|
|
129
132
|
// After create: reload the list (a unique tuple insert can
|
|
130
133
|
// affect the filter).
|
|
@@ -141,7 +144,7 @@ export function useMarketingProjections(
|
|
|
141
144
|
body: JSON.stringify(data),
|
|
142
145
|
});
|
|
143
146
|
if (!updated) {
|
|
144
|
-
throw new MarketingProjectionsApiError(0, null, 'Update
|
|
147
|
+
throw new MarketingProjectionsApiError(0, null, 'Update returned no body');
|
|
145
148
|
}
|
|
146
149
|
projections.value = projections.value.map((p) => (p.id === id ? updated : p));
|
|
147
150
|
return updated;
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
type SidebarSection,
|
|
12
12
|
buildRoutes,
|
|
13
13
|
buildSidebar,
|
|
14
|
-
|
|
14
|
+
defaultSectionOrder,
|
|
15
|
+
} from '../client/nav-builder.js';
|
|
16
|
+
import { useSuperAdminI18n } from './use-super-admin-i18n.js';
|
|
15
17
|
|
|
16
18
|
export interface UseNavResult {
|
|
17
19
|
/** List of all routes available via the manifest — filtered by capabilities. */
|
|
@@ -24,10 +26,14 @@ export function useNav(
|
|
|
24
26
|
manifest: Ref<AdminManifest | null>,
|
|
25
27
|
options: NavBuilderOptions = {},
|
|
26
28
|
): UseNavResult {
|
|
29
|
+
const { locale } = useSuperAdminI18n();
|
|
30
|
+
const activeLocale = computed(() => options.locale ?? locale.value);
|
|
27
31
|
const routes = computed<BuildRouteEntry[]>(() => {
|
|
28
32
|
if (!manifest.value) return [];
|
|
29
|
-
return buildRoutes(manifest.value, options);
|
|
33
|
+
return buildRoutes(manifest.value, { ...options, locale: activeLocale.value });
|
|
30
34
|
});
|
|
31
|
-
const sidebar = computed<SidebarSection[]>(() =>
|
|
35
|
+
const sidebar = computed<SidebarSection[]>(() =>
|
|
36
|
+
buildSidebar(routes.value, defaultSectionOrder(activeLocale.value)),
|
|
37
|
+
);
|
|
32
38
|
return { routes, sidebar };
|
|
33
39
|
}
|
|
@@ -31,8 +31,8 @@ import type { AdminManifest, FeatureDef, FeatureKey } from '@saasicat/types';
|
|
|
31
31
|
export class PlannedOnlyFeatureError extends Error {
|
|
32
32
|
constructor(public readonly violations: FeatureKey[]) {
|
|
33
33
|
super(
|
|
34
|
-
`
|
|
35
|
-
`
|
|
34
|
+
`The following features are marked as plannedOnly in the catalog and ` +
|
|
35
|
+
`must not appear in a plan version: ${violations.sort().join(', ')}.`,
|
|
36
36
|
);
|
|
37
37
|
this.name = 'PlannedOnlyFeatureError';
|
|
38
38
|
}
|
|
@@ -57,9 +57,9 @@ function buildVersionsComposable(label: string) {
|
|
|
57
57
|
return function (options: VersionsOptions): VersionsResult {
|
|
58
58
|
if (!options?.endpoint) {
|
|
59
59
|
throw new Error(
|
|
60
|
-
`${label}: \`endpoint\`
|
|
61
|
-
`
|
|
62
|
-
`
|
|
60
|
+
`${label}: \`endpoint\` is required (e.g. "/api/admin/${label}" ` +
|
|
61
|
+
`or "/api/v1/admin/${label}"). The platform has no default ` +
|
|
62
|
+
`because apps use different globalPrefix conventions.`,
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
const filter = options.filter ?? ref<PlanVersionListFilter>({});
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
UpdatePlanData,
|
|
14
14
|
UpdatePlanVersionDraftData,
|
|
15
15
|
} from '@saasicat/types';
|
|
16
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
16
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
17
17
|
|
|
18
18
|
export interface UsePlansOptions {
|
|
19
19
|
/**
|
|
@@ -73,11 +73,11 @@ export interface UsePlansResult {
|
|
|
73
73
|
export function usePlans(options: UsePlansOptions): UsePlansResult {
|
|
74
74
|
if (!options?.adminEndpoint) {
|
|
75
75
|
throw new Error(
|
|
76
|
-
'usePlans: `adminEndpoint`
|
|
76
|
+
'usePlans: `adminEndpoint` is required (e.g. "/api/admin" or ' + '"/api/v1/admin").',
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
79
|
if (!options?.projectKey) {
|
|
80
|
-
throw new Error('usePlans: `projectKey`
|
|
80
|
+
throw new Error('usePlans: `projectKey` is required.');
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -109,7 +109,7 @@ export function usePlans(options: UsePlansOptions): UsePlansResult {
|
|
|
109
109
|
throw new PlansApiError(
|
|
110
110
|
res.status,
|
|
111
111
|
body,
|
|
112
|
-
`Plans
|
|
112
|
+
`Plans API responded with HTTP ${res.status}`,
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
115
|
return body as T;
|
|
@@ -147,7 +147,7 @@ export function usePlans(options: UsePlansOptions): UsePlansResult {
|
|
|
147
147
|
method: 'POST',
|
|
148
148
|
body: JSON.stringify(data),
|
|
149
149
|
});
|
|
150
|
-
if (!created) throw new PlansApiError(0, null, 'Create
|
|
150
|
+
if (!created) throw new PlansApiError(0, null, 'Create returned no body');
|
|
151
151
|
plans.value = [...plans.value, created];
|
|
152
152
|
return created;
|
|
153
153
|
}
|
|
@@ -157,7 +157,7 @@ export function usePlans(options: UsePlansOptions): UsePlansResult {
|
|
|
157
157
|
method: 'PATCH',
|
|
158
158
|
body: JSON.stringify(data),
|
|
159
159
|
});
|
|
160
|
-
if (!updated) throw new PlansApiError(0, null, 'Update
|
|
160
|
+
if (!updated) throw new PlansApiError(0, null, 'Update returned no body');
|
|
161
161
|
plans.value = plans.value.map((p) => (p.id === planId ? updated : p));
|
|
162
162
|
return updated;
|
|
163
163
|
}
|
|
@@ -245,10 +245,10 @@ export interface UsePlanVersionsResult {
|
|
|
245
245
|
|
|
246
246
|
export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersionsResult {
|
|
247
247
|
if (!options?.adminEndpoint) {
|
|
248
|
-
throw new Error('usePlanVersions: `adminEndpoint`
|
|
248
|
+
throw new Error('usePlanVersions: `adminEndpoint` is required.');
|
|
249
249
|
}
|
|
250
250
|
if (!options?.planId) {
|
|
251
|
-
throw new Error('usePlanVersions: `planId`
|
|
251
|
+
throw new Error('usePlanVersions: `planId` is required.');
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -280,7 +280,7 @@ export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersion
|
|
|
280
280
|
throw new PlansApiError(
|
|
281
281
|
res.status,
|
|
282
282
|
body,
|
|
283
|
-
`PlanVersions
|
|
283
|
+
`PlanVersions API responded with HTTP ${res.status}`,
|
|
284
284
|
);
|
|
285
285
|
}
|
|
286
286
|
return body as T;
|
|
@@ -306,7 +306,7 @@ export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersion
|
|
|
306
306
|
method: 'POST',
|
|
307
307
|
body: JSON.stringify(data),
|
|
308
308
|
});
|
|
309
|
-
if (!result) throw new PlansApiError(0, null, 'CreateDraft
|
|
309
|
+
if (!result) throw new PlansApiError(0, null, 'CreateDraft returned no body');
|
|
310
310
|
versions.value = [...versions.value, result.planVersion];
|
|
311
311
|
return result;
|
|
312
312
|
}
|
|
@@ -319,7 +319,7 @@ export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersion
|
|
|
319
319
|
`${versionUrlBase}/${versionId}`,
|
|
320
320
|
{ method: 'PATCH', body: JSON.stringify(data) },
|
|
321
321
|
);
|
|
322
|
-
if (!result) throw new PlansApiError(0, null, 'UpdateDraft
|
|
322
|
+
if (!result) throw new PlansApiError(0, null, 'UpdateDraft returned no body');
|
|
323
323
|
versions.value = versions.value.map((v) => (v.id === versionId ? result.planVersion : v));
|
|
324
324
|
return result;
|
|
325
325
|
}
|
|
@@ -337,7 +337,7 @@ export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersion
|
|
|
337
337
|
`${versionUrlBase}/${versionId}/publish`,
|
|
338
338
|
{ method: 'POST', body: JSON.stringify(opts) },
|
|
339
339
|
);
|
|
340
|
-
if (!result) throw new PlansApiError(0, null, 'Publish
|
|
340
|
+
if (!result) throw new PlansApiError(0, null, 'Publish returned no body');
|
|
341
341
|
versions.value = versions.value.map((v) => (v.id === versionId ? result.planVersion : v));
|
|
342
342
|
return result;
|
|
343
343
|
}
|
|
@@ -352,7 +352,7 @@ export function usePlanVersions(options: UsePlanVersionsOptions): UsePlanVersion
|
|
|
352
352
|
`${versionUrlBase}/${versionId}/terminate`,
|
|
353
353
|
{ method: 'POST', body: JSON.stringify({ endsAt }) },
|
|
354
354
|
);
|
|
355
|
-
if (!updated) throw new PlansApiError(0, null, 'Terminate
|
|
355
|
+
if (!updated) throw new PlansApiError(0, null, 'Terminate returned no body');
|
|
356
356
|
versions.value = versions.value.map((v) => (v.id === versionId ? updated : v));
|
|
357
357
|
return updated;
|
|
358
358
|
}
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { computed, ref, type ComputedRef, type Ref } from 'vue';
|
|
15
15
|
import type { AdminManifest, TenantActionDef, TenantDto } from '@saasicat/types';
|
|
16
16
|
import { useTenantActionFlow } from './use-tenant-action-flow.js';
|
|
17
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
18
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
17
19
|
|
|
18
20
|
export type TenantRowLike = TenantDto & Record<string, unknown>;
|
|
19
21
|
|
|
@@ -91,11 +93,6 @@ const DEFAULT_VISIBLE_FOR_ROW = <TRow extends TenantRowLike>(
|
|
|
91
93
|
return true;
|
|
92
94
|
};
|
|
93
95
|
|
|
94
|
-
const DEFAULT_MFA_DESCRIPTION = <TRow extends TenantRowLike>(
|
|
95
|
-
def: TenantActionDef,
|
|
96
|
-
row: TRow,
|
|
97
|
-
): string => `${def.label} — Tenant „${row.name}". TOTP-Code aus Authenticator eingeben.`;
|
|
98
|
-
|
|
99
96
|
const DEFAULT_ICON_FOR_ACTION_KEY = (actionKey: string): string => {
|
|
100
97
|
if (actionKey.endsWith('.suspend')) return 'block';
|
|
101
98
|
if (actionKey.endsWith('.reactivate')) return 'play_arrow';
|
|
@@ -131,7 +128,13 @@ export function defaultToneForActionKey(actionKey: string): PlatformTenantAction
|
|
|
131
128
|
export function usePlatformTenantActions<TRow extends TenantRowLike>(
|
|
132
129
|
options: PlatformTenantActionsOptions<TRow>,
|
|
133
130
|
): PlatformTenantActionsResult<TRow> {
|
|
134
|
-
const
|
|
131
|
+
const msg = useSaMessages('tenants');
|
|
132
|
+
const defaultMfaDescription = (def: TenantActionDef, row: TRow): string =>
|
|
133
|
+
formatMessage(msg.value.actions.mfaDescription, {
|
|
134
|
+
action: def.label,
|
|
135
|
+
tenant: row.name,
|
|
136
|
+
});
|
|
137
|
+
const mfaDescription = options.mfaDescription ?? defaultMfaDescription;
|
|
135
138
|
const iconForActionKey = options.iconForActionKey ?? DEFAULT_ICON_FOR_ACTION_KEY;
|
|
136
139
|
const toneForActionKey = options.toneForActionKey ?? DEFAULT_TONE_FOR_ACTION_KEY;
|
|
137
140
|
const visibleForRow = options.visibleForRow ?? DEFAULT_VISIBLE_FOR_ROW;
|
|
@@ -5,12 +5,10 @@
|
|
|
5
5
|
// (e.g. `/api/admin` or `/api/v1/admin`).
|
|
6
6
|
|
|
7
7
|
import { ref, type Ref } from 'vue';
|
|
8
|
-
import type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from '@saasicat/types';
|
|
13
|
-
import { defaultHttpClient, type HttpClient } from './types.js';
|
|
8
|
+
import type { CreatePromotionData, PromotionRow, UpdatePromotionData } from '@saasicat/types';
|
|
9
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
10
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
11
|
+
import { useSaMessages } from './use-super-admin-i18n.js';
|
|
14
12
|
|
|
15
13
|
export interface UsePromotionsOptions {
|
|
16
14
|
adminEndpoint: string;
|
|
@@ -43,12 +41,13 @@ export interface UsePromotionsResult {
|
|
|
43
41
|
|
|
44
42
|
export function usePromotions(options: UsePromotionsOptions): UsePromotionsResult {
|
|
45
43
|
if (!options?.adminEndpoint) {
|
|
46
|
-
throw new Error('usePromotions: `adminEndpoint`
|
|
44
|
+
throw new Error('usePromotions: `adminEndpoint` is required.');
|
|
47
45
|
}
|
|
48
46
|
if (!options?.projectKey) {
|
|
49
|
-
throw new Error('usePromotions: `projectKey`
|
|
47
|
+
throw new Error('usePromotions: `projectKey` is required.');
|
|
50
48
|
}
|
|
51
49
|
|
|
50
|
+
const msg = useSaMessages('promos');
|
|
52
51
|
const http = options.http ?? defaultHttpClient();
|
|
53
52
|
const promotions = ref<PromotionRow[]>([]);
|
|
54
53
|
const loading = ref(false);
|
|
@@ -74,7 +73,7 @@ export function usePromotions(options: UsePromotionsOptions): UsePromotionsResul
|
|
|
74
73
|
throw new PromotionsApiError(
|
|
75
74
|
res.status,
|
|
76
75
|
body,
|
|
77
|
-
|
|
76
|
+
formatMessage(msg.value.apiErrorHttpStatus, { status: res.status }),
|
|
78
77
|
);
|
|
79
78
|
}
|
|
80
79
|
return body as T;
|
|
@@ -98,7 +97,7 @@ export function usePromotions(options: UsePromotionsOptions): UsePromotionsResul
|
|
|
98
97
|
method: 'POST',
|
|
99
98
|
body: JSON.stringify(data),
|
|
100
99
|
});
|
|
101
|
-
if (!created) throw new PromotionsApiError(0, null, 'Create
|
|
100
|
+
if (!created) throw new PromotionsApiError(0, null, 'Create returned no body');
|
|
102
101
|
promotions.value = [...promotions.value, created];
|
|
103
102
|
return created;
|
|
104
103
|
}
|
|
@@ -108,7 +107,7 @@ export function usePromotions(options: UsePromotionsOptions): UsePromotionsResul
|
|
|
108
107
|
method: 'PATCH',
|
|
109
108
|
body: JSON.stringify(data),
|
|
110
109
|
});
|
|
111
|
-
if (!updated) throw new PromotionsApiError(0, null, 'Update
|
|
110
|
+
if (!updated) throw new PromotionsApiError(0, null, 'Update returned no body');
|
|
112
111
|
promotions.value = promotions.value.map((p) => (p.id === id ? updated : p));
|
|
113
112
|
return updated;
|
|
114
113
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { ref, type Ref } from 'vue';
|
|
10
10
|
import type { PublicBootResponse } from '@saasicat/types';
|
|
11
|
-
import { BootLoader, type BootLoaderOptions } from '
|
|
11
|
+
import { BootLoader, type BootLoaderOptions } from '../client/boot-loader.js';
|
|
12
12
|
|
|
13
13
|
export interface UsePublicBootResult {
|
|
14
14
|
boot: Ref<PublicBootResponse | null>;
|
|
@@ -39,8 +39,7 @@ export interface PromoState {
|
|
|
39
39
|
export interface UseSubscriptionDraftOptions {
|
|
40
40
|
plans: Ref<CatalogPlan[] | null> | ComputedRef<CatalogPlan[] | null>;
|
|
41
41
|
subscriptionBundles?:
|
|
42
|
-
|
|
|
43
|
-
| ComputedRef<PublicMarketingBundle[] | null>;
|
|
42
|
+
Ref<PublicMarketingBundle[] | null> | ComputedRef<PublicMarketingBundle[] | null>;
|
|
44
43
|
initialPlan?: string | null;
|
|
45
44
|
initialCycle?: BillingCycleStr;
|
|
46
45
|
initialBundleVersionIds?: ReadonlyArray<string>;
|
|
@@ -316,7 +315,7 @@ export function useSubscriptionDraft(options: UseSubscriptionDraftOptions): Subs
|
|
|
316
315
|
|
|
317
316
|
function toApiPayload(): OnboardingSelectionRequest {
|
|
318
317
|
if (!plan.value) {
|
|
319
|
-
throw new Error('useSubscriptionDraft: plan
|
|
318
|
+
throw new Error('useSubscriptionDraft: plan is not set');
|
|
320
319
|
}
|
|
321
320
|
const payload: OnboardingSelectionRequest = {
|
|
322
321
|
plan: plan.value,
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
type SuperAdminBrand,
|
|
18
18
|
type SuperAdminEndpoints,
|
|
19
19
|
type SuperAdminLoginAdapter,
|
|
20
|
-
} from './
|
|
21
|
-
import { defaultHttpClient, type HttpClient } from '
|
|
20
|
+
} from './super-admin-context.js';
|
|
21
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
22
22
|
|
|
23
23
|
/** Returns the `extensions:` map registered in `createSuperAdminApp()`. */
|
|
24
24
|
export function useSuperAdminExtensions(): ExtensionsMap {
|
|
@@ -39,7 +39,7 @@ export function useSuperAdminBrand(): SuperAdminBrand {
|
|
|
39
39
|
const brand = inject(SUPER_ADMIN_BRAND_KEY);
|
|
40
40
|
if (!brand) {
|
|
41
41
|
throw new Error(
|
|
42
|
-
'useSuperAdminBrand():
|
|
42
|
+
'useSuperAdminBrand(): no SuperAdmin branding in inject scope. Was the component mounted inside createSuperAdminApp()?',
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
return brand;
|
|
@@ -50,7 +50,7 @@ export function useSuperAdminEndpoints(): Required<SuperAdminEndpoints> {
|
|
|
50
50
|
const endpoints = inject(SUPER_ADMIN_ENDPOINTS_KEY);
|
|
51
51
|
if (!endpoints) {
|
|
52
52
|
throw new Error(
|
|
53
|
-
'useSuperAdminEndpoints():
|
|
53
|
+
'useSuperAdminEndpoints(): no endpoints in inject scope. Was the component mounted inside createSuperAdminApp()?',
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
return endpoints;
|
|
@@ -77,7 +77,7 @@ export function useSuperAdminLoginAdapter(): SuperAdminLoginAdapter {
|
|
|
77
77
|
const adapter = inject(SUPER_ADMIN_LOGIN_ADAPTER_KEY);
|
|
78
78
|
if (!adapter) {
|
|
79
79
|
throw new Error(
|
|
80
|
-
'useSuperAdminLoginAdapter():
|
|
80
|
+
'useSuperAdminLoginAdapter(): no login adapter registered. Pass it via createSuperAdminApp({ loginAdapter }).',
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
return adapter;
|