@saasicat/ui-vue 0.19.0 → 0.22.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 (145) hide show
  1. package/dist/{catalog-JXdKdIqG.d.cts → catalog-DJcfm5N2.d.cts} +21 -7
  2. package/dist/{catalog-JXdKdIqG.d.ts → catalog-DJcfm5N2.d.ts} +21 -7
  3. package/dist/{chunk-DPTIOQXX.js → chunk-F7NRM6KI.js} +56 -28
  4. package/dist/{chunk-RVG6LQHL.js → chunk-LY52T4N4.js} +21 -2
  5. package/dist/{chunk-ORX3ZG47.js → chunk-XMMFN2WJ.js} +74 -3
  6. package/dist/client/index.cjs +134 -29
  7. package/dist/client/index.d.cts +53 -3
  8. package/dist/client/index.d.ts +53 -3
  9. package/dist/client/index.js +14 -2
  10. package/dist/index.cjs +321 -162
  11. package/dist/index.d.cts +30 -8
  12. package/dist/index.d.ts +30 -8
  13. package/dist/index.js +176 -133
  14. package/dist/quasar/index.cjs +78 -29
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +6 -2
  18. package/dist/testing-e2e/admin-pages-suite.d.cts +37 -0
  19. package/dist/testing-e2e/admin-pages-suite.d.ts +37 -0
  20. package/dist/{use-super-admin-i18n-BlqcD0N7.d.ts → use-super-admin-i18n-CHNdsSlm.d.ts} +34 -7
  21. package/dist/{use-super-admin-i18n-1nCOkvgi.d.cts → use-super-admin-i18n-CgTuNi8h.d.cts} +34 -7
  22. package/package.json +18 -8
  23. package/src/client/i18n/messages/bundles.ts +0 -2
  24. package/src/client/i18n/messages/common.ts +24 -0
  25. package/src/client/i18n/messages/discovery.ts +2 -2
  26. package/src/client/i18n/messages/marketing.ts +2 -4
  27. package/src/client/i18n/messages/plan-detail.ts +0 -4
  28. package/src/client/i18n/messages/plans.ts +20 -8
  29. package/src/client/i18n/messages/tenants.ts +0 -2
  30. package/src/client/index.ts +1 -0
  31. package/src/client/manifest-loader.ts +1 -1
  32. package/src/client/resolve-plans.ts +144 -0
  33. package/src/components/BundleVersionPublishDialog.vue +6 -6
  34. package/src/components/KvBlock.vue +4 -4
  35. package/src/components/MarketingPromotionsTab.vue +34 -48
  36. package/src/components/MfaPromptDialog.vue +8 -2
  37. package/src/components/TenantActionConfirmDialog.vue +4 -4
  38. package/src/components/VersionDiffPreview.vue +7 -7
  39. package/src/components/admin-page/AdminBody.vue +40 -0
  40. package/src/components/admin-page/AdminFilters.vue +12 -0
  41. package/src/components/admin-page/AdminHero.vue +49 -0
  42. package/src/components/admin-page/AdminKpi.vue +84 -0
  43. package/src/components/admin-page/AdminPage.vue +16 -0
  44. package/src/components/admin-page/AdminPaginator.vue +195 -0
  45. package/src/components/admin-page/AdminRefreshBtn.vue +39 -0
  46. package/src/components/admin-page/AdminSection.vue +53 -0
  47. package/src/components/admin-page/AdminStatistics.vue +40 -0
  48. package/src/components/admin-page/AdminTable.vue +175 -0
  49. package/src/components/bundle-editor/BundleCreatePanel.vue +23 -23
  50. package/src/components/bundle-editor/BundleFeaturesEditor.vue +7 -7
  51. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +9 -9
  52. package/src/components/bundle-editor/BundleQuotasEditor.vue +11 -11
  53. package/src/components/bundle-editor/BundleStatusBanner.vue +6 -6
  54. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +18 -18
  55. package/src/components/bundle-editor/BundleVersionStrip.vue +12 -12
  56. package/src/components/dialogs/PilotCreateDialog.vue +12 -12
  57. package/src/components/dialogs/PilotEditDialog.vue +7 -7
  58. package/src/components/dialogs/PromoCodeCreateDialog.vue +8 -8
  59. package/src/components/dialogs/PromoCodeDialogFields.vue +33 -19
  60. package/src/components/dialogs/PromoCodeEditDialog.vue +10 -10
  61. package/src/components/plan/PlanGrid.vue +1 -1
  62. package/src/components/plan-create-dialog/PlanCreateDialog.vue +34 -46
  63. package/src/components/plan-detail/PlanAuditLog.vue +7 -8
  64. package/src/components/plan-detail/PlanDetail.vue +95 -292
  65. package/src/components/plan-detail/PlanDetailKpis.vue +22 -27
  66. package/src/components/plan-detail/PlanTitleEdit.vue +133 -0
  67. package/src/components/plan-detail/PlanVersionDiffPanel.vue +5 -8
  68. package/src/components/plan-detail/PlanVersionsPanel.vue +9 -11
  69. package/src/components/plan-list/PlanList.vue +206 -457
  70. package/src/components/plan-matrix/PlanMatrix.vue +66 -183
  71. package/src/components/plan-review/PlanReview.vue +191 -275
  72. package/src/components/plan-version-editor/PlanCatalogPreview.vue +7 -5
  73. package/src/components/plan-version-editor/PlanVersionEditor.vue +200 -295
  74. package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +23 -55
  75. package/src/index.ts +1 -0
  76. package/src/pages-standard/AdminLayout.vue +38 -12
  77. package/src/pages-standard/AdminManifestErrorPage.vue +79 -9
  78. package/src/pages-standard/AuditPage.vue +65 -109
  79. package/src/pages-standard/BundlesPage.vue +146 -179
  80. package/src/pages-standard/DashboardPage.vue +59 -154
  81. package/src/pages-standard/DiscoveryPage.vue +172 -227
  82. package/src/pages-standard/EmailHistoryPage.vue +118 -159
  83. package/src/pages-standard/MarketingCatalogPage.vue +399 -440
  84. package/src/pages-standard/PilotsPage.vue +69 -117
  85. package/src/pages-standard/PlansPage.vue +240 -112
  86. package/src/pages-standard/PlatformEmailPage.vue +56 -91
  87. package/src/pages-standard/PromoCodeDetailPage.vue +49 -74
  88. package/src/pages-standard/PromoCodesPage.vue +95 -128
  89. package/src/pages-standard/SubscriptionsPage.vue +19 -52
  90. package/src/pages-standard/SuperAdminLoginPage.vue +12 -12
  91. package/src/pages-standard/SuperAdminSetupWizard.vue +22 -18
  92. package/src/pages-standard/TenantDetailPage.vue +100 -191
  93. package/src/pages-standard/TenantsPage.vue +190 -295
  94. package/src/pages-standard/UsersPage.vue +89 -157
  95. package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -17
  96. package/src/pages-standard/bundles-page/BundlesKpis.vue +13 -22
  97. package/src/pages-standard/bundles-page/BundlesToolbar.vue +63 -0
  98. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +10 -10
  99. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -5
  100. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +16 -16
  101. package/src/pages-standard/discovery-page/DiscoveryKpis.vue +31 -27
  102. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +7 -7
  103. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +111 -73
  104. package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +43 -62
  105. package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +53 -35
  106. package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +7 -7
  107. package/src/pages-standard/plan-versions/PlanDiffCard.vue +6 -6
  108. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +6 -6
  109. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +16 -16
  110. package/src/pages-standard/plans-page/PlanBundleOverview.vue +14 -29
  111. package/src/pages-standard/plans-page/PlanPublishDialog.vue +1 -1
  112. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  113. package/src/pages-standard/sa-theme.css +552 -86
  114. package/src/pages-standard/tenant-detail/TenantMasterData.vue +28 -0
  115. package/src/pages-standard/tenant-detail/TenantUsage.vue +31 -0
  116. package/src/pages-standard/tenant-detail/TenantUsers.vue +15 -0
  117. package/src/pages-standard/tenant-detail/types.ts +38 -0
  118. package/src/pages-standard/tenants/StatusPill.vue +2 -2
  119. package/src/pages-tenant/MySubscriptionBundlesPage.vue +25 -25
  120. package/src/pages-tenant/OnboardingConfigurator.vue +1 -5
  121. package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
  122. package/src/pages-tenant/TenantPlanSection.vue +12 -20
  123. package/src/quasar/create-super-admin-app.ts +4 -0
  124. package/src/vue/entitlement-provider.ts +0 -1
  125. package/src/vue/feature-router-guard.ts +0 -1
  126. package/src/vue/super-admin-context.ts +106 -1
  127. package/src/vue/use-api-list.ts +2 -1
  128. package/src/vue/use-mfa-prompt.ts +72 -0
  129. package/src/vue/use-pagination.ts +63 -0
  130. package/src/vue/use-plans.ts +1 -2
  131. package/src/vue/use-sign-out.ts +90 -0
  132. package/src/vue/use-tenant-billing.ts +1 -1
  133. package/src/vue/use-tenant-manifest.ts +0 -1
  134. package/src/components/KpiCard.vue +0 -53
  135. package/src/components/plan-cockpit/PlanCockpit.vue +0 -1012
  136. package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +0 -72
  137. package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +0 -100
  138. package/src/components/plan-cockpit/PlanCockpitHeader.vue +0 -101
  139. package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +0 -112
  140. package/src/components/plan-cockpit/PlanCockpitKpis.vue +0 -68
  141. package/src/components/plan-cockpit/PlanCockpitVersions.vue +0 -251
  142. package/src/components/plan-cockpit/types.ts +0 -72
  143. package/src/components/plan-detail/PlanDetailHeader.vue +0 -194
  144. package/src/pages-standard/bundles-page/BundlesHeader.vue +0 -68
  145. package/src/pages-standard/discovery-page/DiscoveryHeader.vue +0 -34
@@ -39,6 +39,7 @@ __export(client_exports, {
39
39
  SA_MESSAGES: () => SA_MESSAGES,
40
40
  buildRoutes: () => buildRoutes,
41
41
  buildSidebar: () => buildSidebar,
42
+ countPlans: () => countPlans,
42
43
  createAdminResourceClient: () => createAdminResourceClient,
43
44
  createSaCatalog: () => createSaCatalog,
44
45
  defaultHttpClient: () => defaultHttpClient,
@@ -48,6 +49,9 @@ __export(client_exports, {
48
49
  formatCurrency: () => formatCurrency,
49
50
  formatMessage: () => formatMessage,
50
51
  getJson: () => getJson,
52
+ isCurrentlyValid: () => isCurrentlyValid,
53
+ isExpired: () => isExpired,
54
+ isFutureScheduled: () => isFutureScheduled,
51
55
  isProductionBoot: () => isProductionBoot,
52
56
  isSaBuiltinLocale: () => isSaBuiltinLocale,
53
57
  mergeMessages: () => mergeMessages,
@@ -55,6 +59,8 @@ __export(client_exports, {
55
59
  resolveExtension: () => resolveExtension,
56
60
  resolveLoginBranding: () => resolveLoginBranding,
57
61
  resolveMessages: () => resolveMessages,
62
+ resolvePlans: () => resolvePlans,
63
+ todayIsoDate: () => todayIsoDate,
58
64
  trimTrailingSlashes: () => trimTrailingSlashes
59
65
  });
60
66
  module.exports = __toCommonJS(client_exports);
@@ -233,7 +239,7 @@ var ManifestLoader = class {
233
239
  if (res.status !== 200) {
234
240
  throw new ManifestLoadError(
235
241
  res.status,
236
- `Manifest-Endpunkt antwortete HTTP ${res.status}`
242
+ `Manifest endpoint responded with HTTP ${res.status}`
237
243
  );
238
244
  }
239
245
  const body = await res.json();
@@ -839,8 +845,7 @@ var bundlesMessages = defineMessages(
839
845
  title: "Bundles",
840
846
  subtitle: "Produktgruppen aus Features & Quotas \u2014 verwendet in Pl\xE4nen. Bundles werden im SuperAdmin kuratiert.",
841
847
  displayLocale: "Anzeige-Sprache",
842
- newBundle: "Neues Bundle",
843
- reload: "Liste neu laden"
848
+ newBundle: "Neues Bundle"
844
849
  },
845
850
  filter: {
846
851
  all: "Alle Status",
@@ -1054,8 +1059,7 @@ var bundlesMessages = defineMessages(
1054
1059
  title: "Bundles",
1055
1060
  subtitle: "Product groups made of features & quotas \u2014 used in plans. Bundles are curated in the SuperAdmin.",
1056
1061
  displayLocale: "Display language",
1057
- newBundle: "New bundle",
1058
- reload: "Reload list"
1062
+ newBundle: "New bundle"
1059
1063
  },
1060
1064
  filter: {
1061
1065
  all: "All statuses",
@@ -1254,6 +1258,9 @@ var commonMessages = defineMessages(
1254
1258
  loading: "Lade \u2026",
1255
1259
  saving: "Speichere \u2026",
1256
1260
  loadingData: "Daten werden geladen\u2026",
1261
+ noData: "Keine Daten vorhanden",
1262
+ filters: "Filter",
1263
+ results: "Ergebnisse",
1257
1264
  error: "Fehler",
1258
1265
  errorLoadFailed: "Laden fehlgeschlagen",
1259
1266
  errorSaveFailed: "Speichern fehlgeschlagen",
@@ -1299,7 +1306,16 @@ var commonMessages = defineMessages(
1299
1306
  unlimited: "unbegrenzt",
1300
1307
  both: "Beide",
1301
1308
  createFailed: "Anlegen fehlgeschlagen",
1302
- noChanges: "Keine \xC4nderungen"
1309
+ noChanges: "Keine \xC4nderungen",
1310
+ paginator: {
1311
+ label: "Seitennavigation",
1312
+ rowsPerPage: "Zeilen pro Seite",
1313
+ all: "Alle",
1314
+ page: "Seite {page}/{pages}",
1315
+ pageInput: "Seite, 1 bis {pages}",
1316
+ previous: "Vorherige Seite",
1317
+ next: "N\xE4chste Seite"
1318
+ }
1303
1319
  },
1304
1320
  {
1305
1321
  save: "Save",
@@ -1324,6 +1340,9 @@ var commonMessages = defineMessages(
1324
1340
  loading: "Loading \u2026",
1325
1341
  saving: "Saving \u2026",
1326
1342
  loadingData: "Loading data\u2026",
1343
+ noData: "No data available",
1344
+ filters: "Filters",
1345
+ results: "Results",
1327
1346
  error: "Error",
1328
1347
  errorLoadFailed: "Failed to load",
1329
1348
  errorSaveFailed: "Failed to save",
@@ -1369,7 +1388,16 @@ var commonMessages = defineMessages(
1369
1388
  unlimited: "unlimited",
1370
1389
  both: "Both",
1371
1390
  createFailed: "Creation failed",
1372
- noChanges: "No changes"
1391
+ noChanges: "No changes",
1392
+ paginator: {
1393
+ label: "Pagination",
1394
+ rowsPerPage: "Rows per page",
1395
+ all: "All",
1396
+ page: "Page {page}/{pages}",
1397
+ pageInput: "Page, 1 to {pages}",
1398
+ previous: "Previous page",
1399
+ next: "Next page"
1400
+ }
1373
1401
  }
1374
1402
  );
1375
1403
 
@@ -1474,7 +1502,7 @@ var discoveryMessages = defineMessages(
1474
1502
  quota: {
1475
1503
  usageProvider: "UsageProvider",
1476
1504
  usageProviderMissing: "fehlt",
1477
- noUsageProviderWarning: "Eine harte Quota ohne UsageProvider ist nicht deploy-f\xE4hig (Preflight, SPEC_V2 \xA76.3).",
1505
+ noUsageProviderWarning: "Eine harte Quota ohne UsageProvider ist nicht deploy-f\xE4hig (Preflight).",
1478
1506
  outdatedBanner: "Die code-abgeleiteten Quota-Fakten (Einheit/Enforcement/Provider) haben sich seit der letzten Freigabe ge\xE4ndert \u2014 bitte pr\xFCfen und"
1479
1507
  },
1480
1508
  caps: {
@@ -1578,7 +1606,7 @@ var discoveryMessages = defineMessages(
1578
1606
  quota: {
1579
1607
  usageProvider: "UsageProvider",
1580
1608
  usageProviderMissing: "missing",
1581
- noUsageProviderWarning: "A hard quota without a UsageProvider is not deployable (preflight, SPEC_V2 \xA76.3).",
1609
+ noUsageProviderWarning: "A hard quota without a UsageProvider is not deployable (preflight).",
1582
1610
  outdatedBanner: "The code-derived quota facts (unit/enforcement/provider) have changed since the last approval \u2014 please review and"
1583
1611
  },
1584
1612
  caps: {
@@ -1738,8 +1766,7 @@ var marketingMessages = defineMessages(
1738
1766
  localesLabel: "Sprachen:",
1739
1767
  defaultLocale: "Default-Sprache",
1740
1768
  deactivateLocale: "Sprache deaktivieren",
1741
- addLocale: "+ Sprache",
1742
- refresh: "Aktualisieren"
1769
+ addLocale: "+ Sprache"
1743
1770
  },
1744
1771
  page: {
1745
1772
  loading: "Lade Marketing-Catalog \u2026",
@@ -1807,7 +1834,7 @@ var marketingMessages = defineMessages(
1807
1834
  },
1808
1835
  promotionsTab: {
1809
1836
  title: "Aktionen & Rabatte",
1810
- subtitle: "Zeitlich begrenzte Preis-Aktionen \u2014 \xFCberschreiben den regul\xE4ren Preis auf der Pricing-Page (SPEC_V2 \xA79a).",
1837
+ subtitle: "Zeitlich begrenzte Preis-Aktionen \u2014 \xFCberschreiben den regul\xE4ren Preis auf der Pricing-Page.",
1811
1838
  add: "+ Aktion anlegen",
1812
1839
  timelineHead: "Aktions-Timeline \xB7 gestrichelt = heute",
1813
1840
  today: "heute",
@@ -1866,8 +1893,7 @@ var marketingMessages = defineMessages(
1866
1893
  localesLabel: "Languages:",
1867
1894
  defaultLocale: "Default language",
1868
1895
  deactivateLocale: "Deactivate language",
1869
- addLocale: "+ Language",
1870
- refresh: "Refresh"
1896
+ addLocale: "+ Language"
1871
1897
  },
1872
1898
  page: {
1873
1899
  loading: "Loading marketing catalog \u2026",
@@ -1935,7 +1961,7 @@ var marketingMessages = defineMessages(
1935
1961
  },
1936
1962
  promotionsTab: {
1937
1963
  title: "Promotions & discounts",
1938
- subtitle: "Time-limited price promotions \u2014 they override the regular price on the pricing page (SPEC_V2 \xA79a).",
1964
+ subtitle: "Time-limited price promotions \u2014 they override the regular price on the pricing page.",
1939
1965
  add: "+ Create promotion",
1940
1966
  timelineHead: "Promotion timeline \xB7 dashed = today",
1941
1967
  today: "today",
@@ -2200,10 +2226,8 @@ var planDetailMessages = defineMessages(
2200
2226
  versionsSummary: "{published} live/superseded",
2201
2227
  versionsSummaryWithDrafts: "{published} live/superseded \xB7 {drafts} Draft",
2202
2228
  openDraft: "Offener Draft",
2203
- noDraft: "Kein Draft",
2204
2229
  readyToEdit: "Bereit zum Bearbeiten",
2205
- noOpenDraft: "Keine Draft-Version offen",
2206
- createNewDraft: "Neue Draft anlegen"
2230
+ noOpenDraft: "Keine Draft-Version offen"
2207
2231
  },
2208
2232
  versions: {
2209
2233
  title: "Versionen",
@@ -2327,10 +2351,8 @@ var planDetailMessages = defineMessages(
2327
2351
  versionsSummary: "{published} live/superseded",
2328
2352
  versionsSummaryWithDrafts: "{published} live/superseded \xB7 {drafts} draft",
2329
2353
  openDraft: "Open draft",
2330
- noDraft: "No draft",
2331
2354
  readyToEdit: "Ready to edit",
2332
- noOpenDraft: "No draft version open",
2333
- createNewDraft: "Create a new draft"
2355
+ noOpenDraft: "No draft version open"
2334
2356
  },
2335
2357
  versions: {
2336
2358
  title: "Versions",
@@ -2717,6 +2739,7 @@ var plansMessages = defineMessages(
2717
2739
  // PlansPage — shell of the plan area: loading state, toasts and the
2718
2740
  // error texts of the draft/publish/archive/discard actions.
2719
2741
  page: {
2742
+ subtitle: "Pl\xE4ne b\xFCndeln Features & Quotas zu einem Angebot. Jede \xC4nderung wird als neue Version ver\xF6ffentlicht \u2014 Live-Versionen bleiben unangetastet.",
2720
2743
  loading: "Pl\xE4ne werden geladen\u2026",
2721
2744
  toastPlanCreated: "Plan {planKey} angelegt \u2014 jetzt die erste Version zusammenstellen.",
2722
2745
  toastDraftSaved: "Draft v{version} von {planKey} gespeichert.",
@@ -2763,7 +2786,10 @@ var plansMessages = defineMessages(
2763
2786
  // PlanList — default plan overview with one row per plan.
2764
2787
  list: {
2765
2788
  title: "Alle Pl\xE4ne",
2766
- summary: "{plans} Pl\xE4ne \xB7 {live} live \xB7 {drafts} offene Drafts \xB7 {tenants} Mandanten zugeordnet",
2789
+ statPlans: "Pl\xE4ne",
2790
+ statLive: "Live",
2791
+ statDrafts: "Offene Drafts",
2792
+ statTenants: "Mandanten",
2767
2793
  matrixView: "Matrix-Ansicht",
2768
2794
  newPlan: "Neuer Plan",
2769
2795
  searchPlaceholder: "Plan suchen\u2026",
@@ -2801,7 +2827,10 @@ var plansMessages = defineMessages(
2801
2827
  // PlanMatrix — all plans side by side, components as rows.
2802
2828
  matrix: {
2803
2829
  title: "Pl\xE4ne \xB7 Matrix-Vergleich",
2804
- summary: "Alle Pl\xE4ne nebeneinander \xB7 {plans} Pl\xE4ne \xB7 {features} Features \xB7 {quotas} Quotas \xB7 {bundles} Bundles",
2830
+ statPlans: "Pl\xE4ne",
2831
+ statFeatures: "Features",
2832
+ statQuotas: "Quotas",
2833
+ statBundles: "Bundles",
2805
2834
  catalogPreview: "Catalog-Vorschau",
2806
2835
  createPlan: "Plan anlegen",
2807
2836
  createPlanSub: "oder Klon erstellen",
@@ -2942,6 +2971,7 @@ var plansMessages = defineMessages(
2942
2971
  },
2943
2972
  {
2944
2973
  page: {
2974
+ subtitle: "Plans bundle features & quotas into an offering. Every change ships as a new version \u2014 live versions stay untouched.",
2945
2975
  loading: "Loading plans\u2026",
2946
2976
  toastPlanCreated: "Plan {planKey} created \u2014 now assemble the first version.",
2947
2977
  toastDraftSaved: "Draft v{version} of {planKey} saved.",
@@ -2986,7 +3016,10 @@ var plansMessages = defineMessages(
2986
3016
  },
2987
3017
  list: {
2988
3018
  title: "All plans",
2989
- summary: "{plans} plans \xB7 {live} live \xB7 {drafts} open drafts \xB7 {tenants} tenants assigned",
3019
+ statPlans: "Plans",
3020
+ statLive: "Live",
3021
+ statDrafts: "Open drafts",
3022
+ statTenants: "Tenants",
2990
3023
  matrixView: "Matrix view",
2991
3024
  newPlan: "New plan",
2992
3025
  searchPlaceholder: "Search plan\u2026",
@@ -3023,7 +3056,10 @@ var plansMessages = defineMessages(
3023
3056
  },
3024
3057
  matrix: {
3025
3058
  title: "Plans \xB7 matrix comparison",
3026
- summary: "All plans side by side \xB7 {plans} plans \xB7 {features} features \xB7 {quotas} quotas \xB7 {bundles} bundles",
3059
+ statPlans: "Plans",
3060
+ statFeatures: "Features",
3061
+ statQuotas: "Quotas",
3062
+ statBundles: "Bundles",
3027
3063
  catalogPreview: "Catalog preview",
3028
3064
  createPlan: "Create plan",
3029
3065
  createPlanSub: "or create a clone",
@@ -3512,8 +3548,7 @@ var tenantsMessages = defineMessages(
3512
3548
  columnUsage: "Verbrauch",
3513
3549
  columnCreatedAt: "Angelegt",
3514
3550
  suspended: "Suspendiert",
3515
- empty: "Keine Mandanten mit diesen Filtern.",
3516
- pagination: "{total} Mandanten \xB7 Seite {page} / {pages}"
3551
+ empty: "Keine Mandanten mit diesen Filtern."
3517
3552
  },
3518
3553
  detail: {
3519
3554
  backToList: "Mandanten-Liste",
@@ -3561,8 +3596,7 @@ var tenantsMessages = defineMessages(
3561
3596
  columnUsage: "Usage",
3562
3597
  columnCreatedAt: "Created",
3563
3598
  suspended: "Suspended",
3564
- empty: "No tenants match these filters.",
3565
- pagination: "{total} tenants \xB7 Page {page} / {pages}"
3599
+ empty: "No tenants match these filters."
3566
3600
  },
3567
3601
  detail: {
3568
3602
  backToList: "Tenant list",
@@ -3757,6 +3791,71 @@ function resolveLoginBranding(boot, fallback = {}) {
3757
3791
  function isProductionBoot(boot) {
3758
3792
  return boot?.project?.environment === "production";
3759
3793
  }
3794
+
3795
+ // src/client/resolve-plans.ts
3796
+ function todayIsoDate() {
3797
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3798
+ }
3799
+ function isCurrentlyValid(v, today) {
3800
+ if (!v.publishedAt) return false;
3801
+ if (v.validFrom && v.validFrom.slice(0, 10) > today) return false;
3802
+ if (v.validUntil && v.validUntil.slice(0, 10) < today) return false;
3803
+ return true;
3804
+ }
3805
+ function isFutureScheduled(v, today) {
3806
+ if (!v.publishedAt) return false;
3807
+ if (!v.validFrom) return false;
3808
+ return v.validFrom.slice(0, 10) > today;
3809
+ }
3810
+ function isExpired(v, today) {
3811
+ if (!v.publishedAt) return false;
3812
+ if (!v.validUntil) return false;
3813
+ return v.validUntil.slice(0, 10) < today;
3814
+ }
3815
+ function resolvePlans({
3816
+ plans,
3817
+ versionsByPlanId,
3818
+ tenantCountsByPlanKey,
3819
+ today = todayIsoDate()
3820
+ }) {
3821
+ return [...plans].sort((a, b) => a.sortOrder - b.sortOrder || a.planKey.localeCompare(b.planKey)).map((plan) => {
3822
+ const versions = versionsByPlanId[plan.id] ?? [];
3823
+ const drafts = versions.filter((v) => !v.publishedAt);
3824
+ const published = versions.filter((v) => Boolean(v.publishedAt));
3825
+ const currentLive = published.find((v) => isCurrentlyValid(v, today)) ?? null;
3826
+ const futureScheduled = published.filter((v) => isFutureScheduled(v, today)).sort((a, b) => (a.validFrom ?? "").localeCompare(b.validFrom ?? ""));
3827
+ const primary = currentLive ?? futureScheduled[0] ?? null;
3828
+ const seen = /* @__PURE__ */ new Set();
3829
+ if (primary) seen.add(primary.id);
3830
+ const subRows = [];
3831
+ for (const v of [...futureScheduled, ...drafts]) {
3832
+ if (seen.has(v.id)) continue;
3833
+ subRows.push(v);
3834
+ seen.add(v.id);
3835
+ }
3836
+ return {
3837
+ plan,
3838
+ planKey: plan.planKey,
3839
+ label: plan.label,
3840
+ description: plan.description ?? null,
3841
+ currentLive,
3842
+ primary,
3843
+ subRows,
3844
+ hasAnyVersion: versions.length > 0,
3845
+ allExpired: versions.length > 0 && drafts.length === 0 && futureScheduled.length === 0 && published.every((v) => isExpired(v, today)),
3846
+ draft: drafts[0] ?? null,
3847
+ tenantCount: tenantCountsByPlanKey[plan.planKey] ?? 0
3848
+ };
3849
+ });
3850
+ }
3851
+ function countPlans(resolved) {
3852
+ return {
3853
+ plans: resolved.length,
3854
+ live: resolved.filter((p) => p.currentLive !== null).length,
3855
+ drafts: resolved.filter((p) => p.draft !== null).length,
3856
+ tenants: resolved.reduce((sum, p) => sum + p.tenantCount, 0)
3857
+ };
3858
+ }
3760
3859
  // Annotate the CommonJS export names for ESM import in node:
3761
3860
  0 && (module.exports = {
3762
3861
  ADMIN_UI_VERSION,
@@ -3778,6 +3877,7 @@ function isProductionBoot(boot) {
3778
3877
  SA_MESSAGES,
3779
3878
  buildRoutes,
3780
3879
  buildSidebar,
3880
+ countPlans,
3781
3881
  createAdminResourceClient,
3782
3882
  createSaCatalog,
3783
3883
  defaultHttpClient,
@@ -3787,6 +3887,9 @@ function isProductionBoot(boot) {
3787
3887
  formatCurrency,
3788
3888
  formatMessage,
3789
3889
  getJson,
3890
+ isCurrentlyValid,
3891
+ isExpired,
3892
+ isFutureScheduled,
3790
3893
  isProductionBoot,
3791
3894
  isSaBuiltinLocale,
3792
3895
  mergeMessages,
@@ -3794,5 +3897,7 @@ function isProductionBoot(boot) {
3794
3897
  resolveExtension,
3795
3898
  resolveLoginBranding,
3796
3899
  resolveMessages,
3900
+ resolvePlans,
3901
+ todayIsoDate,
3797
3902
  trimTrailingSlashes
3798
3903
  });
@@ -1,5 +1,5 @@
1
- import { H as HttpClient, K as KvStore, S as SaLocale, w as SaNavMessages } from '../catalog-JXdKdIqG.cjs';
2
- export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-JXdKdIqG.cjs';
1
+ import { H as HttpClient, K as KvStore, S as SaLocale, w as SaNavMessages } from '../catalog-DJcfm5N2.cjs';
2
+ export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-DJcfm5N2.cjs';
3
3
  import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
@@ -339,4 +339,54 @@ declare function isProductionBoot(boot: {
339
339
  project?: LoginBootProject | null;
340
340
  } | null | undefined): boolean;
341
341
 
342
- export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes };
342
+ interface PlanRowLike {
343
+ id: string;
344
+ planKey: string;
345
+ label: string;
346
+ description?: string | null;
347
+ sortOrder: number;
348
+ }
349
+ interface PlanVersionLike {
350
+ id: string;
351
+ publishedAt?: string | null;
352
+ validFrom?: string | null;
353
+ validUntil?: string | null;
354
+ }
355
+ interface ResolvedPlan<P extends PlanRowLike, V extends PlanVersionLike> {
356
+ plan: P;
357
+ planKey: string;
358
+ label: string;
359
+ description: string | null;
360
+ /** Version currently active for new bookings. */
361
+ currentLive: V | null;
362
+ /** Version shown on the parent row — the live one where there is one. */
363
+ primary: V | null;
364
+ /** Future-published versions first, then drafts. */
365
+ subRows: V[];
366
+ hasAnyVersion: boolean;
367
+ /** Every version has run out: hidden from the admin listing. */
368
+ allExpired: boolean;
369
+ draft: V | null;
370
+ tenantCount: number;
371
+ }
372
+ declare function todayIsoDate(): string;
373
+ declare function isCurrentlyValid(v: PlanVersionLike, today: string): boolean;
374
+ declare function isFutureScheduled(v: PlanVersionLike, today: string): boolean;
375
+ declare function isExpired(v: PlanVersionLike, today: string): boolean;
376
+ interface ResolvePlansInput<P extends PlanRowLike, V extends PlanVersionLike> {
377
+ plans: readonly P[];
378
+ versionsByPlanId: Record<string, V[]>;
379
+ tenantCountsByPlanKey: Record<string, number>;
380
+ /** Injectable for tests; defaults to today. */
381
+ today?: string;
382
+ }
383
+ declare function resolvePlans<P extends PlanRowLike, V extends PlanVersionLike>({ plans, versionsByPlanId, tenantCountsByPlanKey, today, }: ResolvePlansInput<P, V>): ResolvedPlan<P, V>[];
384
+ interface PlanCounts {
385
+ plans: number;
386
+ live: number;
387
+ drafts: number;
388
+ tenants: number;
389
+ }
390
+ declare function countPlans<P extends PlanRowLike, V extends PlanVersionLike>(resolved: readonly ResolvedPlan<P, V>[]): PlanCounts;
391
+
392
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, type PlanCounts, type PlanRowLike, type PlanVersionLike, type ResolvePlansInput, type ResolvedPlan, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, countPlans, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isCurrentlyValid, isExpired, isFutureScheduled, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, resolvePlans, todayIsoDate, trimTrailingSlashes };
@@ -1,5 +1,5 @@
1
- import { H as HttpClient, K as KvStore, S as SaLocale, w as SaNavMessages } from '../catalog-JXdKdIqG.js';
2
- export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-JXdKdIqG.js';
1
+ import { H as HttpClient, K as KvStore, S as SaLocale, w as SaNavMessages } from '../catalog-DJcfm5N2.js';
2
+ export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-DJcfm5N2.js';
3
3
  import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
@@ -339,4 +339,54 @@ declare function isProductionBoot(boot: {
339
339
  project?: LoginBootProject | null;
340
340
  } | null | undefined): boolean;
341
341
 
342
- export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes };
342
+ interface PlanRowLike {
343
+ id: string;
344
+ planKey: string;
345
+ label: string;
346
+ description?: string | null;
347
+ sortOrder: number;
348
+ }
349
+ interface PlanVersionLike {
350
+ id: string;
351
+ publishedAt?: string | null;
352
+ validFrom?: string | null;
353
+ validUntil?: string | null;
354
+ }
355
+ interface ResolvedPlan<P extends PlanRowLike, V extends PlanVersionLike> {
356
+ plan: P;
357
+ planKey: string;
358
+ label: string;
359
+ description: string | null;
360
+ /** Version currently active for new bookings. */
361
+ currentLive: V | null;
362
+ /** Version shown on the parent row — the live one where there is one. */
363
+ primary: V | null;
364
+ /** Future-published versions first, then drafts. */
365
+ subRows: V[];
366
+ hasAnyVersion: boolean;
367
+ /** Every version has run out: hidden from the admin listing. */
368
+ allExpired: boolean;
369
+ draft: V | null;
370
+ tenantCount: number;
371
+ }
372
+ declare function todayIsoDate(): string;
373
+ declare function isCurrentlyValid(v: PlanVersionLike, today: string): boolean;
374
+ declare function isFutureScheduled(v: PlanVersionLike, today: string): boolean;
375
+ declare function isExpired(v: PlanVersionLike, today: string): boolean;
376
+ interface ResolvePlansInput<P extends PlanRowLike, V extends PlanVersionLike> {
377
+ plans: readonly P[];
378
+ versionsByPlanId: Record<string, V[]>;
379
+ tenantCountsByPlanKey: Record<string, number>;
380
+ /** Injectable for tests; defaults to today. */
381
+ today?: string;
382
+ }
383
+ declare function resolvePlans<P extends PlanRowLike, V extends PlanVersionLike>({ plans, versionsByPlanId, tenantCountsByPlanKey, today, }: ResolvePlansInput<P, V>): ResolvedPlan<P, V>[];
384
+ interface PlanCounts {
385
+ plans: number;
386
+ live: number;
387
+ drafts: number;
388
+ tenants: number;
389
+ }
390
+ declare function countPlans<P extends PlanRowLike, V extends PlanVersionLike>(resolved: readonly ResolvedPlan<P, V>[]): PlanCounts;
391
+
392
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, type PlanCounts, type PlanRowLike, type PlanVersionLike, type ResolvePlansInput, type ResolvedPlan, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, countPlans, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isCurrentlyValid, isExpired, isFutureScheduled, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, resolvePlans, todayIsoDate, trimTrailingSlashes };
@@ -13,15 +13,21 @@ import {
13
13
  MissingHandlerError,
14
14
  buildRoutes,
15
15
  buildSidebar,
16
+ countPlans,
16
17
  createAdminResourceClient,
17
18
  defaultSectionOrder,
18
19
  getJson,
20
+ isCurrentlyValid,
21
+ isExpired,
22
+ isFutureScheduled,
19
23
  isProductionBoot,
20
24
  postJson,
21
25
  resolveExtension,
22
26
  resolveLoginBranding,
27
+ resolvePlans,
28
+ todayIsoDate,
23
29
  trimTrailingSlashes
24
- } from "../chunk-ORX3ZG47.js";
30
+ } from "../chunk-XMMFN2WJ.js";
25
31
  import {
26
32
  DEFAULT_SA_LOCALE,
27
33
  SA_INTL_LOCALES,
@@ -37,7 +43,7 @@ import {
37
43
  isSaBuiltinLocale,
38
44
  mergeMessages,
39
45
  resolveMessages
40
- } from "../chunk-DPTIOQXX.js";
46
+ } from "../chunk-F7NRM6KI.js";
41
47
  export {
42
48
  ADMIN_UI_VERSION,
43
49
  ActionDefNotInManifestError,
@@ -58,6 +64,7 @@ export {
58
64
  SA_MESSAGES,
59
65
  buildRoutes,
60
66
  buildSidebar,
67
+ countPlans,
61
68
  createAdminResourceClient,
62
69
  createSaCatalog,
63
70
  defaultHttpClient,
@@ -67,6 +74,9 @@ export {
67
74
  formatCurrency,
68
75
  formatMessage,
69
76
  getJson,
77
+ isCurrentlyValid,
78
+ isExpired,
79
+ isFutureScheduled,
70
80
  isProductionBoot,
71
81
  isSaBuiltinLocale,
72
82
  mergeMessages,
@@ -74,5 +84,7 @@ export {
74
84
  resolveExtension,
75
85
  resolveLoginBranding,
76
86
  resolveMessages,
87
+ resolvePlans,
88
+ todayIsoDate,
77
89
  trimTrailingSlashes
78
90
  };