@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
@@ -2,8 +2,10 @@
2
2
  <div class="sa-pilots">
3
3
  <header class="sa-page-head">
4
4
  <div>
5
- <h1 class="sa-page-head__title">Pilot-Mandanten</h1>
6
- <p class="sa-page-head__sub">{{ rows.length }} Pilot-Tenants insgesamt.</p>
5
+ <h1 class="sa-page-head__title">{{ msg.title }}</h1>
6
+ <p class="sa-page-head__sub">
7
+ {{ formatMessage(msg.subtitleCount, { count: rows.length }) }}
8
+ </p>
7
9
  </div>
8
10
  <div class="sa-page-head__actions">
9
11
  <slot name="head-actions">
@@ -12,7 +14,7 @@
12
14
  unelevated
13
15
  color="primary"
14
16
  icon="add"
15
- :label="createLabel"
17
+ :label="resolvedCreateLabel"
16
18
  @click="showCreate = true"
17
19
  />
18
20
  </slot>
@@ -38,7 +40,7 @@
38
40
 
39
41
  <q-banner v-if="reviewSoon.length" class="bg-amber-2 text-grey-9 q-mb-md" rounded>
40
42
  <template #avatar><q-icon name="event" color="amber-9" /></template>
41
- {{ reviewSoon.length }} Pilot-Mandanten enden in den nächsten 30 Tagen — bitte prüfen.
43
+ {{ formatMessage(msg.list.reviewSoonBanner, { count: reviewSoon.length }) }}
42
44
  </q-banner>
43
45
 
44
46
  <div class="sa-pilots__card">
@@ -109,6 +111,9 @@
109
111
  <script setup lang="ts">
110
112
  import { computed, onMounted, ref } from 'vue';
111
113
  import { useQuasar } from 'quasar';
114
+ import { formatMessage } from '../client/i18n/format.js';
115
+ import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
116
+ import { useSuperAdminNotify } from '../quasar/notify.js';
112
117
  import PilotCreateDialog from '../components/dialogs/PilotCreateDialog.vue';
113
118
  import PilotEditDialog from '../components/dialogs/PilotEditDialog.vue';
114
119
  import MfaPromptDialog from '../components/MfaPromptDialog.vue';
@@ -194,12 +199,17 @@ const props = withDefaults(
194
199
  requireMfa: false,
195
200
  requireMfaForExtend: false,
196
201
  requireMfaForRevoke: false,
197
- createLabel: 'Pilot anlegen',
198
202
  defaultActions: () => ['edit', 'extend', 'revoke'],
199
203
  },
200
204
  );
201
205
 
206
+ const msg = useSaMessages('pilots');
207
+ const common = useSaMessages('common');
208
+ const { intlLocale } = useSuperAdminI18n();
209
+ const resolvedCreateLabel = computed(() => props.createLabel ?? msg.value.createAction);
210
+
202
211
  const q = useQuasar();
212
+ const notify = useSuperAdminNotify();
203
213
  const rows = ref<PilotRow[]>([]);
204
214
  const reviewSoon = ref<PilotRow[]>([]);
205
215
  const loading = ref(false);
@@ -289,53 +299,53 @@ const statTiles = computed<
289
299
  const counts = { all: rows.value.length, active: 0, expiring: 0, expired: 0 };
290
300
  for (const r of rows.value) counts[classifyRow(r)]++;
291
301
  return [
292
- { id: 'all', label: 'Alle', count: counts.all },
293
- { id: 'active', label: 'Aktiv', count: counts.active, tone: 'positive' },
302
+ { id: 'all', label: common.value.all, count: counts.all },
303
+ { id: 'active', label: common.value.active, count: counts.active, tone: 'positive' },
294
304
  {
295
305
  id: 'expiring',
296
- label: 'Läuft bald aus',
306
+ label: msg.value.list.tileExpiring,
297
307
  count: counts.expiring,
298
308
  tone: 'warn',
299
- hint: '≤ 14 Tage',
309
+ hint: msg.value.list.tileExpiringHint,
300
310
  },
301
- { id: 'expired', label: 'Abgelaufen', count: counts.expired, tone: 'danger' },
311
+ { id: 'expired', label: common.value.expired, count: counts.expired, tone: 'danger' },
302
312
  ];
303
313
  });
304
314
 
305
- const baseColumns = [
315
+ const baseColumns = computed(() => [
306
316
  {
307
317
  name: 'slug',
308
- label: 'Slug',
318
+ label: msg.value.list.columnSlug,
309
319
  field: (r: PilotRow) => r.tenant.slug,
310
320
  align: 'left' as const,
311
321
  sortable: true,
312
322
  },
313
323
  {
314
324
  name: 'name',
315
- label: 'Name',
325
+ label: common.value.name,
316
326
  field: (r: PilotRow) => r.tenant.name,
317
327
  align: 'left' as const,
318
328
  },
319
- { name: 'plan', label: 'Plan', field: 'plan', align: 'left' as const },
329
+ { name: 'plan', label: msg.value.list.columnPlan, field: 'plan', align: 'left' as const },
320
330
  {
321
331
  name: 'note',
322
- label: 'Note',
332
+ label: msg.value.list.columnNote,
323
333
  field: (r: PilotRow) => r.pilotNote ?? '—',
324
334
  align: 'left' as const,
325
335
  },
326
336
  {
327
337
  name: 'grantedBy',
328
- label: 'Granted by',
338
+ label: msg.value.list.columnGrantedBy,
329
339
  field: (r: PilotRow) => r.grantedBy ?? '—',
330
340
  align: 'left' as const,
331
341
  },
332
342
  {
333
343
  name: 'pilotEndsAt',
334
- label: 'Endet',
344
+ label: msg.value.list.columnEndsAt,
335
345
  field: (r: PilotRow) => formatDate(r.pilotEndsAt) ?? '∞',
336
346
  align: 'left' as const,
337
347
  },
338
- ];
348
+ ]);
339
349
 
340
350
  // Built-in default actions (edit/extend/revoke) — are APPENDED to the
341
351
  // consumer `actions`, not replaced. Order follows the `defaultActions` prop.
@@ -345,7 +355,7 @@ const bakedActions = computed<PilotRowAction[]>(() => {
345
355
  if (id === 'edit' && props.enableEdit && props.submitEdit) {
346
356
  out.push({
347
357
  id: 'edit',
348
- label: 'Bearbeiten',
358
+ label: common.value.edit,
349
359
  icon: 'edit',
350
360
  color: 'primary',
351
361
  handler: (row) => onEditClick(row),
@@ -353,7 +363,7 @@ const bakedActions = computed<PilotRowAction[]>(() => {
353
363
  } else if (id === 'extend' && props.enableExtend && props.submitExtend) {
354
364
  out.push({
355
365
  id: 'extend',
356
- label: 'Verlängern',
366
+ label: msg.value.list.actionExtend,
357
367
  icon: 'event_repeat',
358
368
  color: 'primary',
359
369
  handler: (row) => onExtendClick(row),
@@ -361,7 +371,7 @@ const bakedActions = computed<PilotRowAction[]>(() => {
361
371
  } else if (id === 'revoke' && props.enableRevoke && props.submitRevoke) {
362
372
  out.push({
363
373
  id: 'revoke',
364
- label: 'Widerrufen',
374
+ label: msg.value.list.actionRevoke,
365
375
  icon: 'block',
366
376
  color: 'negative',
367
377
  handler: (row) => onRevokeClick(row),
@@ -377,7 +387,7 @@ const mergedActions = computed<readonly PilotRowAction[]>(() => [
377
387
  ]);
378
388
 
379
389
  const effectiveColumns = computed(() => {
380
- const cols = [...baseColumns];
390
+ const cols = [...baseColumns.value];
381
391
  if (mergedActions.value.length > 0) {
382
392
  cols.push({
383
393
  name: 'actions',
@@ -435,7 +445,7 @@ function errMsg(err: unknown): string {
435
445
  return (
436
446
  (err as { response?: { data?: { message?: string } } })?.response?.data?.message ??
437
447
  (err as Error)?.message ??
438
- 'Aktion fehlgeschlagen'
448
+ msg.value.list.actionFailed
439
449
  );
440
450
  }
441
451
 
@@ -445,22 +455,24 @@ function onEditClick(row: PilotRow): void {
445
455
  }
446
456
 
447
457
  function onUpdated(result: PilotEditResult): void {
448
- q.notify({
449
- type: 'positive',
450
- message: `Pilot ${result.slug} aktualisiert.`,
451
- caption: result.changed?.length ? `Geändert: ${result.changed.join(', ')}` : undefined,
452
- position: 'top',
458
+ notify('positive', formatMessage(msg.value.list.updatedNotice, { slug: result.slug }), {
459
+ caption: result.changed?.length
460
+ ? formatMessage(msg.value.list.updatedChangedCaption, {
461
+ fields: result.changed.join(', '),
462
+ })
463
+ : undefined,
453
464
  });
454
465
  void reload();
455
466
  }
456
467
 
457
468
  function onCreated(result: PilotCreateResult): void {
458
- q.notify({
459
- type: 'positive',
460
- message: `Pilot ${result.slug} angelegt.`,
461
- caption: result.initialPassword ? `Initial-Passwort: ${result.initialPassword}` : undefined,
462
- position: 'top',
463
- timeout: 8000,
469
+ notify('positive', formatMessage(msg.value.list.createdNotice, { slug: result.slug }), {
470
+ caption: result.initialPassword
471
+ ? formatMessage(msg.value.list.createdPasswordCaption, {
472
+ password: result.initialPassword,
473
+ })
474
+ : undefined,
475
+ timeoutMs: 8000,
464
476
  });
465
477
  void reload();
466
478
  }
@@ -476,10 +488,10 @@ async function runAction(
476
488
  if (!requireMfa) {
477
489
  try {
478
490
  await invoke('');
479
- q.notify({ type: 'positive', message: successMessage, position: 'top' });
491
+ notify('positive', successMessage);
480
492
  await reload();
481
493
  } catch (err) {
482
- q.notify({ type: 'negative', message: errMsg(err), position: 'top' });
494
+ notify('negative', errMsg(err));
483
495
  }
484
496
  return;
485
497
  }
@@ -491,17 +503,17 @@ async function runAction(
491
503
  try {
492
504
  await invoke(code);
493
505
  showMfa.value = false;
494
- q.notify({ type: 'positive', message: successMessage, position: 'top' });
506
+ notify('positive', successMessage);
495
507
  await reload();
496
508
  return;
497
509
  } catch (err) {
498
510
  const status = (err as { response?: { status?: number } })?.response?.status;
499
511
  if (status === 401) {
500
- mfaError.value = 'TOTP-Code ungültig oder MFA nicht eingerichtet.';
512
+ mfaError.value = msg.value.mfa.invalidOrNotSetUp;
501
513
  continue;
502
514
  }
503
515
  showMfa.value = false;
504
- q.notify({ type: 'negative', message: errMsg(err), position: 'top' });
516
+ notify('negative', errMsg(err));
505
517
  return;
506
518
  }
507
519
  }
@@ -511,19 +523,19 @@ function onExtendClick(row: PilotRow): void {
511
523
  if (!props.submitExtend) return;
512
524
  const submit = props.submitExtend;
513
525
  q.dialog({
514
- title: `Pilot ${row.tenant.slug} verlängern`,
515
- message: 'Neues Enddatum:',
526
+ title: formatMessage(msg.value.list.extendTitle, { slug: row.tenant.slug }),
527
+ message: msg.value.list.extendMessage,
516
528
  prompt: {
517
529
  model: row.pilotEndsAt?.slice(0, 10) ?? '',
518
530
  type: 'date',
519
531
  },
520
- cancel: 'Abbrechen',
521
- ok: { label: 'Verlängern', color: 'primary' },
532
+ cancel: common.value.cancel,
533
+ ok: { label: msg.value.list.actionExtend, color: 'primary' },
522
534
  }).onOk(async (until: string) => {
523
535
  if (!until) return;
524
536
  await runAction(
525
- `Pilot "${row.tenant.slug}" bis ${until} verlängern.`,
526
- `Pilot bis ${until} verlängert.`,
537
+ formatMessage(msg.value.list.extendMfaDescription, { slug: row.tenant.slug, until }),
538
+ formatMessage(msg.value.list.extendSuccess, { until }),
527
539
  !!props.requireMfaForExtend,
528
540
  (code) => submit(row.tenant.slug, until, code),
529
541
  );
@@ -534,14 +546,14 @@ function onRevokeClick(row: PilotRow): void {
534
546
  if (!props.submitRevoke) return;
535
547
  const submit = props.submitRevoke;
536
548
  q.dialog({
537
- title: `Pilot ${row.tenant.slug} widerrufen`,
538
- message: 'Pilot-Status entfernen. Subscription bleibt bestehen.',
539
- cancel: 'Abbrechen',
540
- ok: { label: 'Widerrufen', color: 'negative' },
549
+ title: formatMessage(msg.value.list.revokeTitle, { slug: row.tenant.slug }),
550
+ message: msg.value.list.revokeMessage,
551
+ cancel: common.value.cancel,
552
+ ok: { label: msg.value.list.actionRevoke, color: 'negative' },
541
553
  }).onOk(async () => {
542
554
  await runAction(
543
- `Pilot-Status für "${row.tenant.slug}" widerrufen.`,
544
- 'Pilot widerrufen.',
555
+ formatMessage(msg.value.list.revokeMfaDescription, { slug: row.tenant.slug }),
556
+ msg.value.list.revokeSuccess,
545
557
  !!props.requireMfaForRevoke,
546
558
  (code) => submit(row.tenant.slug, code),
547
559
  );
@@ -551,7 +563,7 @@ function onRevokeClick(row: PilotRow): void {
551
563
  function formatDate(iso: string | null | undefined): string | null {
552
564
  if (!iso) return null;
553
565
  try {
554
- return new Date(iso).toLocaleDateString('de-DE', {
566
+ return new Date(iso).toLocaleDateString(intlLocale.value, {
555
567
  day: '2-digit',
556
568
  month: 'short',
557
569
  year: 'numeric',
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="sa-pv">
3
3
  <div v-if="loading" class="sa-pv__loading">
4
- <q-spinner size="32px" /> Catalog wird geladen…
4
+ <q-spinner size="32px" /> {{ msg.page.loadingCatalog }}
5
5
  </div>
6
6
 
7
7
  <template v-else>
@@ -63,7 +63,7 @@
63
63
  :action-meta="auditActionMeta"
64
64
  />
65
65
  <div v-else class="sa-pv__no-audit">
66
- Kein Audit-Loader konfiguriert.
66
+ {{ msg.page.noAuditLoader }}
67
67
  </div>
68
68
  </slot>
69
69
  </template>
@@ -76,8 +76,8 @@
76
76
 
77
77
  <script setup lang="ts">
78
78
  import { computed, ref, watch } from 'vue';
79
- import type { CatalogSnapshot, RawCatalogData } from '../plan-versions-catalog.js';
80
- import { buildSnapshots } from '../plan-versions-catalog.js';
79
+ import type { CatalogSnapshot, RawCatalogData } from '../client/plan-versions-catalog.js';
80
+ import { buildSnapshots } from '../client/plan-versions-catalog.js';
81
81
  import PlanVersionsTimeline from './plan-versions/PlanVersionsTimeline.vue';
82
82
  import PlanVersionHeader from './plan-versions/PlanVersionHeader.vue';
83
83
  import PlanVersionsList, { type QuotaColumnConfig } from './plan-versions/PlanVersionsList.vue';
@@ -85,6 +85,7 @@ import PlanVersionsMatrix from './plan-versions/PlanVersionsMatrix.vue';
85
85
  import PlanVersionsAudit from './plan-versions/PlanVersionsAudit.vue';
86
86
  import PlanVersionsDiff from './plan-versions/PlanVersionsDiff.vue';
87
87
  import type { PlanVersionViewMode } from './plan-versions/types.js';
88
+ import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
88
89
 
89
90
  // Platform standard page: plan versions.
90
91
  //
@@ -153,12 +154,15 @@ const emit = defineEmits<{
153
154
  (e: 'createPlanDraft', planId: string): void;
154
155
  }>();
155
156
 
157
+ const msg = useSaMessages('planVersions');
158
+ const { locale } = useSuperAdminI18n();
159
+
156
160
  const selectedId = ref<string>('drafts');
157
161
  const compareId = ref<string | null>(null);
158
162
  const viewMode = ref<PlanVersionViewMode>('list');
159
163
 
160
164
  const snapshots = computed<CatalogSnapshot[]>(() =>
161
- buildSnapshots(props.data, { planSortOrder: props.planSortOrder }),
165
+ buildSnapshots(props.data, { planSortOrder: props.planSortOrder, locale: locale.value }),
162
166
  );
163
167
 
164
168
  const selected = computed<CatalogSnapshot | null>(