@saasicat/ui-vue 0.7.0 → 0.9.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 (41) hide show
  1. package/dist/{chunk-A3W2N26K.js → chunk-66BUSVC5.js} +68 -217
  2. package/dist/{chunk-X5SQ5HMB.js → chunk-TBLXKSTR.js} +0 -137
  3. package/dist/{chunk-QZOSDCNP.js → chunk-TY2WYKME.js} +1 -1
  4. package/dist/client/index.cjs +180 -463
  5. package/dist/client/index.d.cts +32 -57
  6. package/dist/client/index.d.ts +32 -57
  7. package/dist/client/index.js +4 -6
  8. package/dist/index.cjs +273 -580
  9. package/dist/index.d.cts +10 -55
  10. package/dist/index.d.ts +10 -55
  11. package/dist/index.js +76 -101
  12. package/dist/{messages-7b0P8W75.d.ts → messages-BIYw32u1.d.cts} +0 -67
  13. package/dist/{messages-7b0P8W75.d.cts → messages-BIYw32u1.d.ts} +0 -67
  14. package/dist/quasar/index.cjs +0 -136
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +2 -2
  18. package/dist/{use-super-admin-i18n-B3v3-SWZ.d.ts → use-super-admin-i18n-CWNu_W3u.d.ts} +1 -1
  19. package/dist/{use-super-admin-i18n-DMktRVEt.d.cts → use-super-admin-i18n-DL_qI1BY.d.cts} +1 -1
  20. package/package.json +5 -5
  21. package/src/client/admin-resource-client.ts +112 -0
  22. package/src/client/i18n/messages/nav.ts +0 -2
  23. package/src/client/i18n/messages/plan-versions.ts +0 -143
  24. package/src/client/index.ts +1 -2
  25. package/src/client/nav-builder.ts +9 -4
  26. package/src/index.ts +0 -1
  27. package/src/pages-standard/AdminLayout.vue +1 -1
  28. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +1 -1
  29. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +1 -1
  30. package/src/pages-standard/plan-versions/catalog-history.types.ts +37 -0
  31. package/src/pages-standard/plan-versions/format.ts +2 -38
  32. package/src/client/plan-versions-catalog.ts +0 -380
  33. package/src/pages-standard/PlanVersionsPage.vue +0 -220
  34. package/src/pages-standard/plan-versions/PlanVersionHeader.vue +0 -309
  35. package/src/pages-standard/plan-versions/PlanVersionStatusBadge.vue +0 -48
  36. package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +0 -326
  37. package/src/pages-standard/plan-versions/PlanVersionsKpi.vue +0 -65
  38. package/src/pages-standard/plan-versions/PlanVersionsList.vue +0 -315
  39. package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +0 -261
  40. package/src/pages-standard/plan-versions/types.ts +0 -33
  41. package/src/vue/use-plan-versions.ts +0 -83
@@ -1352,7 +1352,6 @@ var navMessages = defineMessages(
1352
1352
  subscriptions: "Abonnements",
1353
1353
  promoCodes: "Promo-Codes",
1354
1354
  plans: "Pl\xE4ne & Versionen",
1355
- planVersions: "Plan-Versionen",
1356
1355
  audit: "Audit-Log",
1357
1356
  users: "Benutzer",
1358
1357
  pilots: "Piloten",
@@ -1376,7 +1375,6 @@ var navMessages = defineMessages(
1376
1375
  subscriptions: "Subscriptions",
1377
1376
  promoCodes: "Promo codes",
1378
1377
  plans: "Plans & versions",
1379
- planVersions: "Plan versions",
1380
1378
  audit: "Audit log",
1381
1379
  users: "Users",
1382
1380
  pilots: "Pilots",
@@ -2019,21 +2017,6 @@ var planEditorMessages = defineMessages(
2019
2017
  var planVersionsMessages = defineMessages(
2020
2018
  {
2021
2019
  compareEnd: "Vergleich beenden",
2022
- page: {
2023
- loadingCatalog: "Catalog wird geladen\u2026",
2024
- noAuditLoader: "Kein Audit-Loader konfiguriert."
2025
- },
2026
- header: {
2027
- modeList: "Plan-Liste",
2028
- modeMatrix: "Feature-Matrix",
2029
- modeAudit: "Aktivit\xE4t",
2030
- publishedOn: "Publiziert {date}",
2031
- openDrafts: "offene Drafts",
2032
- regressionOne: "Regression",
2033
- regressionMany: "Regressionen",
2034
- startPublishFlow: "Publish-Flow starten",
2035
- compareModeHint: "Vergleichsmodus aktiv \u2014 andere Ansichten deaktiviert"
2036
- },
2037
2020
  status: {
2038
2021
  draft: "DRAFT",
2039
2022
  active: "AKTIV",
@@ -2047,29 +2030,6 @@ var planVersionsMessages = defineMessages(
2047
2030
  unknown: "unbekannt",
2048
2031
  compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
2049
2032
  },
2050
- list: {
2051
- kpiPlans: "Pakete",
2052
- kpiSelfService: "Self-Service",
2053
- kpiOfTotal: "von {count}",
2054
- kpiFeaturesTotal: "Features gesamt",
2055
- missingPlansLabel: "Fehlende Pakete:",
2056
- missingPlansHint: "\u2014 keine Live-Version in diesem Snapshot.",
2057
- createDraftFor: "Draft f\xFCr {planId}",
2058
- colPlan: "Paket",
2059
- colPriceNet: "Preis (netto)",
2060
- colFeatures: "Features",
2061
- draftHintLabel: "Arbeitsstand:",
2062
- draftHintBefore: "Drafts oben in der Liste. Limits, Preise und Features per Klick auf",
2063
- draftHintEditButton: '\u201EBearbeiten"',
2064
- draftHintMiddle: "\xE4ndern (ohne MFA). Erst",
2065
- draftHintPublishFlow: "Publish-Flow",
2066
- draftHintAfter: "(Validate \u2192 Diff-Review \u2192 MFA \u2192 Apply) macht sie f\xFCr k\xFCnftige Renewals wirksam."
2067
- },
2068
- matrix: {
2069
- colFeature: "Feature",
2070
- perMonthShort: "/Mo",
2071
- fallbackGroup: "Sonstige"
2072
- },
2073
2033
  diff: {
2074
2034
  legend: "Vergleich",
2075
2035
  plansChanged: "Pakete ge\xE4ndert",
@@ -2093,24 +2053,10 @@ var planVersionsMessages = defineMessages(
2093
2053
  yearlyNet: "Preis j\xE4hrlich (netto)",
2094
2054
  unitSize: "Einheitsgr\xF6\xDFe"
2095
2055
  },
2096
- audit: {
2097
- title: "Aktivit\xE4t",
2098
- eventCount: "{count} Events",
2099
- loading: "Audit-Trail wird geladen\u2026",
2100
- empty: "Keine Plan-/Add-on-Events im Audit-Log gefunden.",
2101
- actionPlanPublished: "Plan publiziert",
2102
- actionPlanDraftCreated: "Plan-Draft angelegt",
2103
- actionPlanDraftUpdated: "Plan-Draft ge\xE4ndert",
2104
- actionPlanDraftDeleted: "Plan-Draft gel\xF6scht",
2105
- actionCatalogPublished: "Catalog publiziert",
2106
- detailRegression: "Mit mindestens einer Verschlechterung publiziert.",
2107
- detailFieldsChanged: "{count} Felder ge\xE4ndert."
2108
- },
2109
2056
  bulkPublish: {
2110
2057
  changeNoteRequired: "changeNote ist Pflicht beim Publish."
2111
2058
  },
2112
2059
  format: {
2113
- priceIndividual: "individuell",
2114
2060
  today: "heute",
2115
2061
  yesterday: "gestern",
2116
2062
  daysAgo: "vor {count} Tagen",
@@ -2119,40 +2065,10 @@ var planVersionsMessages = defineMessages(
2119
2065
  monthsAgo: "vor {count} Monaten",
2120
2066
  yearsAgoOne: "vor {count} Jahr",
2121
2067
  yearsAgoMany: "vor {count} Jahren"
2122
- },
2123
- catalog: {
2124
- draftsLabel: "Arbeitsstand",
2125
- draftsTitleEmpty: "Keine offenen Drafts",
2126
- draftsTitleOne: "{count} offener Draft bereit f\xFCr Publish",
2127
- draftsTitleMany: "{count} offene Drafts bereit f\xFCr Publish",
2128
- draftsDescriptionEmpty: "Lege einen Draft an, um Limits, Preise oder Features zu \xE4ndern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam.",
2129
- draftsDescription: "Diese Tabelle zeigt, wie der Catalog nach Publish aller Drafts aussehen w\xFCrde. Bestehende Mandanten bleiben auf der vorherigen Version, bis sie aktiv migriert werden.",
2130
- activeLabel: "Aktuell",
2131
- activeTitle: "Live-Catalog",
2132
- activeDescription: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
2133
- publishEvent: "Publish-Event",
2134
- publishEventSingle: "{planId} v{version} publiziert",
2135
- publishEventMultiple: "{count} Versionen publiziert",
2136
- reconstructedSnapshot: "Snapshot rekonstruiert aus per-Entity-Versionen."
2137
2068
  }
2138
2069
  },
2139
2070
  {
2140
2071
  compareEnd: "End comparison",
2141
- page: {
2142
- loadingCatalog: "Loading catalog\u2026",
2143
- noAuditLoader: "No audit loader configured."
2144
- },
2145
- header: {
2146
- modeList: "Plan list",
2147
- modeMatrix: "Feature matrix",
2148
- modeAudit: "Activity",
2149
- publishedOn: "Published {date}",
2150
- openDrafts: "open drafts",
2151
- regressionOne: "regression",
2152
- regressionMany: "regressions",
2153
- startPublishFlow: "Start publish flow",
2154
- compareModeHint: "Comparison mode active \u2014 other views disabled"
2155
- },
2156
2072
  status: {
2157
2073
  draft: "DRAFT",
2158
2074
  active: "ACTIVE",
@@ -2166,29 +2082,6 @@ var planVersionsMessages = defineMessages(
2166
2082
  unknown: "unknown",
2167
2083
  compareHint: "Right-click a snapshot \u2192 compare"
2168
2084
  },
2169
- list: {
2170
- kpiPlans: "Plans",
2171
- kpiSelfService: "Self-service",
2172
- kpiOfTotal: "of {count}",
2173
- kpiFeaturesTotal: "Features total",
2174
- missingPlansLabel: "Missing plans:",
2175
- missingPlansHint: "\u2014 no live version in this snapshot.",
2176
- createDraftFor: "Draft for {planId}",
2177
- colPlan: "Plan",
2178
- colPriceNet: "Price (net)",
2179
- colFeatures: "Features",
2180
- draftHintLabel: "Working state:",
2181
- draftHintBefore: "Drafts at the top of the list. Change limits, prices and features by clicking",
2182
- draftHintEditButton: '"Edit"',
2183
- draftHintMiddle: "(without MFA). Only the",
2184
- draftHintPublishFlow: "publish flow",
2185
- draftHintAfter: "(validate \u2192 diff review \u2192 MFA \u2192 apply) makes them effective for future renewals."
2186
- },
2187
- matrix: {
2188
- colFeature: "Feature",
2189
- perMonthShort: "/mo",
2190
- fallbackGroup: "Other"
2191
- },
2192
2085
  diff: {
2193
2086
  legend: "Comparison",
2194
2087
  plansChanged: "Plans changed",
@@ -2212,24 +2105,10 @@ var planVersionsMessages = defineMessages(
2212
2105
  yearlyNet: "Price yearly (net)",
2213
2106
  unitSize: "Unit size"
2214
2107
  },
2215
- audit: {
2216
- title: "Activity",
2217
- eventCount: "{count} events",
2218
- loading: "Loading audit trail\u2026",
2219
- empty: "No plan/add-on events found in the audit log.",
2220
- actionPlanPublished: "Plan published",
2221
- actionPlanDraftCreated: "Plan draft created",
2222
- actionPlanDraftUpdated: "Plan draft changed",
2223
- actionPlanDraftDeleted: "Plan draft deleted",
2224
- actionCatalogPublished: "Catalog published",
2225
- detailRegression: "Published with at least one regression.",
2226
- detailFieldsChanged: "{count} fields changed."
2227
- },
2228
2108
  bulkPublish: {
2229
2109
  changeNoteRequired: "changeNote is required when publishing."
2230
2110
  },
2231
2111
  format: {
2232
- priceIndividual: "custom",
2233
2112
  today: "today",
2234
2113
  yesterday: "yesterday",
2235
2114
  daysAgo: "{count} days ago",
@@ -2238,21 +2117,6 @@ var planVersionsMessages = defineMessages(
2238
2117
  monthsAgo: "{count} months ago",
2239
2118
  yearsAgoOne: "{count} year ago",
2240
2119
  yearsAgoMany: "{count} years ago"
2241
- },
2242
- catalog: {
2243
- draftsLabel: "Working state",
2244
- draftsTitleEmpty: "No open drafts",
2245
- draftsTitleOne: "{count} open draft ready to publish",
2246
- draftsTitleMany: "{count} open drafts ready to publish",
2247
- draftsDescriptionEmpty: "Create a draft to change limits, prices or features. Drafts are editable without MFA and only take effect when published.",
2248
- draftsDescription: "This table shows what the catalog would look like after publishing all drafts. Existing tenants stay on the previous version until they are actively migrated.",
2249
- activeLabel: "Current",
2250
- activeTitle: "Live catalog",
2251
- activeDescription: "These plan versions are currently active for new onboardings and for renewals after the effective date.",
2252
- publishEvent: "Publish event",
2253
- publishEventSingle: "{planId} v{version} published",
2254
- publishEventMultiple: "{count} versions published",
2255
- reconstructedSnapshot: "Snapshot reconstructed from per-entity versions."
2256
2120
  }
2257
2121
  }
2258
2122
  );
@@ -2,8 +2,8 @@ import { Component, App } from 'vue';
2
2
  import { QuasarPluginOptions } from 'quasar';
3
3
  import { Pinia } from 'pinia';
4
4
  import { RouteRecordRaw, RouterHistory, Router } from 'vue-router';
5
- import { H as HttpClient } from '../messages-7b0P8W75.cjs';
6
- import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-DMktRVEt.cjs';
5
+ import { H as HttpClient } from '../messages-BIYw32u1.cjs';
6
+ import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-DL_qI1BY.cjs';
7
7
  import '@saasicat/types';
8
8
 
9
9
  interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
@@ -2,8 +2,8 @@ import { Component, App } from 'vue';
2
2
  import { QuasarPluginOptions } from 'quasar';
3
3
  import { Pinia } from 'pinia';
4
4
  import { RouteRecordRaw, RouterHistory, Router } from 'vue-router';
5
- import { H as HttpClient } from '../messages-7b0P8W75.js';
6
- import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-B3v3-SWZ.js';
5
+ import { H as HttpClient } from '../messages-BIYw32u1.js';
6
+ import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-CWNu_W3u.js';
7
7
  import '@saasicat/types';
8
8
 
9
9
  interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
@@ -10,10 +10,10 @@ import {
10
10
  SUPER_ADMIN_NOTIFY_KEY,
11
11
  buildNavigationGuard,
12
12
  createSuperAdminI18n
13
- } from "../chunk-QZOSDCNP.js";
13
+ } from "../chunk-TY2WYKME.js";
14
14
  import {
15
15
  defaultHttpClient
16
- } from "../chunk-X5SQ5HMB.js";
16
+ } from "../chunk-TBLXKSTR.js";
17
17
 
18
18
  // src/quasar/create-super-admin-app.ts
19
19
  import { createApp } from "vue";
@@ -1,7 +1,7 @@
1
1
  import { Component, App, InjectionKey, Ref, ComputedRef } from 'vue';
2
2
  import { NavigationGuardWithThis } from 'vue-router';
3
3
  import { ActionKey, ComponentKey, AdminManifest } from '@saasicat/types';
4
- import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaMessagesOverrides } from './messages-7b0P8W75.js';
4
+ import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaMessagesOverrides } from './messages-BIYw32u1.js';
5
5
 
6
6
  /**
7
7
  * App-specific branding data that the platform `AdminLayout` and other
@@ -1,7 +1,7 @@
1
1
  import { Component, App, InjectionKey, Ref, ComputedRef } from 'vue';
2
2
  import { NavigationGuardWithThis } from 'vue-router';
3
3
  import { ActionKey, ComponentKey, AdminManifest } from '@saasicat/types';
4
- import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaMessagesOverrides } from './messages-7b0P8W75.cjs';
4
+ import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaMessagesOverrides } from './messages-BIYw32u1.cjs';
5
5
 
6
6
  /**
7
7
  * App-specific branding data that the platform `AdminLayout` and other
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saasicat/ui-vue",
3
- "version": "0.7.0",
4
- "description": "Vue 3 components + composables for the SuperAdmin UI shell. Provides boot loader, manifest loader (ETag cache), nav builder, action registry and standard pages.",
3
+ "version": "0.9.0",
4
+ "description": "Vue 3 components, resource clients and composables for the SuperAdmin UI shell. Provides boot and manifest loaders, navigation, actions and standard pages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -53,11 +53,11 @@
53
53
  "src"
54
54
  ],
55
55
  "dependencies": {
56
- "@saasicat/types": "^0.7.0"
56
+ "@saasicat/types": "^0.9.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "pinia": "^2.0.0 || ^3.0.0",
60
- "quasar": "^2.18.0",
60
+ "quasar": "^2.22.0",
61
61
  "vue": "^3.5.0",
62
62
  "vue-router": "^4.5.0 || ^5.0.0"
63
63
  },
@@ -76,7 +76,7 @@
76
76
  "@playwright/test": "^1.59.1",
77
77
  "@types/node": "^25.6.0",
78
78
  "pinia": "^3.0.0",
79
- "quasar": "^2.18.0",
79
+ "quasar": "^2.22.0",
80
80
  "tsup": "^8.0.0",
81
81
  "typescript": "^6.0.0",
82
82
  "vue": "^3.5.0",
@@ -0,0 +1,112 @@
1
+ import type {
2
+ AdminAuditListFilter,
3
+ AdminSubscriptionListRow,
4
+ AdminTenantDetail,
5
+ AdminUserListFilter,
6
+ AdminUserListRow,
7
+ AuditEntry,
8
+ PromoCodeRecord,
9
+ } from '@saasicat/types';
10
+ import type { HttpClient } from './types.js';
11
+
12
+ export interface AdminResourceClientOptions {
13
+ http: HttpClient;
14
+ /** Default `/api/v1/admin`. */
15
+ adminBase?: string;
16
+ }
17
+
18
+ /** Filters accepted by the standard PromoCodesPage, including its "all" state. */
19
+ export interface AdminPromoListFilter {
20
+ search?: string;
21
+ status?: string | null;
22
+ }
23
+
24
+ /** Promo row shape used by the extensible standard Admin table. */
25
+ export interface AdminPromoListRow extends PromoCodeRecord {
26
+ [extra: string]: unknown;
27
+ }
28
+
29
+ /**
30
+ * Ready-to-use client for the standard SaaSiCat AdminResources and promo
31
+ * controllers. App wrappers pass these functions straight to the standard
32
+ * pages; no repeated fetch/error/query-string plumbing is needed.
33
+ */
34
+ export function createAdminResourceClient(options: AdminResourceClientOptions) {
35
+ const base = options.adminBase ?? '/api/v1/admin';
36
+ const tenantsEndpoint = `${base}/tenants`;
37
+
38
+ const getJson = async <T>(url: string): Promise<T> => {
39
+ const response = await options.http(url, { method: 'GET' });
40
+ assertSuccess(response.status, 'GET', url);
41
+ return (await response.json()) as T;
42
+ };
43
+
44
+ const sendJson = async <T>(method: string, url: string, body?: unknown): Promise<T> => {
45
+ const response = await options.http(url, {
46
+ method,
47
+ headers: { 'content-type': 'application/json' },
48
+ body: body === undefined ? undefined : JSON.stringify(body),
49
+ });
50
+ assertSuccess(response.status, method, url);
51
+ return (await response.json()) as T;
52
+ };
53
+
54
+ return {
55
+ tenantsEndpoint,
56
+ loadTenantDetail: (slug: string) =>
57
+ getJson<AdminTenantDetail>(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
58
+ loadUsers: (filter: AdminUserListFilter) =>
59
+ getJson<AdminUserListRow[]>(
60
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`,
61
+ ),
62
+ loadAudit: (filter: AdminAuditListFilter) =>
63
+ getJson<AuditEntry[]>(
64
+ `${base}/audit${queryString({
65
+ actor: filter.actor,
66
+ action: filter.action,
67
+ entity: filter.entity,
68
+ since: filter.since,
69
+ limit: filter.limit,
70
+ })}`,
71
+ ),
72
+ loadSubscriptions: () => getJson<AdminSubscriptionListRow[]>(`${base}/subscriptions`),
73
+ loadPromos: (filter: AdminPromoListFilter) =>
74
+ getJson<AdminPromoListRow[]>(
75
+ `${base}/promo-codes${queryString({
76
+ search: filter.search,
77
+ status: filter.status,
78
+ })}`,
79
+ ),
80
+ createPromo: async (payload: unknown): Promise<void> => {
81
+ await sendJson('POST', `${base}/promo-codes`, payload);
82
+ },
83
+ updatePromo: async (id: string, payload: unknown): Promise<void> => {
84
+ await sendJson('PATCH', `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
85
+ },
86
+ deletePromo: async (id: string): Promise<void> => {
87
+ await sendJson('DELETE', `${base}/promo-codes/${encodeURIComponent(id)}`);
88
+ },
89
+ suspendTenant: (slug: string, reason: string): Promise<unknown> =>
90
+ sendJson('POST', `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
91
+ reason,
92
+ }),
93
+ reactivateTenant: (slug: string): Promise<unknown> =>
94
+ sendJson('POST', `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`),
95
+ };
96
+ }
97
+
98
+ function assertSuccess(status: number, method: string, url: string): void {
99
+ if (status < 200 || status >= 300) {
100
+ throw new Error(`${method} ${url} → HTTP ${status}`);
101
+ }
102
+ }
103
+
104
+ function queryString(params: Record<string, string | number | null | undefined>): string {
105
+ const search = new URLSearchParams();
106
+ for (const [key, value] of Object.entries(params)) {
107
+ if (value === undefined || value === null || value === '') continue;
108
+ search.set(key, String(value));
109
+ }
110
+ const value = search.toString();
111
+ return value ? `?${value}` : '';
112
+ }
@@ -28,7 +28,6 @@ export const navMessages: Record<SaLocale, NavNamespace> = defineMessages(
28
28
  subscriptions: 'Abonnements',
29
29
  promoCodes: 'Promo-Codes',
30
30
  plans: 'Pläne & Versionen',
31
- planVersions: 'Plan-Versionen',
32
31
  audit: 'Audit-Log',
33
32
  users: 'Benutzer',
34
33
  pilots: 'Piloten',
@@ -52,7 +51,6 @@ export const navMessages: Record<SaLocale, NavNamespace> = defineMessages(
52
51
  subscriptions: 'Subscriptions',
53
52
  promoCodes: 'Promo codes',
54
53
  plans: 'Plans & versions',
55
- planVersions: 'Plan versions',
56
54
  audit: 'Audit log',
57
55
  users: 'Users',
58
56
  pilots: 'Pilots',
@@ -3,21 +3,6 @@ import { defineMessages } from '../define.js';
3
3
  export const planVersionsMessages = defineMessages(
4
4
  {
5
5
  compareEnd: 'Vergleich beenden',
6
- page: {
7
- loadingCatalog: 'Catalog wird geladen…',
8
- noAuditLoader: 'Kein Audit-Loader konfiguriert.',
9
- },
10
- header: {
11
- modeList: 'Plan-Liste',
12
- modeMatrix: 'Feature-Matrix',
13
- modeAudit: 'Aktivität',
14
- publishedOn: 'Publiziert {date}',
15
- openDrafts: 'offene Drafts',
16
- regressionOne: 'Regression',
17
- regressionMany: 'Regressionen',
18
- startPublishFlow: 'Publish-Flow starten',
19
- compareModeHint: 'Vergleichsmodus aktiv — andere Ansichten deaktiviert',
20
- },
21
6
  status: {
22
7
  draft: 'DRAFT',
23
8
  active: 'AKTIV',
@@ -31,30 +16,6 @@ export const planVersionsMessages = defineMessages(
31
16
  unknown: 'unbekannt',
32
17
  compareHint: 'Rechtsklick auf Snapshot → vergleichen',
33
18
  },
34
- list: {
35
- kpiPlans: 'Pakete',
36
- kpiSelfService: 'Self-Service',
37
- kpiOfTotal: 'von {count}',
38
- kpiFeaturesTotal: 'Features gesamt',
39
- missingPlansLabel: 'Fehlende Pakete:',
40
- missingPlansHint: '— keine Live-Version in diesem Snapshot.',
41
- createDraftFor: 'Draft für {planId}',
42
- colPlan: 'Paket',
43
- colPriceNet: 'Preis (netto)',
44
- colFeatures: 'Features',
45
- draftHintLabel: 'Arbeitsstand:',
46
- draftHintBefore: 'Drafts oben in der Liste. Limits, Preise und Features per Klick auf',
47
- draftHintEditButton: '„Bearbeiten"',
48
- draftHintMiddle: 'ändern (ohne MFA). Erst',
49
- draftHintPublishFlow: 'Publish-Flow',
50
- draftHintAfter:
51
- '(Validate → Diff-Review → MFA → Apply) macht sie für künftige Renewals wirksam.',
52
- },
53
- matrix: {
54
- colFeature: 'Feature',
55
- perMonthShort: '/Mo',
56
- fallbackGroup: 'Sonstige',
57
- },
58
19
  diff: {
59
20
  legend: 'Vergleich',
60
21
  plansChanged: 'Pakete geändert',
@@ -78,24 +39,10 @@ export const planVersionsMessages = defineMessages(
78
39
  yearlyNet: 'Preis jährlich (netto)',
79
40
  unitSize: 'Einheitsgröße',
80
41
  },
81
- audit: {
82
- title: 'Aktivität',
83
- eventCount: '{count} Events',
84
- loading: 'Audit-Trail wird geladen…',
85
- empty: 'Keine Plan-/Add-on-Events im Audit-Log gefunden.',
86
- actionPlanPublished: 'Plan publiziert',
87
- actionPlanDraftCreated: 'Plan-Draft angelegt',
88
- actionPlanDraftUpdated: 'Plan-Draft geändert',
89
- actionPlanDraftDeleted: 'Plan-Draft gelöscht',
90
- actionCatalogPublished: 'Catalog publiziert',
91
- detailRegression: 'Mit mindestens einer Verschlechterung publiziert.',
92
- detailFieldsChanged: '{count} Felder geändert.',
93
- },
94
42
  bulkPublish: {
95
43
  changeNoteRequired: 'changeNote ist Pflicht beim Publish.',
96
44
  },
97
45
  format: {
98
- priceIndividual: 'individuell',
99
46
  today: 'heute',
100
47
  yesterday: 'gestern',
101
48
  daysAgo: 'vor {count} Tagen',
@@ -105,42 +52,9 @@ export const planVersionsMessages = defineMessages(
105
52
  yearsAgoOne: 'vor {count} Jahr',
106
53
  yearsAgoMany: 'vor {count} Jahren',
107
54
  },
108
- catalog: {
109
- draftsLabel: 'Arbeitsstand',
110
- draftsTitleEmpty: 'Keine offenen Drafts',
111
- draftsTitleOne: '{count} offener Draft bereit für Publish',
112
- draftsTitleMany: '{count} offene Drafts bereit für Publish',
113
- draftsDescriptionEmpty:
114
- 'Lege einen Draft an, um Limits, Preise oder Features zu ändern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam.',
115
- draftsDescription:
116
- 'Diese Tabelle zeigt, wie der Catalog nach Publish aller Drafts aussehen würde. Bestehende Mandanten bleiben auf der vorherigen Version, bis sie aktiv migriert werden.',
117
- activeLabel: 'Aktuell',
118
- activeTitle: 'Live-Catalog',
119
- activeDescription:
120
- 'Diese Plan-Versionen sind aktuell für neue Onboardings und für Renewals nach Stichtag aktiv.',
121
- publishEvent: 'Publish-Event',
122
- publishEventSingle: '{planId} v{version} publiziert',
123
- publishEventMultiple: '{count} Versionen publiziert',
124
- reconstructedSnapshot: 'Snapshot rekonstruiert aus per-Entity-Versionen.',
125
- },
126
55
  },
127
56
  {
128
57
  compareEnd: 'End comparison',
129
- page: {
130
- loadingCatalog: 'Loading catalog…',
131
- noAuditLoader: 'No audit loader configured.',
132
- },
133
- header: {
134
- modeList: 'Plan list',
135
- modeMatrix: 'Feature matrix',
136
- modeAudit: 'Activity',
137
- publishedOn: 'Published {date}',
138
- openDrafts: 'open drafts',
139
- regressionOne: 'regression',
140
- regressionMany: 'regressions',
141
- startPublishFlow: 'Start publish flow',
142
- compareModeHint: 'Comparison mode active — other views disabled',
143
- },
144
58
  status: {
145
59
  draft: 'DRAFT',
146
60
  active: 'ACTIVE',
@@ -154,31 +68,6 @@ export const planVersionsMessages = defineMessages(
154
68
  unknown: 'unknown',
155
69
  compareHint: 'Right-click a snapshot → compare',
156
70
  },
157
- list: {
158
- kpiPlans: 'Plans',
159
- kpiSelfService: 'Self-service',
160
- kpiOfTotal: 'of {count}',
161
- kpiFeaturesTotal: 'Features total',
162
- missingPlansLabel: 'Missing plans:',
163
- missingPlansHint: '— no live version in this snapshot.',
164
- createDraftFor: 'Draft for {planId}',
165
- colPlan: 'Plan',
166
- colPriceNet: 'Price (net)',
167
- colFeatures: 'Features',
168
- draftHintLabel: 'Working state:',
169
- draftHintBefore:
170
- 'Drafts at the top of the list. Change limits, prices and features by clicking',
171
- draftHintEditButton: '"Edit"',
172
- draftHintMiddle: '(without MFA). Only the',
173
- draftHintPublishFlow: 'publish flow',
174
- draftHintAfter:
175
- '(validate → diff review → MFA → apply) makes them effective for future renewals.',
176
- },
177
- matrix: {
178
- colFeature: 'Feature',
179
- perMonthShort: '/mo',
180
- fallbackGroup: 'Other',
181
- },
182
71
  diff: {
183
72
  legend: 'Comparison',
184
73
  plansChanged: 'Plans changed',
@@ -202,24 +91,10 @@ export const planVersionsMessages = defineMessages(
202
91
  yearlyNet: 'Price yearly (net)',
203
92
  unitSize: 'Unit size',
204
93
  },
205
- audit: {
206
- title: 'Activity',
207
- eventCount: '{count} events',
208
- loading: 'Loading audit trail…',
209
- empty: 'No plan/add-on events found in the audit log.',
210
- actionPlanPublished: 'Plan published',
211
- actionPlanDraftCreated: 'Plan draft created',
212
- actionPlanDraftUpdated: 'Plan draft changed',
213
- actionPlanDraftDeleted: 'Plan draft deleted',
214
- actionCatalogPublished: 'Catalog published',
215
- detailRegression: 'Published with at least one regression.',
216
- detailFieldsChanged: '{count} fields changed.',
217
- },
218
94
  bulkPublish: {
219
95
  changeNoteRequired: 'changeNote is required when publishing.',
220
96
  },
221
97
  format: {
222
- priceIndividual: 'custom',
223
98
  today: 'today',
224
99
  yesterday: 'yesterday',
225
100
  daysAgo: '{count} days ago',
@@ -229,23 +104,5 @@ export const planVersionsMessages = defineMessages(
229
104
  yearsAgoOne: '{count} year ago',
230
105
  yearsAgoMany: '{count} years ago',
231
106
  },
232
- catalog: {
233
- draftsLabel: 'Working state',
234
- draftsTitleEmpty: 'No open drafts',
235
- draftsTitleOne: '{count} open draft ready to publish',
236
- draftsTitleMany: '{count} open drafts ready to publish',
237
- draftsDescriptionEmpty:
238
- 'Create a draft to change limits, prices or features. Drafts are editable without MFA and only take effect when published.',
239
- draftsDescription:
240
- 'This table shows what the catalog would look like after publishing all drafts. Existing tenants stay on the previous version until they are actively migrated.',
241
- activeLabel: 'Current',
242
- activeTitle: 'Live catalog',
243
- activeDescription:
244
- 'These plan versions are currently active for new onboardings and for renewals after the effective date.',
245
- publishEvent: 'Publish event',
246
- publishEventSingle: '{planId} v{version} published',
247
- publishEventMultiple: '{count} versions published',
248
- reconstructedSnapshot: 'Snapshot reconstructed from per-entity versions.',
249
- },
250
107
  },
251
108
  );
@@ -11,7 +11,6 @@
11
11
  // - nav-builder: buildRoutes, buildSidebar, resolveExtension
12
12
  // - action-registry: ActionRegistry, MissingHandlerError, ActionDefNotInManifestError
13
13
  // - batch-column-fetcher: BatchColumnFetcher + BatchColumnDriftError
14
- // - plan-versions-catalog: plan-version list/diff helpers
15
14
  // - i18n: SaLocale, typed DE/EN catalogs, formatMessage
16
15
  // - version: ADMIN_UI_VERSION
17
16
 
@@ -23,5 +22,5 @@ export * from './manifest-loader.js';
23
22
  export * from './nav-builder.js';
24
23
  export * from './action-registry.js';
25
24
  export * from './batch-column-fetcher.js';
26
- export * from './plan-versions-catalog.js';
25
+ export * from './admin-resource-client.js';
27
26
  export * from './i18n/index.js';