@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.
Files changed (214) hide show
  1. package/README.md +64 -4
  2. package/dist/chunk-A3W2N26K.js +714 -0
  3. package/dist/chunk-QZOSDCNP.js +98 -0
  4. package/dist/chunk-X5SQ5HMB.js +3231 -0
  5. package/dist/client/index.cjs +3988 -0
  6. package/dist/client/index.d.cts +321 -0
  7. package/dist/client/index.d.ts +321 -0
  8. package/dist/client/index.js +70 -0
  9. package/dist/index.cjs +4446 -1249
  10. package/dist/index.d.cts +297 -888
  11. package/dist/index.d.ts +297 -888
  12. package/dist/index.js +609 -1348
  13. package/dist/messages-7b0P8W75.d.cts +1652 -0
  14. package/dist/messages-7b0P8W75.d.ts +1652 -0
  15. package/dist/quasar/index.cjs +3340 -0
  16. package/dist/quasar/index.d.cts +95 -0
  17. package/dist/quasar/index.d.ts +95 -0
  18. package/dist/quasar/index.js +96 -0
  19. package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
  20. package/dist/testing-e2e/admin-pages-suite.js +14 -11
  21. package/dist/use-super-admin-i18n-B3v3-SWZ.d.ts +210 -0
  22. package/dist/use-super-admin-i18n-DMktRVEt.d.cts +210 -0
  23. package/package.json +23 -3
  24. package/src/{action-registry.ts → client/action-registry.ts} +4 -4
  25. package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +4 -4
  26. package/src/{boot-loader.ts → client/boot-loader.ts} +3 -3
  27. package/src/client/i18n/currency.ts +42 -0
  28. package/src/client/i18n/define.ts +59 -0
  29. package/src/client/i18n/format.ts +12 -0
  30. package/src/client/i18n/index.ts +14 -0
  31. package/src/client/i18n/locale.ts +15 -0
  32. package/src/client/i18n/messages/audit.ts +42 -0
  33. package/src/client/i18n/messages/bundles.ts +459 -0
  34. package/src/client/i18n/messages/common.ts +147 -0
  35. package/src/client/i18n/messages/dashboard.ts +16 -0
  36. package/src/client/i18n/messages/discovery.ts +229 -0
  37. package/src/client/i18n/messages/email.ts +125 -0
  38. package/src/client/i18n/messages/marketing.ts +270 -0
  39. package/src/client/i18n/messages/nav.ts +72 -0
  40. package/src/client/i18n/messages/pilots.ts +192 -0
  41. package/src/client/i18n/messages/plan-detail.ts +266 -0
  42. package/src/client/i18n/messages/plan-editor.ts +177 -0
  43. package/src/client/i18n/messages/plan-versions.ts +251 -0
  44. package/src/client/i18n/messages/plans.ts +503 -0
  45. package/src/client/i18n/messages/promos.ts +202 -0
  46. package/src/client/i18n/messages/shell.ts +145 -0
  47. package/src/client/i18n/messages/tenants.ts +104 -0
  48. package/src/client/i18n/messages/users.ts +78 -0
  49. package/src/client/i18n/messages.ts +84 -0
  50. package/src/client/index.ts +27 -0
  51. package/src/{manifest-loader.ts → client/manifest-loader.ts} +4 -4
  52. package/src/{nav-builder.ts → client/nav-builder.ts} +44 -51
  53. package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +42 -30
  54. package/src/components/BundleVersionPublishDialog.vue +35 -24
  55. package/src/components/FeatureGate.vue +1 -1
  56. package/src/components/MarketingPromotionsTab.vue +112 -59
  57. package/src/components/MfaPromptDialog.vue +11 -11
  58. package/src/components/TenantActionConfirmDialog.vue +19 -17
  59. package/src/components/VersionDiffPreview.vue +72 -43
  60. package/src/components/bundle-editor/BundleCreatePanel.vue +76 -63
  61. package/src/components/bundle-editor/BundleFeaturesEditor.vue +13 -6
  62. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +19 -14
  63. package/src/components/bundle-editor/BundleQuotasEditor.vue +7 -4
  64. package/src/components/bundle-editor/BundleStatusBanner.vue +36 -19
  65. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +51 -35
  66. package/src/components/bundle-editor/BundleVersionStrip.vue +24 -12
  67. package/src/components/bundle-editor/bundle-version-status.ts +29 -29
  68. package/src/components/dialogs/PilotCreateDialog.vue +58 -63
  69. package/src/components/dialogs/PilotEditDialog.vue +40 -34
  70. package/src/components/dialogs/PromoCodeCreateDialog.vue +89 -63
  71. package/src/components/dialogs/PromoCodeEditDialog.vue +98 -66
  72. package/src/components/dialogs/types.ts +3 -13
  73. package/src/components/plan/PlanCycleToggle.vue +21 -10
  74. package/src/components/plan/PlanGrid.vue +2 -2
  75. package/src/components/plan/PriceSummary.vue +1 -1
  76. package/src/components/plan/PromoCodeInput.vue +1 -1
  77. package/src/components/plan/PublicBundleGrid.vue +1 -1
  78. package/src/components/plan-cockpit/PlanCockpit.vue +34 -15
  79. package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +13 -6
  80. package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +18 -9
  81. package/src/components/plan-cockpit/PlanCockpitHeader.vue +9 -6
  82. package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +24 -11
  83. package/src/components/plan-cockpit/PlanCockpitKpis.vue +28 -17
  84. package/src/components/plan-cockpit/PlanCockpitVersions.vue +50 -25
  85. package/src/components/plan-create-dialog/PlanCreateDialog.vue +45 -35
  86. package/src/components/plan-detail/PlanAuditLog.vue +11 -6
  87. package/src/components/plan-detail/PlanDetail.vue +21 -23
  88. package/src/components/plan-detail/PlanDetailHeader.vue +20 -11
  89. package/src/components/plan-detail/PlanDetailKpis.vue +30 -17
  90. package/src/components/plan-detail/PlanTerminateDialog.vue +22 -9
  91. package/src/components/plan-detail/PlanVersionDiffPanel.vue +61 -27
  92. package/src/components/plan-detail/PlanVersionsPanel.vue +71 -36
  93. package/src/components/plan-list/PlanList.vue +99 -57
  94. package/src/components/plan-matrix/PlanMatrix.vue +85 -38
  95. package/src/components/plan-review/PlanReview.vue +105 -80
  96. package/src/components/plan-version-editor/PlanCatalogPreview.vue +43 -20
  97. package/src/components/plan-version-editor/PlanComponentPool.vue +15 -7
  98. package/src/components/plan-version-editor/PlanVersionBasket.vue +45 -24
  99. package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +8 -7
  100. package/src/components/plan-version-editor/PlanVersionEditor.vue +74 -40
  101. package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +24 -12
  102. package/src/index.ts +82 -79
  103. package/src/pages-standard/AdminLayout.vue +43 -18
  104. package/src/pages-standard/AdminManifestErrorPage.vue +10 -10
  105. package/src/pages-standard/AuditPage.vue +58 -19
  106. package/src/pages-standard/BundlesPage.vue +29 -18
  107. package/src/pages-standard/DashboardPage.vue +31 -17
  108. package/src/pages-standard/DiscoveryPage.vue +40 -28
  109. package/src/pages-standard/EmailHistoryPage.vue +98 -69
  110. package/src/pages-standard/MarketingCatalogPage.vue +40 -21
  111. package/src/pages-standard/PilotsPage.vue +64 -52
  112. package/src/pages-standard/PlanVersionsPage.vue +9 -5
  113. package/src/pages-standard/PlansPage.vue +91 -59
  114. package/src/pages-standard/PlatformEmailPage.vue +120 -53
  115. package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
  116. package/src/pages-standard/PromoCodesPage.vue +51 -54
  117. package/src/pages-standard/SubscriptionsPage.vue +14 -9
  118. package/src/pages-standard/SuperAdminLoginPage.vue +19 -16
  119. package/src/pages-standard/SuperAdminSetupWizard.vue +53 -49
  120. package/src/pages-standard/TenantDetailPage.vue +54 -40
  121. package/src/pages-standard/TenantsPage.vue +57 -44
  122. package/src/pages-standard/UsersPage.vue +70 -52
  123. package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -8
  124. package/src/pages-standard/bundles-page/BundleDetailPanel.vue +28 -18
  125. package/src/pages-standard/bundles-page/BundlesFilterBar.vue +4 -1
  126. package/src/pages-standard/bundles-page/BundlesHeader.vue +9 -8
  127. package/src/pages-standard/bundles-page/BundlesKpis.vue +29 -11
  128. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +20 -8
  129. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -3
  130. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +43 -24
  131. package/src/pages-standard/discovery-page/DiscoveryHeader.vue +7 -4
  132. package/src/pages-standard/discovery-page/DiscoveryKpis.vue +28 -15
  133. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +20 -10
  134. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +9 -6
  135. package/src/pages-standard/discovery-page/discovery-ui.ts +40 -52
  136. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +81 -49
  137. package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +13 -10
  138. package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +24 -20
  139. package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +6 -3
  140. package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -6
  141. package/src/pages-standard/plan-versions/PlanVersionHeader.vue +42 -26
  142. package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +46 -27
  143. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +8 -6
  144. package/src/pages-standard/plan-versions/PlanVersionsList.vue +40 -17
  145. package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
  146. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +25 -13
  147. package/src/pages-standard/plan-versions/format.ts +33 -17
  148. package/src/pages-standard/plans-page/PlanArchiveDialog.vue +12 -8
  149. package/src/pages-standard/plans-page/PlanBundleOverview.vue +15 -6
  150. package/src/pages-standard/plans-page/PlanDiscardDraftDialog.vue +18 -7
  151. package/src/pages-standard/plans-page/PlanPublishDialog.vue +23 -12
  152. package/src/pages-standard/tenants/format.ts +3 -2
  153. package/src/pages-tenant/MySubscriptionBundlesPage.vue +73 -38
  154. package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
  155. package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
  156. package/src/pages-tenant/PlanChangeWizard.vue +10 -6
  157. package/src/pages-tenant/TenantPlanSection.vue +20 -16
  158. package/src/pages-tenant/default-i18n.ts +217 -1
  159. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +9 -7
  160. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +11 -12
  161. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
  162. package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
  163. package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
  164. package/src/quasar/create-super-admin-app.ts +192 -0
  165. package/src/quasar/index.ts +11 -0
  166. package/src/quasar/notify.ts +30 -0
  167. package/src/testing-e2e/admin-pages-suite.ts +14 -11
  168. package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
  169. package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
  170. package/src/{project-page-host.ts → vue/project-page-host.ts} +6 -4
  171. package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
  172. package/src/vue/ui-notify.ts +30 -0
  173. package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
  174. package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
  175. package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +3 -3
  176. package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
  177. package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +7 -5
  178. package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +7 -5
  179. package/src/{use-bundles.ts → vue/use-bundles.ts} +14 -14
  180. package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +14 -11
  181. package/src/{use-discovery.ts → vue/use-discovery.ts} +9 -6
  182. package/src/{use-entitlement.ts → vue/use-entitlement.ts} +4 -4
  183. package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +5 -5
  184. package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
  185. package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +10 -7
  186. package/src/{use-nav.ts → vue/use-nav.ts} +9 -3
  187. package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +2 -2
  188. package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +3 -3
  189. package/src/{use-plans.ts → vue/use-plans.ts} +13 -13
  190. package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +9 -6
  191. package/src/{use-promotions.ts → vue/use-promotions.ts} +10 -11
  192. package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
  193. package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +2 -3
  194. package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +5 -5
  195. package/src/vue/use-super-admin-i18n.ts +82 -0
  196. package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +12 -7
  197. package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
  198. package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
  199. package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +2 -4
  200. package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +5 -5
  201. package/src/{use-tenants.ts → vue/use-tenants.ts} +3 -3
  202. package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
  203. package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
  204. package/src/components/BusinessTypeVersionEditorDialog.vue +0 -417
  205. package/src/components/BusinessTypeVersionPublishDialog.vue +0 -258
  206. package/src/pages-standard/BusinessTypesPage.vue +0 -662
  207. package/src/pages-standard/plan-versions/VersionDiffPreview.vue +0 -167
  208. package/src/use-business-types.ts +0 -269
  209. /package/src/{http-json.ts → client/http-json.ts} +0 -0
  210. /package/src/{types.ts → client/types.ts} +0 -0
  211. /package/src/{version.ts → client/version.ts} +0 -0
  212. /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
  213. /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
  214. /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 { defaultHttpClient, type HttpClient } from './types.js';
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` ist Pflicht.');
80
+ throw new Error('useCatalogEntries: `adminEndpoint` is required.');
79
81
  }
80
82
  if (!options?.projectKey) {
81
- throw new Error('useCatalogEntries: `projectKey` ist Pflicht.');
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
- `Catalog-Entries-API antwortete mit HTTP ${res.status}`,
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 './types.js';
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` ist Pflicht (z. B. "/api/admin/discovery" ' +
74
- 'oder "/api/v1/admin/discovery"). Plattform hat keinen Default, ' +
75
- 'weil Apps unterschiedliche globalPrefix-Konventionen haben.',
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
- `Discovery-Endpoint antwortete mit HTTP ${res.status}`,
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
- `Discovery-Rescan antwortete mit HTTP ${res.status}`,
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 './types.js';
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` ist Pflicht (z. B. "/api/billing/entitlement" ' +
48
- 'oder "/api/v1/billing/entitlement"). Plattform hat keinen Default, weil ' +
49
- 'Apps unterschiedliche globalPrefix-Konventionen haben.',
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 './types.js';
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` ist Pflicht.');
36
+ throw new Error('useLivePlanVersions: `adminEndpoint` is required.');
37
37
  }
38
38
  if (!options?.plans) {
39
- throw new Error('useLivePlanVersions: `plans` ist Pflicht.');
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} beim Laden der Versionen für Plan '${planId}'`);
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: Plan '${plan.planKey}' Versions-Load failed`,
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 './manifest-loader.js';
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 Bundle/BusinessType, **without versioning**: marketing edits
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 './types.js';
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` ist Pflicht.');
58
+ throw new Error('useMarketingProjections: `adminEndpoint` is required.');
57
59
  }
58
60
  if (!options?.filter?.projectKey) {
59
- throw new Error('useMarketingProjections: `filter.projectKey` ist Pflicht.');
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
- `MarketingProjections-API antwortete mit HTTP ${res.status}`,
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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
- } from './nav-builder.js';
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[]>(() => buildSidebar(routes.value));
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
- `Folgende Features sind im Catalog als plannedOnly markiert und ` +
35
- `dürfen nicht in einer Plan-Version stehen: ${violations.sort().join(', ')}.`,
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\` ist Pflicht (z. B. "/api/admin/${label}" ` +
61
- `oder "/api/v1/admin/${label}"). Plattform hat keinen Default, ` +
62
- `weil Apps unterschiedliche globalPrefix-Konventionen haben.`,
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 './types.js';
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` ist Pflicht (z. B. "/api/admin" oder ' + '"/api/v1/admin").',
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` ist Pflicht.');
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-API antwortete mit HTTP ${res.status}`,
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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` ist Pflicht.');
248
+ throw new Error('usePlanVersions: `adminEndpoint` is required.');
249
249
  }
250
250
  if (!options?.planId) {
251
- throw new Error('usePlanVersions: `planId` ist Pflicht.');
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-API antwortete mit HTTP ${res.status}`,
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 mfaDescription = options.mfaDescription ?? DEFAULT_MFA_DESCRIPTION;
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
- CreatePromotionData,
10
- PromotionRow,
11
- UpdatePromotionData,
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` ist Pflicht.');
44
+ throw new Error('usePromotions: `adminEndpoint` is required.');
47
45
  }
48
46
  if (!options?.projectKey) {
49
- throw new Error('usePromotions: `projectKey` ist Pflicht.');
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
- `Promotions-API antwortete mit HTTP ${res.status}`,
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 gab keinen Body zurück');
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 gab keinen Body zurück');
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 './boot-loader.js';
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
- | Ref<PublicMarketingBundle[] | null>
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 ist nicht gesetzt');
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 './create-super-admin-app.js';
21
- import { defaultHttpClient, type HttpClient } from './types.js';
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(): kein SuperAdmin-Branding im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?',
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(): keine Endpoints im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?',
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(): kein Login-Adapter registriert. Reiche ihn via createSuperAdminApp({ loginAdapter }) ein.',
80
+ 'useSuperAdminLoginAdapter(): no login adapter registered. Pass it via createSuperAdminApp({ loginAdapter }).',
81
81
  );
82
82
  }
83
83
  return adapter;