@saasicat/ui-vue 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -4
- package/dist/action-registry-CQ2wL3R-.d.cts +85 -0
- package/dist/action-registry-CQ2wL3R-.d.ts +85 -0
- package/dist/chunk-3YP2ZAOD.js +63 -0
- package/dist/chunk-EH7TOD4H.js +718 -0
- package/dist/chunk-LVGUSD3T.js +26 -0
- package/dist/client/index.cjs +785 -0
- package/dist/client/index.d.cts +295 -0
- package/dist/client/index.d.ts +295 -0
- package/dist/client/index.js +52 -0
- package/dist/index.cjs +787 -834
- package/dist/index.d.cts +267 -841
- package/dist/index.d.ts +267 -841
- package/dist/index.js +284 -1059
- package/dist/quasar/index.cjs +159 -0
- package/dist/quasar/index.d.cts +86 -0
- package/dist/quasar/index.d.ts +86 -0
- package/dist/quasar/index.js +91 -0
- package/dist/ui-notify-COUzXEQ4.d.ts +178 -0
- package/dist/ui-notify-D_eAAwRh.d.cts +178 -0
- package/package.json +23 -3
- package/src/client/index.ts +25 -0
- package/src/components/FeatureGate.vue +1 -1
- package/src/components/plan/PlanCycleToggle.vue +1 -1
- package/src/components/plan/PlanGrid.vue +2 -2
- package/src/components/plan/PriceSummary.vue +1 -1
- package/src/components/plan/PromoCodeInput.vue +1 -1
- package/src/components/plan/PublicBundleGrid.vue +1 -1
- package/src/index.ts +82 -79
- package/src/pages-standard/AdminLayout.vue +2 -2
- package/src/pages-standard/DashboardPage.vue +2 -2
- package/src/pages-standard/EmailHistoryPage.vue +9 -13
- package/src/pages-standard/MarketingCatalogPage.vue +5 -5
- package/src/pages-standard/PilotsPage.vue +9 -13
- package/src/pages-standard/PlanVersionsPage.vue +2 -2
- package/src/pages-standard/PlansPage.vue +2 -2
- package/src/pages-standard/PlatformEmailPage.vue +7 -5
- package/src/pages-standard/PromoCodesPage.vue +8 -22
- package/src/pages-standard/SuperAdminLoginPage.vue +3 -3
- package/src/pages-standard/SuperAdminSetupWizard.vue +2 -2
- package/src/pages-standard/TenantDetailPage.vue +4 -4
- package/src/pages-standard/TenantsPage.vue +3 -3
- package/src/pages-standard/UsersPage.vue +6 -12
- package/src/pages-standard/plan-versions/PlanVersionHeader.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +1 -1
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +1 -1
- package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/PlanChangeWizard.vue +2 -2
- package/src/pages-tenant/TenantPlanSection.vue +3 -3
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +1 -1
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +2 -2
- package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
- package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
- package/src/quasar/create-super-admin-app.ts +173 -0
- package/src/quasar/index.ts +11 -0
- package/src/quasar/notify.ts +30 -0
- package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
- package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
- package/src/{project-page-host.ts → vue/project-page-host.ts} +1 -1
- package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
- package/src/vue/ui-notify.ts +30 -0
- package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
- package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
- package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
- package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +1 -1
- package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +1 -1
- package/src/{use-bundles.ts → vue/use-bundles.ts} +1 -1
- package/src/{use-business-types.ts → vue/use-business-types.ts} +1 -1
- package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +1 -1
- package/src/{use-discovery.ts → vue/use-discovery.ts} +1 -1
- package/src/{use-entitlement.ts → vue/use-entitlement.ts} +1 -1
- package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +1 -1
- package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
- package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +1 -1
- package/src/{use-nav.ts → vue/use-nav.ts} +1 -1
- package/src/{use-plans.ts → vue/use-plans.ts} +1 -1
- package/src/{use-promotions.ts → vue/use-promotions.ts} +1 -1
- package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
- package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +2 -2
- package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +1 -1
- package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
- package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
- package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +1 -1
- package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +1 -1
- package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
- package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
- /package/src/{action-registry.ts → client/action-registry.ts} +0 -0
- /package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +0 -0
- /package/src/{boot-loader.ts → client/boot-loader.ts} +0 -0
- /package/src/{http-json.ts → client/http-json.ts} +0 -0
- /package/src/{manifest-loader.ts → client/manifest-loader.ts} +0 -0
- /package/src/{nav-builder.ts → client/nav-builder.ts} +0 -0
- /package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +0 -0
- /package/src/{types.ts → client/types.ts} +0 -0
- /package/src/{version.ts → client/version.ts} +0 -0
- /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
- /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
- /package/src/{feature-router-guard.ts → vue/feature-router-guard.ts} +0 -0
- /package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +0 -0
- /package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +0 -0
- /package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +0 -0
- /package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +0 -0
- /package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +0 -0
- /package/src/{use-tenants.ts → vue/use-tenants.ts} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -18,8 +18,8 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
23
|
ADMIN_UI_VERSION: () => ADMIN_UI_VERSION,
|
|
24
24
|
ActionDefNotInManifestError: () => ActionDefNotInManifestError,
|
|
25
25
|
ActionRegistry: () => ActionRegistry,
|
|
@@ -54,6 +54,7 @@ __export(index_exports, {
|
|
|
54
54
|
SUPER_ADMIN_HTTP_KEY: () => SUPER_ADMIN_HTTP_KEY,
|
|
55
55
|
SUPER_ADMIN_LOGIN_ADAPTER_KEY: () => SUPER_ADMIN_LOGIN_ADAPTER_KEY,
|
|
56
56
|
SUPER_ADMIN_MANIFEST_KEY: () => SUPER_ADMIN_MANIFEST_KEY,
|
|
57
|
+
SUPER_ADMIN_NOTIFY_KEY: () => SUPER_ADMIN_NOTIFY_KEY,
|
|
57
58
|
TenantSubscriptionBundlesApiError: () => TenantSubscriptionBundlesApiError,
|
|
58
59
|
buildFeatureRegistry: () => buildFeatureRegistry,
|
|
59
60
|
buildFeatureRouterGuard: () => buildFeatureRouterGuard,
|
|
@@ -66,7 +67,6 @@ __export(index_exports, {
|
|
|
66
67
|
createManifestStore: () => createManifestStore,
|
|
67
68
|
createPlatformLoaders: () => createPlatformLoaders,
|
|
68
69
|
createProjectPageHostRoute: () => createProjectPageHostRoute,
|
|
69
|
-
createSuperAdminApp: () => createSuperAdminApp,
|
|
70
70
|
defaultHttpClient: () => defaultHttpClient,
|
|
71
71
|
defaultIconForActionKey: () => defaultIconForActionKey,
|
|
72
72
|
defaultKvStore: () => defaultKvStore,
|
|
@@ -117,12 +117,12 @@ __export(index_exports, {
|
|
|
117
117
|
useTenantSubscriptionBundles: () => useTenantSubscriptionBundles,
|
|
118
118
|
useTenants: () => useTenants
|
|
119
119
|
});
|
|
120
|
-
module.exports = __toCommonJS(
|
|
120
|
+
module.exports = __toCommonJS(src_exports);
|
|
121
121
|
|
|
122
|
-
// src/version.ts
|
|
122
|
+
// src/client/version.ts
|
|
123
123
|
var ADMIN_UI_VERSION = "1.2.0";
|
|
124
124
|
|
|
125
|
-
// src/types.ts
|
|
125
|
+
// src/client/types.ts
|
|
126
126
|
function defaultKvStore() {
|
|
127
127
|
if (typeof globalThis.localStorage === "undefined") {
|
|
128
128
|
return {
|
|
@@ -144,7 +144,7 @@ function defaultHttpClient() {
|
|
|
144
144
|
return (url, init) => fetch(url, init);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
// src/http-json.ts
|
|
147
|
+
// src/client/http-json.ts
|
|
148
148
|
var HttpJsonError = class extends Error {
|
|
149
149
|
constructor(status, code) {
|
|
150
150
|
super(code ?? `HTTP ${status}`);
|
|
@@ -187,195 +187,7 @@ async function postJson(http, url, body) {
|
|
|
187
187
|
return await res.json();
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
// src/
|
|
191
|
-
var import_vue2 = require("vue");
|
|
192
|
-
var import_vue_router2 = require("vue-router");
|
|
193
|
-
|
|
194
|
-
// src/create-super-admin-app.ts
|
|
195
|
-
var import_vue = require("vue");
|
|
196
|
-
var import_quasar = require("quasar");
|
|
197
|
-
var import_pinia = require("pinia");
|
|
198
|
-
var import_vue_router = require("vue-router");
|
|
199
|
-
var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
|
|
200
|
-
"@saasicat/ui-vue/SUPER_ADMIN_BRAND"
|
|
201
|
-
);
|
|
202
|
-
var SUPER_ADMIN_ENDPOINTS_KEY = /* @__PURE__ */ Symbol.for(
|
|
203
|
-
"@saasicat/ui-vue/SUPER_ADMIN_ENDPOINTS"
|
|
204
|
-
);
|
|
205
|
-
var SUPER_ADMIN_EXTENSIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
206
|
-
"@saasicat/ui-vue/SUPER_ADMIN_EXTENSIONS"
|
|
207
|
-
);
|
|
208
|
-
var SUPER_ADMIN_ACTIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
209
|
-
"@saasicat/ui-vue/SUPER_ADMIN_ACTIONS"
|
|
210
|
-
);
|
|
211
|
-
var SUPER_ADMIN_MANIFEST_KEY = /* @__PURE__ */ Symbol.for(
|
|
212
|
-
"@saasicat/ui-vue/SUPER_ADMIN_MANIFEST"
|
|
213
|
-
);
|
|
214
|
-
var SUPER_ADMIN_LOGIN_ADAPTER_KEY = /* @__PURE__ */ Symbol.for(
|
|
215
|
-
"@saasicat/ui-vue/SUPER_ADMIN_LOGIN_ADAPTER"
|
|
216
|
-
);
|
|
217
|
-
var SUPER_ADMIN_HTTP_KEY = /* @__PURE__ */ Symbol.for(
|
|
218
|
-
"@saasicat/ui-vue/SUPER_ADMIN_HTTP"
|
|
219
|
-
);
|
|
220
|
-
var DEFAULT_QUASAR_OPTIONS = {
|
|
221
|
-
plugins: { Notify: import_quasar.Notify, Dialog: import_quasar.Dialog, Loading: import_quasar.Loading },
|
|
222
|
-
config: { notify: { position: "top-right", timeout: 3e3 } }
|
|
223
|
-
};
|
|
224
|
-
function createSuperAdminApp(options) {
|
|
225
|
-
const app = (0, import_vue.createApp)(options.rootComponent);
|
|
226
|
-
app.use(import_quasar.Quasar, options.quasarOptions ?? DEFAULT_QUASAR_OPTIONS);
|
|
227
|
-
const pinia = (0, import_pinia.createPinia)();
|
|
228
|
-
app.use(pinia);
|
|
229
|
-
const router = (0, import_vue_router.createRouter)({
|
|
230
|
-
history: options.routerHistory ?? (0, import_vue_router.createWebHistory)(),
|
|
231
|
-
routes: options.appRoutes
|
|
232
|
-
});
|
|
233
|
-
const navGuard = buildNavigationGuard(options);
|
|
234
|
-
if (navGuard) {
|
|
235
|
-
router.beforeEach(navGuard);
|
|
236
|
-
}
|
|
237
|
-
app.use(router);
|
|
238
|
-
const endpoints = {
|
|
239
|
-
apiBase: options.endpoints.apiBase,
|
|
240
|
-
publicBootEndpoint: options.endpoints.publicBootEndpoint ?? `${options.endpoints.apiBase}/boot`,
|
|
241
|
-
manifestEndpoint: options.endpoints.manifestEndpoint ?? `${options.endpoints.apiBase}/manifest`
|
|
242
|
-
};
|
|
243
|
-
app.provide(SUPER_ADMIN_BRAND_KEY, { tag: "SuperAdmin", ...options.brand });
|
|
244
|
-
app.provide(SUPER_ADMIN_ENDPOINTS_KEY, endpoints);
|
|
245
|
-
app.provide(SUPER_ADMIN_EXTENSIONS_KEY, options.extensions ?? {});
|
|
246
|
-
app.provide(SUPER_ADMIN_ACTIONS_KEY, options.actions ?? {});
|
|
247
|
-
if (options.manifestGuard?.getManifest) {
|
|
248
|
-
app.provide(SUPER_ADMIN_MANIFEST_KEY, options.manifestGuard.getManifest);
|
|
249
|
-
}
|
|
250
|
-
if (options.loginAdapter) {
|
|
251
|
-
app.provide(SUPER_ADMIN_LOGIN_ADAPTER_KEY, options.loginAdapter);
|
|
252
|
-
}
|
|
253
|
-
app.provide(SUPER_ADMIN_HTTP_KEY, options.http ?? defaultHttpClient());
|
|
254
|
-
for (const plugin of options.installPlugins ?? []) {
|
|
255
|
-
plugin(app);
|
|
256
|
-
}
|
|
257
|
-
return {
|
|
258
|
-
app,
|
|
259
|
-
router,
|
|
260
|
-
pinia,
|
|
261
|
-
mount: (selector) => app.mount(selector)
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
function buildNavigationGuard(options) {
|
|
265
|
-
const { authGuard, manifestGuard } = options;
|
|
266
|
-
if (!authGuard && !manifestGuard) return null;
|
|
267
|
-
return async (to) => {
|
|
268
|
-
if (to.meta?.public === true) return true;
|
|
269
|
-
if (authGuard) {
|
|
270
|
-
if (!authGuard.isAuthenticated()) return authGuard.onUnauthenticated();
|
|
271
|
-
if (authGuard.isSuperAdmin && !authGuard.isSuperAdmin()) {
|
|
272
|
-
return authGuard.onUnauthenticated();
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (manifestGuard) {
|
|
276
|
-
try {
|
|
277
|
-
await manifestGuard.ensureLoaded();
|
|
278
|
-
} catch (err) {
|
|
279
|
-
if (manifestGuard.errorRoute && to.path !== manifestGuard.errorRoute) {
|
|
280
|
-
return manifestGuard.errorRoute;
|
|
281
|
-
}
|
|
282
|
-
console.error("[SuperAdmin] manifest load failed", err);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return true;
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// src/project-page-host.ts
|
|
290
|
-
var asyncComponentCache = /* @__PURE__ */ new WeakMap();
|
|
291
|
-
function resolveAsync(extensions, key) {
|
|
292
|
-
let bucket = asyncComponentCache.get(extensions);
|
|
293
|
-
if (!bucket) {
|
|
294
|
-
bucket = /* @__PURE__ */ new Map();
|
|
295
|
-
asyncComponentCache.set(extensions, bucket);
|
|
296
|
-
}
|
|
297
|
-
const cached = bucket.get(key);
|
|
298
|
-
if (cached) return cached;
|
|
299
|
-
const loader = extensions[key];
|
|
300
|
-
if (!loader) return null;
|
|
301
|
-
const cmp = (0, import_vue2.defineAsyncComponent)(loader);
|
|
302
|
-
bucket.set(key, cmp);
|
|
303
|
-
return cmp;
|
|
304
|
-
}
|
|
305
|
-
var ProjectPageHost = (0, import_vue2.defineComponent)({
|
|
306
|
-
name: "ProjectPageHost",
|
|
307
|
-
setup() {
|
|
308
|
-
const route = (0, import_vue_router2.useRoute)();
|
|
309
|
-
const extensions = (0, import_vue2.inject)(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
310
|
-
const manifestAccessor = (0, import_vue2.inject)(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
311
|
-
const matchingPage = (0, import_vue2.computed)(() => {
|
|
312
|
-
const manifest = manifestAccessor ? manifestAccessor() : null;
|
|
313
|
-
if (!manifest) return null;
|
|
314
|
-
const pages = manifest.navigation?.projectPages ?? [];
|
|
315
|
-
return pages.find((p) => p.route === route.path) ?? null;
|
|
316
|
-
});
|
|
317
|
-
const resolvedComponent = (0, import_vue2.computed)(() => {
|
|
318
|
-
const page = matchingPage.value;
|
|
319
|
-
if (!page) return null;
|
|
320
|
-
return resolveAsync(extensions, page.componentKey);
|
|
321
|
-
});
|
|
322
|
-
return () => {
|
|
323
|
-
const page = matchingPage.value;
|
|
324
|
-
const cmp = resolvedComponent.value;
|
|
325
|
-
if (page && cmp) return (0, import_vue2.h)(cmp);
|
|
326
|
-
return (0, import_vue2.h)("div", { class: "sa-project-page-host__missing", role: "alert" }, [
|
|
327
|
-
(0, import_vue2.h)("h2", "Seite nicht verf\xFCgbar"),
|
|
328
|
-
(0, import_vue2.h)(
|
|
329
|
-
"p",
|
|
330
|
-
page ? `componentKey "${page.componentKey}" ist nicht in der extensions:-Map registriert. Apps m\xFCssen die Komponente in createSuperAdminApp({ extensions }) eintragen.` : `Keine Manifest-Definition f\xFCr ${route.path}. Entweder fehlt die ProjectPage im Manifest, oder die Capability ist nicht aktiv.`
|
|
331
|
-
)
|
|
332
|
-
]);
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
function createProjectPageHostRoute(options) {
|
|
337
|
-
return {
|
|
338
|
-
path: options?.path ?? ":projectPagePath(.+)",
|
|
339
|
-
component: ProjectPageHost,
|
|
340
|
-
meta: { isProjectPageHost: true }
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// src/create-admin-routes.ts
|
|
345
|
-
function createAdminRoutes(options) {
|
|
346
|
-
return [
|
|
347
|
-
{
|
|
348
|
-
path: "/login",
|
|
349
|
-
name: "login",
|
|
350
|
-
component: options.loginPage,
|
|
351
|
-
meta: { public: true }
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
// `meta.public: true` MUST be set, otherwise the route runs through
|
|
355
|
-
// the manifest guard again → redirect loop.
|
|
356
|
-
path: "/admin-error",
|
|
357
|
-
name: "admin-error",
|
|
358
|
-
component: options.adminErrorPage,
|
|
359
|
-
meta: { public: true }
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
path: "/admin",
|
|
363
|
-
component: options.adminLayout,
|
|
364
|
-
children: [
|
|
365
|
-
{ path: "", redirect: options.dashboardPath ?? "/admin/dashboard" },
|
|
366
|
-
...options.children,
|
|
367
|
-
// Catch-all for manifest ProjectPages — Vue Router 4 matches
|
|
368
|
-
// more specific children first; the host only steps in when
|
|
369
|
-
// no static page matches. MUST come last.
|
|
370
|
-
createProjectPageHostRoute()
|
|
371
|
-
]
|
|
372
|
-
},
|
|
373
|
-
{ path: "/", redirect: "/admin" },
|
|
374
|
-
{ path: "/:pathMatch(.*)*", redirect: "/admin" }
|
|
375
|
-
];
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// src/boot-loader.ts
|
|
190
|
+
// src/client/boot-loader.ts
|
|
379
191
|
var BootLoadError = class extends Error {
|
|
380
192
|
constructor(status, message) {
|
|
381
193
|
super(message);
|
|
@@ -405,7 +217,7 @@ var BootLoader = class {
|
|
|
405
217
|
}
|
|
406
218
|
};
|
|
407
219
|
|
|
408
|
-
// src/manifest-loader.ts
|
|
220
|
+
// src/client/manifest-loader.ts
|
|
409
221
|
var ManifestLoadError = class extends Error {
|
|
410
222
|
constructor(status, message) {
|
|
411
223
|
super(message);
|
|
@@ -488,7 +300,7 @@ var ManifestLoader = class {
|
|
|
488
300
|
}
|
|
489
301
|
};
|
|
490
302
|
|
|
491
|
-
// src/nav-builder.ts
|
|
303
|
+
// src/client/nav-builder.ts
|
|
492
304
|
var DEFAULT_STANDARD_PAGE_ROUTES = {
|
|
493
305
|
dashboard: "/admin/dashboard",
|
|
494
306
|
tenants: "/admin/tenants",
|
|
@@ -636,7 +448,7 @@ function resolveExtension(componentKey, extensions) {
|
|
|
636
448
|
return extensions[componentKey] ?? null;
|
|
637
449
|
}
|
|
638
450
|
|
|
639
|
-
// src/action-registry.ts
|
|
451
|
+
// src/client/action-registry.ts
|
|
640
452
|
var MissingHandlerError = class extends Error {
|
|
641
453
|
constructor(actionKey) {
|
|
642
454
|
super(
|
|
@@ -712,7 +524,7 @@ var ActionRegistry = class {
|
|
|
712
524
|
}
|
|
713
525
|
};
|
|
714
526
|
|
|
715
|
-
// src/batch-column-fetcher.ts
|
|
527
|
+
// src/client/batch-column-fetcher.ts
|
|
716
528
|
var BatchColumnDriftError = class extends Error {
|
|
717
529
|
constructor(column, reason) {
|
|
718
530
|
super(`Spalte "${column.key}": ${reason}`);
|
|
@@ -812,116 +624,509 @@ var BatchColumnFetcher = class {
|
|
|
812
624
|
}
|
|
813
625
|
};
|
|
814
626
|
|
|
815
|
-
// src/
|
|
816
|
-
var
|
|
817
|
-
function
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
const page = (0, import_vue3.ref)(1);
|
|
821
|
-
const pageSize = (0, import_vue3.ref)(50);
|
|
822
|
-
const total = (0, import_vue3.ref)(0);
|
|
823
|
-
const loading = (0, import_vue3.ref)(false);
|
|
824
|
-
const error = (0, import_vue3.ref)(null);
|
|
825
|
-
function buildUrl() {
|
|
826
|
-
const params = new URLSearchParams();
|
|
827
|
-
params.set("page", String(page.value));
|
|
828
|
-
params.set("pageSize", String(pageSize.value));
|
|
829
|
-
const f = options.filter?.value ?? {};
|
|
830
|
-
for (const [k, v] of Object.entries(f)) {
|
|
831
|
-
if (v === void 0 || v === null || v === "") continue;
|
|
832
|
-
params.set(k, String(v));
|
|
833
|
-
}
|
|
834
|
-
const sep = options.endpoint.includes("?") ? "&" : "?";
|
|
835
|
-
return `${options.endpoint}${sep}${params.toString()}`;
|
|
836
|
-
}
|
|
837
|
-
async function load() {
|
|
838
|
-
loading.value = true;
|
|
839
|
-
error.value = null;
|
|
840
|
-
try {
|
|
841
|
-
const headers = {};
|
|
842
|
-
const token = options.getAuthToken?.();
|
|
843
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
844
|
-
const res = await http(buildUrl(), { method: "GET", headers });
|
|
845
|
-
if (res.status !== 200) {
|
|
846
|
-
throw new Error(`Endpoint ${options.endpoint} \u2192 HTTP ${res.status}`);
|
|
847
|
-
}
|
|
848
|
-
const raw = await res.json();
|
|
849
|
-
if (Array.isArray(raw)) {
|
|
850
|
-
items.value = raw;
|
|
851
|
-
total.value = raw.length;
|
|
852
|
-
} else if (raw !== null && typeof raw === "object") {
|
|
853
|
-
const body = raw;
|
|
854
|
-
items.value = body.items ?? [];
|
|
855
|
-
if (typeof body.page === "number") page.value = body.page;
|
|
856
|
-
if (typeof body.pageSize === "number") pageSize.value = body.pageSize;
|
|
857
|
-
if (typeof body.total === "number") total.value = body.total;
|
|
858
|
-
} else {
|
|
859
|
-
items.value = [];
|
|
860
|
-
total.value = 0;
|
|
861
|
-
}
|
|
862
|
-
} catch (err) {
|
|
863
|
-
error.value = err instanceof Error ? err : new Error(String(err));
|
|
864
|
-
items.value = [];
|
|
865
|
-
total.value = 0;
|
|
866
|
-
} finally {
|
|
867
|
-
loading.value = false;
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
async function goToPage(p) {
|
|
871
|
-
page.value = Math.max(1, Math.floor(p));
|
|
872
|
-
await load();
|
|
873
|
-
}
|
|
874
|
-
async function setPageSize(size) {
|
|
875
|
-
pageSize.value = Math.max(1, Math.floor(size));
|
|
876
|
-
page.value = 1;
|
|
877
|
-
await load();
|
|
878
|
-
}
|
|
879
|
-
if (options.filter) {
|
|
880
|
-
(0, import_vue3.watch)(
|
|
881
|
-
options.filter,
|
|
882
|
-
() => {
|
|
883
|
-
page.value = 1;
|
|
884
|
-
void load();
|
|
885
|
-
},
|
|
886
|
-
{ deep: true }
|
|
887
|
-
);
|
|
888
|
-
}
|
|
889
|
-
if (options.autoLoad !== false) {
|
|
890
|
-
Promise.resolve().then(() => void load());
|
|
627
|
+
// src/client/plan-versions-catalog.ts
|
|
628
|
+
var dec = (s) => Number(s);
|
|
629
|
+
function extractQuotas(p) {
|
|
630
|
+
if (p.quotas && Object.keys(p.quotas).length > 0) {
|
|
631
|
+
return { ...p.quotas };
|
|
891
632
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
loading,
|
|
898
|
-
error,
|
|
899
|
-
reload: load,
|
|
900
|
-
goToPage,
|
|
901
|
-
setPageSize
|
|
902
|
-
};
|
|
633
|
+
const out = {};
|
|
634
|
+
if (typeof p.maxUsers === "number") out.users = p.maxUsers;
|
|
635
|
+
if (typeof p.maxVehicles === "number") out.vehicles = p.maxVehicles;
|
|
636
|
+
if (typeof p.maxStorageGb === "number") out.storageGb = p.maxStorageGb;
|
|
637
|
+
return out;
|
|
903
638
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
639
|
+
var sortByPublishedDesc = (rows) => [...rows].sort((a, b) => {
|
|
640
|
+
const at = a.publishedAt ? Date.parse(a.publishedAt) : Number.POSITIVE_INFINITY;
|
|
641
|
+
const bt = b.publishedAt ? Date.parse(b.publishedAt) : Number.POSITIVE_INFINITY;
|
|
642
|
+
if (at !== bt) return bt - at;
|
|
643
|
+
return b.version - a.version;
|
|
644
|
+
});
|
|
645
|
+
function findLiveAt(rows, asOfMs) {
|
|
646
|
+
const candidates = rows.filter((r) => {
|
|
647
|
+
if (r.publishedAt === null) return false;
|
|
648
|
+
if (Date.parse(r.publishedAt) > asOfMs) return false;
|
|
649
|
+
if (r.supersededAt !== null && Date.parse(r.supersededAt) <= asOfMs) return false;
|
|
650
|
+
return true;
|
|
651
|
+
});
|
|
652
|
+
if (candidates.length === 0) return null;
|
|
653
|
+
return [...candidates].sort((a, b) => b.version - a.version)[0] ?? null;
|
|
654
|
+
}
|
|
655
|
+
function findCurrentLive(rows) {
|
|
656
|
+
return rows.find((r) => r.publishedAt !== null && r.supersededAt === null) ?? null;
|
|
657
|
+
}
|
|
658
|
+
function findDraft(rows) {
|
|
659
|
+
return rows.find((r) => r.publishedAt === null) ?? null;
|
|
660
|
+
}
|
|
661
|
+
function groupBy(rows, keyOf) {
|
|
662
|
+
const out = /* @__PURE__ */ new Map();
|
|
663
|
+
for (const r of rows) {
|
|
664
|
+
const k = keyOf(r);
|
|
665
|
+
const list = out.get(k) ?? [];
|
|
666
|
+
list.push(r);
|
|
667
|
+
out.set(k, list);
|
|
668
|
+
}
|
|
669
|
+
return out;
|
|
670
|
+
}
|
|
671
|
+
function resolvePlan(source, liveBase) {
|
|
672
|
+
const quotas = extractQuotas(source);
|
|
673
|
+
return {
|
|
674
|
+
source,
|
|
675
|
+
liveBase,
|
|
676
|
+
isDraft: source.publishedAt === null,
|
|
677
|
+
planId: source.planId,
|
|
678
|
+
features: source.features,
|
|
679
|
+
quotas,
|
|
680
|
+
monthlyNet: dec(source.monthlyNet),
|
|
681
|
+
yearlyNet: dec(source.yearlyNet),
|
|
682
|
+
marketed: source.marketed,
|
|
683
|
+
version: source.version,
|
|
684
|
+
maxUsers: quotas.users,
|
|
685
|
+
maxVehicles: quotas.vehicles,
|
|
686
|
+
maxStorageGb: quotas.storageGb
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function dateLabelDe(iso) {
|
|
690
|
+
return new Date(iso).toLocaleDateString("de-DE", {
|
|
691
|
+
day: "2-digit",
|
|
692
|
+
month: "short",
|
|
693
|
+
year: "numeric"
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function buildDraftsSnapshot(data, sortPlansFn) {
|
|
697
|
+
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
698
|
+
const plans = [];
|
|
699
|
+
for (const [, rows] of planByKey) {
|
|
700
|
+
const draft = findDraft(rows);
|
|
701
|
+
const live = findCurrentLive(rows);
|
|
702
|
+
if (draft) plans.push(resolvePlan(draft, live));
|
|
703
|
+
else if (live) plans.push(resolvePlan(live, null));
|
|
704
|
+
}
|
|
705
|
+
const draftCount = plans.filter((p) => p.isDraft).length;
|
|
706
|
+
return {
|
|
707
|
+
id: "drafts",
|
|
708
|
+
kind: "drafts",
|
|
709
|
+
status: "DRAFT",
|
|
710
|
+
label: "Arbeitsstand",
|
|
711
|
+
title: draftCount === 0 ? "Keine offenen Drafts" : `${draftCount} offene${draftCount === 1 ? "r" : ""} Draft${draftCount === 1 ? "" : "s"} bereit f\xFCr Publish`,
|
|
712
|
+
description: draftCount === 0 ? "Lege einen Draft an, um Limits, Preise oder Features zu \xE4ndern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam." : "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.",
|
|
713
|
+
asOf: null,
|
|
714
|
+
createdAt: null,
|
|
715
|
+
publishedAt: null,
|
|
716
|
+
authorEmail: null,
|
|
717
|
+
plans: sortPlansFn(plans),
|
|
718
|
+
draftCount,
|
|
719
|
+
regressionCount: 0
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function buildActiveSnapshot(data, sortPlansFn) {
|
|
723
|
+
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
724
|
+
const plans = [];
|
|
725
|
+
for (const [, rows] of planByKey) {
|
|
726
|
+
const live = findCurrentLive(rows);
|
|
727
|
+
if (live) plans.push(resolvePlan(live, null));
|
|
728
|
+
}
|
|
729
|
+
if (plans.length === 0) return null;
|
|
730
|
+
const publishedDates = plans.map((p) => p.source.publishedAt).filter((t) => t !== null).sort();
|
|
731
|
+
const latestPublished = publishedDates[publishedDates.length - 1];
|
|
732
|
+
return {
|
|
733
|
+
id: "active",
|
|
734
|
+
kind: "active",
|
|
735
|
+
status: "ACTIVE",
|
|
736
|
+
label: "Aktuell",
|
|
737
|
+
title: "Live-Catalog",
|
|
738
|
+
description: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
|
|
739
|
+
asOf: latestPublished ?? null,
|
|
740
|
+
createdAt: null,
|
|
741
|
+
publishedAt: latestPublished ?? null,
|
|
742
|
+
authorEmail: null,
|
|
743
|
+
plans: sortPlansFn(plans),
|
|
744
|
+
draftCount: 0,
|
|
745
|
+
regressionCount: 0
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
function buildHistoricalSnapshots(data, sortPlansFn) {
|
|
749
|
+
const allPublishedAt = /* @__PURE__ */ new Set();
|
|
750
|
+
for (const r of data.planVersions) if (r.publishedAt) allPublishedAt.add(r.publishedAt);
|
|
751
|
+
if (allPublishedAt.size === 0) return [];
|
|
752
|
+
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
753
|
+
const liveTimestamps = /* @__PURE__ */ new Set();
|
|
754
|
+
for (const rows of planByKey.values()) {
|
|
755
|
+
const live = findCurrentLive(rows);
|
|
756
|
+
if (live?.publishedAt) liveTimestamps.add(live.publishedAt);
|
|
757
|
+
}
|
|
758
|
+
const liveSorted = [...liveTimestamps].sort();
|
|
759
|
+
const latestLive = liveSorted[liveSorted.length - 1];
|
|
760
|
+
const sortedDesc = [...allPublishedAt].sort((a, b) => Date.parse(b) - Date.parse(a));
|
|
761
|
+
const out = [];
|
|
762
|
+
for (const ts of sortedDesc) {
|
|
763
|
+
if (latestLive && Date.parse(ts) >= Date.parse(latestLive)) continue;
|
|
764
|
+
const tMs = Date.parse(ts) + 1;
|
|
765
|
+
const plans = [];
|
|
766
|
+
for (const [, rows] of planByKey) {
|
|
767
|
+
const live = findLiveAt(rows, tMs);
|
|
768
|
+
if (live) plans.push(resolvePlan(live, null));
|
|
769
|
+
}
|
|
770
|
+
if (plans.length === 0) continue;
|
|
771
|
+
const publishedAtThisEvent = data.planVersions.filter((r) => r.publishedAt === ts);
|
|
772
|
+
const regressionCount = publishedAtThisEvent.filter((r) => !r.nonRegressive).length;
|
|
773
|
+
const author = publishedAtThisEvent[0]?.publishedByUserId ?? null;
|
|
774
|
+
out.push({
|
|
775
|
+
id: `hist-${ts}`,
|
|
776
|
+
kind: "historical",
|
|
777
|
+
status: "ARCHIVED",
|
|
778
|
+
label: dateLabelDe(ts),
|
|
779
|
+
title: summarizeEvent(publishedAtThisEvent),
|
|
780
|
+
description: detailEvent(publishedAtThisEvent),
|
|
781
|
+
asOf: ts,
|
|
782
|
+
createdAt: ts,
|
|
783
|
+
publishedAt: ts,
|
|
784
|
+
authorEmail: author,
|
|
785
|
+
plans: sortPlansFn(plans),
|
|
786
|
+
draftCount: 0,
|
|
787
|
+
regressionCount
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
return out;
|
|
791
|
+
}
|
|
792
|
+
function summarizeEvent(rows) {
|
|
793
|
+
if (rows.length === 0) return "Publish-Event";
|
|
794
|
+
if (rows.length === 1) {
|
|
795
|
+
const r = rows[0];
|
|
796
|
+
return `${r.planId} v${r.version} publiziert`;
|
|
797
|
+
}
|
|
798
|
+
return `${rows.length} Versionen publiziert`;
|
|
799
|
+
}
|
|
800
|
+
function detailEvent(rows) {
|
|
801
|
+
if (rows.length === 0) return "";
|
|
802
|
+
const note = rows[0]?.changeNote ?? "";
|
|
803
|
+
return note.length > 0 ? note : "Snapshot rekonstruiert aus per-Entity-Versionen.";
|
|
804
|
+
}
|
|
805
|
+
function sortPlansBy(order) {
|
|
806
|
+
if (!order || order.length === 0) {
|
|
807
|
+
return (rows) => [...rows].sort((a, b) => a.planId.localeCompare(b.planId));
|
|
808
|
+
}
|
|
809
|
+
const idx = {};
|
|
810
|
+
for (let i = 0; i < order.length; i++) idx[order[i]] = i;
|
|
811
|
+
return (rows) => [...rows].sort((a, b) => {
|
|
812
|
+
const ai = idx[a.planId] ?? Number.POSITIVE_INFINITY;
|
|
813
|
+
const bi = idx[b.planId] ?? Number.POSITIVE_INFINITY;
|
|
814
|
+
if (ai !== bi) return ai - bi;
|
|
815
|
+
return a.planId.localeCompare(b.planId);
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
function buildSnapshots(data, options = {}) {
|
|
819
|
+
const sortPlansFn = sortPlansBy(options.planSortOrder);
|
|
820
|
+
const drafts = buildDraftsSnapshot(data, sortPlansFn);
|
|
821
|
+
const active = buildActiveSnapshot(data, sortPlansFn);
|
|
822
|
+
const historical = buildHistoricalSnapshots(data, sortPlansFn);
|
|
823
|
+
const out = [drafts];
|
|
824
|
+
if (active) out.push(active);
|
|
825
|
+
out.push(...historical);
|
|
826
|
+
return out;
|
|
827
|
+
}
|
|
828
|
+
function listOpenDrafts(data) {
|
|
829
|
+
return {
|
|
830
|
+
plans: sortByPublishedDesc(data.planVersions).filter((r) => r.publishedAt === null)
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/vue/super-admin-context.ts
|
|
835
|
+
var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
|
|
836
|
+
"@saasicat/ui-vue/SUPER_ADMIN_BRAND"
|
|
837
|
+
);
|
|
838
|
+
var SUPER_ADMIN_ENDPOINTS_KEY = /* @__PURE__ */ Symbol.for(
|
|
839
|
+
"@saasicat/ui-vue/SUPER_ADMIN_ENDPOINTS"
|
|
840
|
+
);
|
|
841
|
+
var SUPER_ADMIN_EXTENSIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
842
|
+
"@saasicat/ui-vue/SUPER_ADMIN_EXTENSIONS"
|
|
843
|
+
);
|
|
844
|
+
var SUPER_ADMIN_ACTIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
845
|
+
"@saasicat/ui-vue/SUPER_ADMIN_ACTIONS"
|
|
846
|
+
);
|
|
847
|
+
var SUPER_ADMIN_MANIFEST_KEY = /* @__PURE__ */ Symbol.for(
|
|
848
|
+
"@saasicat/ui-vue/SUPER_ADMIN_MANIFEST"
|
|
849
|
+
);
|
|
850
|
+
var SUPER_ADMIN_LOGIN_ADAPTER_KEY = /* @__PURE__ */ Symbol.for(
|
|
851
|
+
"@saasicat/ui-vue/SUPER_ADMIN_LOGIN_ADAPTER"
|
|
852
|
+
);
|
|
853
|
+
var SUPER_ADMIN_HTTP_KEY = /* @__PURE__ */ Symbol.for(
|
|
854
|
+
"@saasicat/ui-vue/SUPER_ADMIN_HTTP"
|
|
855
|
+
);
|
|
856
|
+
function buildNavigationGuard(options) {
|
|
857
|
+
const { authGuard, manifestGuard } = options;
|
|
858
|
+
if (!authGuard && !manifestGuard) return null;
|
|
859
|
+
return async (to) => {
|
|
860
|
+
if (to.meta?.public === true) return true;
|
|
861
|
+
if (authGuard) {
|
|
862
|
+
if (!authGuard.isAuthenticated()) return authGuard.onUnauthenticated();
|
|
863
|
+
if (authGuard.isSuperAdmin && !authGuard.isSuperAdmin()) {
|
|
864
|
+
return authGuard.onUnauthenticated();
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (manifestGuard) {
|
|
868
|
+
try {
|
|
869
|
+
await manifestGuard.ensureLoaded();
|
|
870
|
+
} catch (err) {
|
|
871
|
+
if (manifestGuard.errorRoute && to.path !== manifestGuard.errorRoute) {
|
|
872
|
+
return manifestGuard.errorRoute;
|
|
873
|
+
}
|
|
874
|
+
console.error("[SuperAdmin] manifest load failed", err);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return true;
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// src/vue/ui-notify.ts
|
|
882
|
+
var SUPER_ADMIN_NOTIFY_KEY = /* @__PURE__ */ Symbol.for(
|
|
883
|
+
"@saasicat/ui-vue/SUPER_ADMIN_NOTIFY"
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
// src/vue/use-super-admin-context.ts
|
|
887
|
+
var import_vue = require("vue");
|
|
888
|
+
function useSuperAdminExtensions() {
|
|
889
|
+
return (0, import_vue.inject)(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
890
|
+
}
|
|
891
|
+
function useSuperAdminActions() {
|
|
892
|
+
return (0, import_vue.inject)(SUPER_ADMIN_ACTIONS_KEY, {});
|
|
893
|
+
}
|
|
894
|
+
function useSuperAdminBrand() {
|
|
895
|
+
const brand = (0, import_vue.inject)(SUPER_ADMIN_BRAND_KEY);
|
|
896
|
+
if (!brand) {
|
|
897
|
+
throw new Error(
|
|
898
|
+
"useSuperAdminBrand(): kein SuperAdmin-Branding im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
return brand;
|
|
902
|
+
}
|
|
903
|
+
function useSuperAdminEndpoints() {
|
|
904
|
+
const endpoints = (0, import_vue.inject)(SUPER_ADMIN_ENDPOINTS_KEY);
|
|
905
|
+
if (!endpoints) {
|
|
906
|
+
throw new Error(
|
|
907
|
+
"useSuperAdminEndpoints(): keine Endpoints im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
return endpoints;
|
|
911
|
+
}
|
|
912
|
+
function useSuperAdminManifest() {
|
|
913
|
+
const accessor = (0, import_vue.inject)(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
914
|
+
return accessor ? accessor() : null;
|
|
915
|
+
}
|
|
916
|
+
function useSuperAdminLoginAdapter() {
|
|
917
|
+
const adapter = (0, import_vue.inject)(SUPER_ADMIN_LOGIN_ADAPTER_KEY);
|
|
918
|
+
if (!adapter) {
|
|
919
|
+
throw new Error(
|
|
920
|
+
"useSuperAdminLoginAdapter(): kein Login-Adapter registriert. Reiche ihn via createSuperAdminApp({ loginAdapter }) ein."
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
return adapter;
|
|
924
|
+
}
|
|
925
|
+
function useSuperAdminHttp() {
|
|
926
|
+
return (0, import_vue.inject)(SUPER_ADMIN_HTTP_KEY, defaultHttpClient());
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// src/vue/project-page-host.ts
|
|
930
|
+
var import_vue2 = require("vue");
|
|
931
|
+
var import_vue_router = require("vue-router");
|
|
932
|
+
var asyncComponentCache = /* @__PURE__ */ new WeakMap();
|
|
933
|
+
function resolveAsync(extensions, key) {
|
|
934
|
+
let bucket = asyncComponentCache.get(extensions);
|
|
935
|
+
if (!bucket) {
|
|
936
|
+
bucket = /* @__PURE__ */ new Map();
|
|
937
|
+
asyncComponentCache.set(extensions, bucket);
|
|
938
|
+
}
|
|
939
|
+
const cached = bucket.get(key);
|
|
940
|
+
if (cached) return cached;
|
|
941
|
+
const loader = extensions[key];
|
|
942
|
+
if (!loader) return null;
|
|
943
|
+
const cmp = (0, import_vue2.defineAsyncComponent)(loader);
|
|
944
|
+
bucket.set(key, cmp);
|
|
945
|
+
return cmp;
|
|
946
|
+
}
|
|
947
|
+
var ProjectPageHost = (0, import_vue2.defineComponent)({
|
|
948
|
+
name: "ProjectPageHost",
|
|
949
|
+
setup() {
|
|
950
|
+
const route = (0, import_vue_router.useRoute)();
|
|
951
|
+
const extensions = (0, import_vue2.inject)(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
952
|
+
const manifestAccessor = (0, import_vue2.inject)(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
953
|
+
const matchingPage = (0, import_vue2.computed)(() => {
|
|
954
|
+
const manifest = manifestAccessor ? manifestAccessor() : null;
|
|
955
|
+
if (!manifest) return null;
|
|
956
|
+
const pages = manifest.navigation?.projectPages ?? [];
|
|
957
|
+
return pages.find((p) => p.route === route.path) ?? null;
|
|
958
|
+
});
|
|
959
|
+
const resolvedComponent = (0, import_vue2.computed)(() => {
|
|
960
|
+
const page = matchingPage.value;
|
|
961
|
+
if (!page) return null;
|
|
962
|
+
return resolveAsync(extensions, page.componentKey);
|
|
963
|
+
});
|
|
964
|
+
return () => {
|
|
965
|
+
const page = matchingPage.value;
|
|
966
|
+
const cmp = resolvedComponent.value;
|
|
967
|
+
if (page && cmp) return (0, import_vue2.h)(cmp);
|
|
968
|
+
return (0, import_vue2.h)("div", { class: "sa-project-page-host__missing", role: "alert" }, [
|
|
969
|
+
(0, import_vue2.h)("h2", "Seite nicht verf\xFCgbar"),
|
|
970
|
+
(0, import_vue2.h)(
|
|
971
|
+
"p",
|
|
972
|
+
page ? `componentKey "${page.componentKey}" ist nicht in der extensions:-Map registriert. Apps m\xFCssen die Komponente in createSuperAdminApp({ extensions }) eintragen.` : `Keine Manifest-Definition f\xFCr ${route.path}. Entweder fehlt die ProjectPage im Manifest, oder die Capability ist nicht aktiv.`
|
|
973
|
+
)
|
|
974
|
+
]);
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
function createProjectPageHostRoute(options) {
|
|
979
|
+
return {
|
|
980
|
+
path: options?.path ?? ":projectPagePath(.+)",
|
|
981
|
+
component: ProjectPageHost,
|
|
982
|
+
meta: { isProjectPageHost: true }
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// src/vue/create-admin-routes.ts
|
|
987
|
+
function createAdminRoutes(options) {
|
|
988
|
+
return [
|
|
989
|
+
{
|
|
990
|
+
path: "/login",
|
|
991
|
+
name: "login",
|
|
992
|
+
component: options.loginPage,
|
|
993
|
+
meta: { public: true }
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
// `meta.public: true` MUST be set, otherwise the route runs through
|
|
997
|
+
// the manifest guard again → redirect loop.
|
|
998
|
+
path: "/admin-error",
|
|
999
|
+
name: "admin-error",
|
|
1000
|
+
component: options.adminErrorPage,
|
|
1001
|
+
meta: { public: true }
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
path: "/admin",
|
|
1005
|
+
component: options.adminLayout,
|
|
1006
|
+
children: [
|
|
1007
|
+
{ path: "", redirect: options.dashboardPath ?? "/admin/dashboard" },
|
|
1008
|
+
...options.children,
|
|
1009
|
+
// Catch-all for manifest ProjectPages — Vue Router 4 matches
|
|
1010
|
+
// more specific children first; the host only steps in when
|
|
1011
|
+
// no static page matches. MUST come last.
|
|
1012
|
+
createProjectPageHostRoute()
|
|
1013
|
+
]
|
|
1014
|
+
},
|
|
1015
|
+
{ path: "/", redirect: "/admin" },
|
|
1016
|
+
{ path: "/:pathMatch(.*)*", redirect: "/admin" }
|
|
1017
|
+
];
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// src/vue/use-api-list.ts
|
|
1021
|
+
var import_vue3 = require("vue");
|
|
1022
|
+
function useApiList(options) {
|
|
1023
|
+
const http = options.http ?? defaultHttpClient();
|
|
1024
|
+
const items = (0, import_vue3.ref)([]);
|
|
1025
|
+
const page = (0, import_vue3.ref)(1);
|
|
1026
|
+
const pageSize = (0, import_vue3.ref)(50);
|
|
1027
|
+
const total = (0, import_vue3.ref)(0);
|
|
1028
|
+
const loading = (0, import_vue3.ref)(false);
|
|
1029
|
+
const error = (0, import_vue3.ref)(null);
|
|
1030
|
+
function buildUrl() {
|
|
1031
|
+
const params = new URLSearchParams();
|
|
1032
|
+
params.set("page", String(page.value));
|
|
1033
|
+
params.set("pageSize", String(pageSize.value));
|
|
1034
|
+
const f = options.filter?.value ?? {};
|
|
1035
|
+
for (const [k, v] of Object.entries(f)) {
|
|
1036
|
+
if (v === void 0 || v === null || v === "") continue;
|
|
1037
|
+
params.set(k, String(v));
|
|
1038
|
+
}
|
|
1039
|
+
const sep = options.endpoint.includes("?") ? "&" : "?";
|
|
1040
|
+
return `${options.endpoint}${sep}${params.toString()}`;
|
|
1041
|
+
}
|
|
1042
|
+
async function load() {
|
|
1043
|
+
loading.value = true;
|
|
1044
|
+
error.value = null;
|
|
1045
|
+
try {
|
|
1046
|
+
const headers = {};
|
|
1047
|
+
const token = options.getAuthToken?.();
|
|
1048
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1049
|
+
const res = await http(buildUrl(), { method: "GET", headers });
|
|
1050
|
+
if (res.status !== 200) {
|
|
1051
|
+
throw new Error(`Endpoint ${options.endpoint} \u2192 HTTP ${res.status}`);
|
|
1052
|
+
}
|
|
1053
|
+
const raw = await res.json();
|
|
1054
|
+
if (Array.isArray(raw)) {
|
|
1055
|
+
items.value = raw;
|
|
1056
|
+
total.value = raw.length;
|
|
1057
|
+
} else if (raw !== null && typeof raw === "object") {
|
|
1058
|
+
const body = raw;
|
|
1059
|
+
items.value = body.items ?? [];
|
|
1060
|
+
if (typeof body.page === "number") page.value = body.page;
|
|
1061
|
+
if (typeof body.pageSize === "number") pageSize.value = body.pageSize;
|
|
1062
|
+
if (typeof body.total === "number") total.value = body.total;
|
|
1063
|
+
} else {
|
|
1064
|
+
items.value = [];
|
|
1065
|
+
total.value = 0;
|
|
1066
|
+
}
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
error.value = err instanceof Error ? err : new Error(String(err));
|
|
1069
|
+
items.value = [];
|
|
1070
|
+
total.value = 0;
|
|
1071
|
+
} finally {
|
|
1072
|
+
loading.value = false;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
async function goToPage(p) {
|
|
1076
|
+
page.value = Math.max(1, Math.floor(p));
|
|
1077
|
+
await load();
|
|
1078
|
+
}
|
|
1079
|
+
async function setPageSize(size) {
|
|
1080
|
+
pageSize.value = Math.max(1, Math.floor(size));
|
|
1081
|
+
page.value = 1;
|
|
1082
|
+
await load();
|
|
1083
|
+
}
|
|
1084
|
+
if (options.filter) {
|
|
1085
|
+
(0, import_vue3.watch)(
|
|
1086
|
+
options.filter,
|
|
1087
|
+
() => {
|
|
1088
|
+
page.value = 1;
|
|
1089
|
+
void load();
|
|
1090
|
+
},
|
|
1091
|
+
{ deep: true }
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (options.autoLoad !== false) {
|
|
1095
|
+
Promise.resolve().then(() => void load());
|
|
1096
|
+
}
|
|
1097
|
+
return {
|
|
1098
|
+
items,
|
|
1099
|
+
page,
|
|
1100
|
+
pageSize,
|
|
1101
|
+
total,
|
|
1102
|
+
loading,
|
|
1103
|
+
error,
|
|
1104
|
+
reload: load,
|
|
1105
|
+
goToPage,
|
|
1106
|
+
setPageSize
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/vue/use-tenants.ts
|
|
1111
|
+
var import_vue4 = require("vue");
|
|
1112
|
+
function useTenants(options) {
|
|
1113
|
+
if (!options?.endpoint) {
|
|
1114
|
+
throw new Error(
|
|
1115
|
+
'useTenants: `endpoint` ist Pflicht (z. B. "/api/v1/admin/tenants" oder "/api/admin/tenants"). Plattform hat keinen Default, weil Apps unterschiedliche globalPrefix-Konventionen haben.'
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
const filter = options.filter ?? (0, import_vue4.ref)({});
|
|
1119
|
+
const list = useApiList({
|
|
1120
|
+
endpoint: options.endpoint,
|
|
1121
|
+
filter,
|
|
1122
|
+
http: options.http,
|
|
1123
|
+
getAuthToken: options.getAuthToken,
|
|
1124
|
+
autoLoad: options.autoLoad
|
|
920
1125
|
});
|
|
921
1126
|
return { ...list, filter };
|
|
922
1127
|
}
|
|
923
1128
|
|
|
924
|
-
// src/use-audit-entries.ts
|
|
1129
|
+
// src/vue/use-audit-entries.ts
|
|
925
1130
|
var import_vue5 = require("vue");
|
|
926
1131
|
function useAuditEntries(options) {
|
|
927
1132
|
if (!options?.endpoint) {
|
|
@@ -940,7 +1145,7 @@ function useAuditEntries(options) {
|
|
|
940
1145
|
return { ...list, filter };
|
|
941
1146
|
}
|
|
942
1147
|
|
|
943
|
-
// src/use-entitlement.ts
|
|
1148
|
+
// src/vue/use-entitlement.ts
|
|
944
1149
|
var import_vue6 = require("vue");
|
|
945
1150
|
function useEntitlement(options) {
|
|
946
1151
|
if (!options?.endpoint) {
|
|
@@ -981,7 +1186,7 @@ function useEntitlement(options) {
|
|
|
981
1186
|
return { entitlement, loading, error, load, hasFeature };
|
|
982
1187
|
}
|
|
983
1188
|
|
|
984
|
-
// src/use-tenant-manifest.ts
|
|
1189
|
+
// src/vue/use-tenant-manifest.ts
|
|
985
1190
|
var import_vue7 = require("vue");
|
|
986
1191
|
function useTenantManifest(options) {
|
|
987
1192
|
if (!options?.endpoint) {
|
|
@@ -1025,7 +1230,7 @@ function useTenantManifest(options) {
|
|
|
1025
1230
|
return { manifest, loading, error, load, hasFeature, quotaLimit };
|
|
1026
1231
|
}
|
|
1027
1232
|
|
|
1028
|
-
// src/entitlement-provider.ts
|
|
1233
|
+
// src/vue/entitlement-provider.ts
|
|
1029
1234
|
var import_vue8 = require("vue");
|
|
1030
1235
|
var ENTITLEMENT_INJECTION_KEY = /* @__PURE__ */ Symbol.for(
|
|
1031
1236
|
"@saasicat/ui-vue/ENTITLEMENT"
|
|
@@ -1037,7 +1242,7 @@ function useInjectedEntitlement() {
|
|
|
1037
1242
|
return (0, import_vue8.inject)(ENTITLEMENT_INJECTION_KEY, null);
|
|
1038
1243
|
}
|
|
1039
1244
|
|
|
1040
|
-
// src/feature-router-guard.ts
|
|
1245
|
+
// src/vue/feature-router-guard.ts
|
|
1041
1246
|
function extractRequired(to) {
|
|
1042
1247
|
const raw = to.meta?.requiresFeature;
|
|
1043
1248
|
if (!raw) return [];
|
|
@@ -1062,7 +1267,7 @@ function buildFeatureRouterGuard(options) {
|
|
|
1062
1267
|
};
|
|
1063
1268
|
}
|
|
1064
1269
|
|
|
1065
|
-
// src/use-tenant-billing-catalog.ts
|
|
1270
|
+
// src/vue/use-tenant-billing-catalog.ts
|
|
1066
1271
|
var import_vue9 = require("vue");
|
|
1067
1272
|
function useTenantBillingCatalog(options = {}) {
|
|
1068
1273
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
@@ -1120,7 +1325,7 @@ function useTenantBillingCatalog(options = {}) {
|
|
|
1120
1325
|
return { plans, featureRegistry, bundles, loading, error, load };
|
|
1121
1326
|
}
|
|
1122
1327
|
|
|
1123
|
-
// src/use-tenant-billing.ts
|
|
1328
|
+
// src/vue/use-tenant-billing.ts
|
|
1124
1329
|
var import_vue10 = require("vue");
|
|
1125
1330
|
function useTenantBilling(options = {}) {
|
|
1126
1331
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
@@ -1261,7 +1466,7 @@ function useTenantBilling(options = {}) {
|
|
|
1261
1466
|
};
|
|
1262
1467
|
}
|
|
1263
1468
|
|
|
1264
|
-
// src/use-subscription-draft.ts
|
|
1469
|
+
// src/vue/use-subscription-draft.ts
|
|
1265
1470
|
var import_vue11 = require("vue");
|
|
1266
1471
|
var import_types10 = require("@saasicat/types");
|
|
1267
1472
|
var DEFAULT_YEARLY_FACTOR = 10;
|
|
@@ -1453,141 +1658,7 @@ function useSubscriptionDraft(options) {
|
|
|
1453
1658
|
};
|
|
1454
1659
|
}
|
|
1455
1660
|
|
|
1456
|
-
// src/
|
|
1457
|
-
var DEFAULT_I18N_DE = {
|
|
1458
|
-
sectionTitle: "Paket & Verbrauch",
|
|
1459
|
-
sectionSubtitle: "Aktuelles Paket, Verbrauch und Bundles.",
|
|
1460
|
-
loading: "Lade \u2026",
|
|
1461
|
-
noSubscription: "Keine Subscription f\xFCr diesen Mandanten gefunden.",
|
|
1462
|
-
activePlan: "Aktuelles Paket",
|
|
1463
|
-
cycleMonthly: "Monatlich",
|
|
1464
|
-
cycleYearly: "J\xE4hrlich",
|
|
1465
|
-
statusActive: "Aktiv",
|
|
1466
|
-
statusTrial: "Testphase",
|
|
1467
|
-
statusPastDue: "Zahlung \xFCberf\xE4llig",
|
|
1468
|
-
statusCanceled: "Gek\xFCndigt",
|
|
1469
|
-
statusPendingSales: "Vertrieb-Kl\xE4rung",
|
|
1470
|
-
trialEndsAt: "Testphase endet am",
|
|
1471
|
-
pilotEndsAt: "Pilot endet am",
|
|
1472
|
-
nextBillingDate: "N\xE4chste Abrechnung",
|
|
1473
|
-
pendingChange: "Ausstehender Plan-Wechsel",
|
|
1474
|
-
changeFromTo: "Wechsel zu",
|
|
1475
|
-
changeEffectiveAt: "wirksam ab",
|
|
1476
|
-
changePlanButton: "Paket wechseln",
|
|
1477
|
-
cancelSubscriptionButton: "Abonnement k\xFCndigen",
|
|
1478
|
-
usageTitle: "Verbrauch",
|
|
1479
|
-
featuresOverviewTitle: "Leistungsumfang",
|
|
1480
|
-
featuresActive: "Enthalten",
|
|
1481
|
-
featuresLocked: "Nicht enthalten",
|
|
1482
|
-
bundlesStoreTitle: "Bundles",
|
|
1483
|
-
bundlesBookedTitle: "Gebuchte Bundles",
|
|
1484
|
-
bundlesAvailableTitle: "Verf\xFCgbare Bundles",
|
|
1485
|
-
bundlesAvailableEmpty: "Aktuell sind keine zus\xE4tzlichen Bundles verf\xFCgbar.",
|
|
1486
|
-
bundlesPerMonth: "netto/Monat",
|
|
1487
|
-
bundleBookAction: "Bundle buchen",
|
|
1488
|
-
bundleBookInProgress: "Buchung l\xE4uft \u2026",
|
|
1489
|
-
bundleCancelAction: "K\xFCndigen",
|
|
1490
|
-
bundleReactivateAction: "Reaktivieren",
|
|
1491
|
-
bundleReactivateConfirmTitle: "Bundle reaktivieren",
|
|
1492
|
-
bundleReactivateConfirmBody: "Die K\xFCndigung wird r\xFCckg\xE4ngig gemacht. Das Bundle bleibt gebucht, l\xE4uft regul\xE4r weiter und wird wieder abgerechnet.",
|
|
1493
|
-
bundleCanceledAt: "Gek\xFCndigt zum",
|
|
1494
|
-
bundleMinimumTermUntil: "Mindestlaufzeit bis",
|
|
1495
|
-
bundleIncludesLabel: "Enth\xE4lt",
|
|
1496
|
-
bundleAlreadyBooked: "Bereits gebucht",
|
|
1497
|
-
bundleIncompatible: "Nicht kompatibel mit aktuellem Paket",
|
|
1498
|
-
bundleMissingRequires: "Ben\xF6tigt",
|
|
1499
|
-
bundlePreviewAddTitle: "Bundle buchen",
|
|
1500
|
-
bundlePreviewCancelTitle: "Bundle k\xFCndigen",
|
|
1501
|
-
bundlePreviewLoading: "Vorschau wird berechnet \u2026",
|
|
1502
|
-
bundlePreviewProrationTitle: "Anteilige Abrechnung",
|
|
1503
|
-
bundlePreviewProratedNow: "Heute anteilig f\xE4llig",
|
|
1504
|
-
bundlePreviewProrationDays: "Tage",
|
|
1505
|
-
bundlePreviewNextPeriod: "Regul\xE4r ab n\xE4chster Periode",
|
|
1506
|
-
bundlePreviewTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an \u2014 die Abrechnung beginnt mit der ersten bezahlten Periode.",
|
|
1507
|
-
bundlePreviewNoPrice: "F\xFCr den aktuellen Abrechnungszyklus ist kein Listenpreis gepflegt.",
|
|
1508
|
-
bundlePreviewMinimumTermLabel: "Mindestlaufzeit",
|
|
1509
|
-
bundlePreviewMinimumTermMonths: "Monate, bis",
|
|
1510
|
-
bundlePreviewMinimumTermNone: "Keine Mindestlaufzeit",
|
|
1511
|
-
bundlePreviewRedundantTitle: "Bereits enthaltene Features (w\xFCrden doppelt bezahlt)",
|
|
1512
|
-
bundlePreviewRedundantCoveredByPlan: "bereits im Plan",
|
|
1513
|
-
bundlePreviewRedundantCoveredByBundle: "bereits im Bundle",
|
|
1514
|
-
bundlePreviewMissingRequiresTitle: "Fehlende Voraussetzungen",
|
|
1515
|
-
bundlePreviewBlockersTitle: "Buchung nicht m\xF6glich",
|
|
1516
|
-
bundlePreviewWarningsTitle: "Hinweise",
|
|
1517
|
-
bundlePreviewEffectiveAt: "K\xFCndigung wirksam zum",
|
|
1518
|
-
bundlePreviewSavings: "Ersparnis pro Periode ab Wirksamkeit",
|
|
1519
|
-
bundlePreviewConfirmAdd: "Kostenpflichtig buchen",
|
|
1520
|
-
bundlePreviewConfirmCancel: "K\xFCndigung best\xE4tigen",
|
|
1521
|
-
bundlePreviewInProgress: "Wird ausgef\xFChrt \u2026",
|
|
1522
|
-
bundlePreviewClose: "Abbrechen",
|
|
1523
|
-
pendingVersionTitle: "Anstehende Plan-\xC4nderung",
|
|
1524
|
-
pendingVersionChipNonRegressive: "Verbessernd",
|
|
1525
|
-
pendingVersionChipRegressive: "Best\xE4tigung erforderlich",
|
|
1526
|
-
pendingVersionEffectiveAt: "Wirksam ab",
|
|
1527
|
-
pendingVersionAcceptAction: "\xC4nderungen akzeptieren",
|
|
1528
|
-
pendingVersionAcceptInProgress: "Akzeptiere \u2026",
|
|
1529
|
-
pendingVersionAcceptedAt: "Akzeptiert am",
|
|
1530
|
-
wizardTitle: "Paket wechseln",
|
|
1531
|
-
wizardClose: "Schlie\xDFen",
|
|
1532
|
-
wizardCurrent: "Aktuell",
|
|
1533
|
-
wizardBadgeCurrent: "aktiv",
|
|
1534
|
-
wizardBadgePopular: "beliebt",
|
|
1535
|
-
wizardPriceUnitMonthly: "netto/Monat",
|
|
1536
|
-
wizardPriceUnitYearly: "netto/Jahr",
|
|
1537
|
-
wizardPriceOnRequest: "auf Anfrage",
|
|
1538
|
-
wizardStepChoose: "Paket w\xE4hlen",
|
|
1539
|
-
wizardStepChooseIntro: "W\xE4hle dein Ziel-Paket und den Abrechnungszyklus. Im n\xE4chsten Schritt zeigen wir Verbrauchs-Check und Feature-Diff.",
|
|
1540
|
-
wizardStepPreview: "Vorschau",
|
|
1541
|
-
wizardStepConfirm: "Best\xE4tigen",
|
|
1542
|
-
wizardNext: "Weiter",
|
|
1543
|
-
wizardBack: "Zur\xFCck",
|
|
1544
|
-
wizardPreviewLoading: "Vorschau wird berechnet \u2026",
|
|
1545
|
-
wizardEffectiveAtLabel: "Wirksam ab",
|
|
1546
|
-
wizardEffectiveImmediate: "Wirksam sofort",
|
|
1547
|
-
wizardProrationTitle: "Anteilige Abrechnung",
|
|
1548
|
-
wizardProrationLine: "Mehrbetrag bis Periodenende:",
|
|
1549
|
-
wizardProrationDays: "Tage",
|
|
1550
|
-
wizardLimitsTitle: "Limit-Vergleich",
|
|
1551
|
-
wizardLimitsUsed: "Verbrauch",
|
|
1552
|
-
wizardLimitsCurrent: "Aktuell",
|
|
1553
|
-
wizardLimitsTarget: "Ziel",
|
|
1554
|
-
wizardFeaturesGained: "Neu freigeschaltet",
|
|
1555
|
-
wizardFeaturesLost: "Wegfallende Features",
|
|
1556
|
-
wizardBlockersTitle: "Verhinderungs-Gr\xFCnde",
|
|
1557
|
-
wizardConfirmImmediate: "Der Wechsel wird sofort wirksam.",
|
|
1558
|
-
wizardConfirmScheduled: "Der Wechsel wird wirksam zum",
|
|
1559
|
-
wizardConfirmAction: "Wechsel best\xE4tigen",
|
|
1560
|
-
wizardConfirmInProgress: "Wechsel l\xE4uft \u2026",
|
|
1561
|
-
wizardConfirmPriceTitle: "Preis\xFCbersicht",
|
|
1562
|
-
wizardConfirmProratedNow: "Heute anteilig f\xE4llig",
|
|
1563
|
-
wizardConfirmRecurringNext: "Regul\xE4r ab n\xE4chster Periode",
|
|
1564
|
-
wizardConfirmRecurringFrom: "Regul\xE4r f\xE4llig ab",
|
|
1565
|
-
wizardConfirmPerCycleMonthly: "pro Monat",
|
|
1566
|
-
wizardConfirmPerCycleYearly: "pro Jahr",
|
|
1567
|
-
wizardConfirmTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an.",
|
|
1568
|
-
wizardConfirmRecurringTrialEnd: "Regul\xE4r ab Ende der Testphase",
|
|
1569
|
-
wizardChangeTypeUpgrade: "Upgrade",
|
|
1570
|
-
wizardChangeTypeDowngrade: "Downgrade",
|
|
1571
|
-
wizardChangeTypeCycle: "Zyklus-Wechsel",
|
|
1572
|
-
wizardChangeTypeNoop: "Keine \xC4nderung",
|
|
1573
|
-
packageSnapshotTitle: "Gebuchtes Paket (Snapshot)",
|
|
1574
|
-
packageSnapshotSubtitle: "Schreibgesch\xFCtzte Kopie des Pakets, wie es beim Abschluss vermarktet wurde.",
|
|
1575
|
-
packageSnapshotCapturedAt: "Erfasst am",
|
|
1576
|
-
packageSnapshotOfferRef: "Angebots-Referenz",
|
|
1577
|
-
packageSnapshotPlanLabel: "Plan",
|
|
1578
|
-
packageSnapshotPlanVersionLabel: "Plan-Version",
|
|
1579
|
-
packageSnapshotCycleLabel: "Abrechnungszyklus",
|
|
1580
|
-
packageSnapshotBundlesLabel: "Enthaltene Bundles",
|
|
1581
|
-
packageSnapshotBundlesEmpty: "Keine Bundles im Paket.",
|
|
1582
|
-
packageSnapshotPriceMonthly: "Preis monatlich",
|
|
1583
|
-
packageSnapshotPriceYearly: "Preis j\xE4hrlich",
|
|
1584
|
-
packageSnapshotPriceTotal: "Gesamtpreis",
|
|
1585
|
-
packageSnapshotNone: "Diese Subscription wurde nicht \xFCber ein Webseiten-Angebot abgeschlossen.",
|
|
1586
|
-
packageSnapshotShowRaw: "Rohdaten anzeigen",
|
|
1587
|
-
packageSnapshotHideRaw: "Rohdaten ausblenden"
|
|
1588
|
-
};
|
|
1589
|
-
|
|
1590
|
-
// src/use-plan-versions.ts
|
|
1661
|
+
// src/vue/use-plan-versions.ts
|
|
1591
1662
|
var import_vue12 = require("vue");
|
|
1592
1663
|
function buildVersionsComposable(label) {
|
|
1593
1664
|
return function(options) {
|
|
@@ -1609,7 +1680,7 @@ function buildVersionsComposable(label) {
|
|
|
1609
1680
|
}
|
|
1610
1681
|
var usePlanVersionsCatalog = buildVersionsComposable("plan-versions");
|
|
1611
1682
|
|
|
1612
|
-
// src/use-bulk-publish.ts
|
|
1683
|
+
// src/vue/use-bulk-publish.ts
|
|
1613
1684
|
var import_vue13 = require("vue");
|
|
1614
1685
|
function useBulkPublish(options) {
|
|
1615
1686
|
if (!options?.endpoints) {
|
|
@@ -1684,7 +1755,7 @@ function useBulkPublish(options) {
|
|
|
1684
1755
|
};
|
|
1685
1756
|
}
|
|
1686
1757
|
|
|
1687
|
-
// src/use-plan-editor.ts
|
|
1758
|
+
// src/vue/use-plan-editor.ts
|
|
1688
1759
|
var import_vue14 = require("vue");
|
|
1689
1760
|
var PlannedOnlyFeatureError = class extends Error {
|
|
1690
1761
|
constructor(violations) {
|
|
@@ -1761,7 +1832,7 @@ function usePlanEditor(manifest, options = {}) {
|
|
|
1761
1832
|
};
|
|
1762
1833
|
}
|
|
1763
1834
|
|
|
1764
|
-
// src/use-public-boot.ts
|
|
1835
|
+
// src/vue/use-public-boot.ts
|
|
1765
1836
|
var import_vue15 = require("vue");
|
|
1766
1837
|
function usePublicBoot(options) {
|
|
1767
1838
|
const loader = new BootLoader(options);
|
|
@@ -1783,7 +1854,7 @@ function usePublicBoot(options) {
|
|
|
1783
1854
|
return { boot, loading, error, load };
|
|
1784
1855
|
}
|
|
1785
1856
|
|
|
1786
|
-
// src/use-discovery.ts
|
|
1857
|
+
// src/vue/use-discovery.ts
|
|
1787
1858
|
var import_vue16 = require("vue");
|
|
1788
1859
|
var DiscoveryLoadError = class extends Error {
|
|
1789
1860
|
constructor(status, message) {
|
|
@@ -1869,7 +1940,7 @@ function useDiscovery(options) {
|
|
|
1869
1940
|
return { snapshot, etag, loading, error, load, reload, rescan };
|
|
1870
1941
|
}
|
|
1871
1942
|
|
|
1872
|
-
// src/use-catalog-entries.ts
|
|
1943
|
+
// src/vue/use-catalog-entries.ts
|
|
1873
1944
|
var import_vue17 = require("vue");
|
|
1874
1945
|
var CatalogEntriesApiError = class extends Error {
|
|
1875
1946
|
constructor(status, body, message) {
|
|
@@ -2018,7 +2089,7 @@ function useCatalogEntries(options) {
|
|
|
2018
2089
|
};
|
|
2019
2090
|
}
|
|
2020
2091
|
|
|
2021
|
-
// src/use-bundles.ts
|
|
2092
|
+
// src/vue/use-bundles.ts
|
|
2022
2093
|
var import_vue18 = require("vue");
|
|
2023
2094
|
var BundlesApiError = class extends Error {
|
|
2024
2095
|
constructor(status, body, message) {
|
|
@@ -2189,7 +2260,7 @@ function useBundleVersions(options) {
|
|
|
2189
2260
|
return { versions, loading, error, load, createDraft, updateDraft, publish, discardDraft };
|
|
2190
2261
|
}
|
|
2191
2262
|
|
|
2192
|
-
// src/use-bundle-versions-map.ts
|
|
2263
|
+
// src/vue/use-bundle-versions-map.ts
|
|
2193
2264
|
var import_vue19 = require("vue");
|
|
2194
2265
|
function useBundleVersionsMap(options) {
|
|
2195
2266
|
if (!options?.adminEndpoint) {
|
|
@@ -2260,7 +2331,7 @@ function useBundleVersionsMap(options) {
|
|
|
2260
2331
|
return { versionsByBundle, loading, error, refresh, refreshOne };
|
|
2261
2332
|
}
|
|
2262
2333
|
|
|
2263
|
-
// src/use-tenant-subscription-bundles.ts
|
|
2334
|
+
// src/vue/use-tenant-subscription-bundles.ts
|
|
2264
2335
|
var import_vue20 = require("vue");
|
|
2265
2336
|
var TenantSubscriptionBundlesApiError = class extends Error {
|
|
2266
2337
|
constructor(status, body, message) {
|
|
@@ -2355,7 +2426,7 @@ function rehydrateDates(raw) {
|
|
|
2355
2426
|
};
|
|
2356
2427
|
}
|
|
2357
2428
|
|
|
2358
|
-
// src/use-business-types.ts
|
|
2429
|
+
// src/vue/use-business-types.ts
|
|
2359
2430
|
var import_vue21 = require("vue");
|
|
2360
2431
|
var BusinessTypesApiError = class extends Error {
|
|
2361
2432
|
constructor(status, body, message) {
|
|
@@ -2524,7 +2595,7 @@ function useBusinessTypeVersions(options) {
|
|
|
2524
2595
|
return { versions, loading, error, load, createDraft, updateDraft, publish };
|
|
2525
2596
|
}
|
|
2526
2597
|
|
|
2527
|
-
// src/use-marketing-projections.ts
|
|
2598
|
+
// src/vue/use-marketing-projections.ts
|
|
2528
2599
|
var import_vue22 = require("vue");
|
|
2529
2600
|
var MarketingProjectionsApiError = class extends Error {
|
|
2530
2601
|
constructor(status, body, message) {
|
|
@@ -2627,7 +2698,7 @@ function useMarketingProjections(options) {
|
|
|
2627
2698
|
return { projections, filter, loading, error, setFilter, load, create, update, remove };
|
|
2628
2699
|
}
|
|
2629
2700
|
|
|
2630
|
-
// src/use-promotions.ts
|
|
2701
|
+
// src/vue/use-promotions.ts
|
|
2631
2702
|
var import_vue23 = require("vue");
|
|
2632
2703
|
var PromotionsApiError = class extends Error {
|
|
2633
2704
|
constructor(status, body, message) {
|
|
@@ -2713,7 +2784,7 @@ function usePromotions(options) {
|
|
|
2713
2784
|
return { promotions, loading, error, load, create, update, remove };
|
|
2714
2785
|
}
|
|
2715
2786
|
|
|
2716
|
-
// src/use-plans.ts
|
|
2787
|
+
// src/vue/use-plans.ts
|
|
2717
2788
|
var import_vue24 = require("vue");
|
|
2718
2789
|
var PlansApiError = class extends Error {
|
|
2719
2790
|
constructor(status, body, message) {
|
|
@@ -2937,7 +3008,7 @@ function usePlanVersions(options) {
|
|
|
2937
3008
|
};
|
|
2938
3009
|
}
|
|
2939
3010
|
|
|
2940
|
-
// src/use-live-plan-versions.ts
|
|
3011
|
+
// src/vue/use-live-plan-versions.ts
|
|
2941
3012
|
var import_vue25 = require("vue");
|
|
2942
3013
|
function useLivePlanVersions(options) {
|
|
2943
3014
|
if (!options?.adminEndpoint) {
|
|
@@ -3012,7 +3083,7 @@ function findLatestLive(versions) {
|
|
|
3012
3083
|
})[0];
|
|
3013
3084
|
}
|
|
3014
3085
|
|
|
3015
|
-
// src/use-manifest.ts
|
|
3086
|
+
// src/vue/use-manifest.ts
|
|
3016
3087
|
var import_vue26 = require("vue");
|
|
3017
3088
|
function useManifest(options) {
|
|
3018
3089
|
const loader = new ManifestLoader(options);
|
|
@@ -3036,91 +3107,46 @@ function useManifest(options) {
|
|
|
3036
3107
|
manifest.value = null;
|
|
3037
3108
|
await load();
|
|
3038
3109
|
}
|
|
3039
|
-
function clearCache() {
|
|
3040
|
-
loader.clearCache();
|
|
3041
|
-
manifest.value = null;
|
|
3042
|
-
}
|
|
3043
|
-
return { manifest, loading, error, load, reload, clearCache };
|
|
3044
|
-
}
|
|
3045
|
-
|
|
3046
|
-
// src/use-nav.ts
|
|
3047
|
-
var import_vue27 = require("vue");
|
|
3048
|
-
function useNav(manifest, options = {}) {
|
|
3049
|
-
const routes = (0, import_vue27.computed)(() => {
|
|
3050
|
-
if (!manifest.value) return [];
|
|
3051
|
-
return buildRoutes(manifest.value, options);
|
|
3052
|
-
});
|
|
3053
|
-
const sidebar = (0, import_vue27.computed)(() => buildSidebar(routes.value));
|
|
3054
|
-
return { routes, sidebar };
|
|
3055
|
-
}
|
|
3056
|
-
|
|
3057
|
-
// src/use-actions.ts
|
|
3058
|
-
var import_vue28 = require("vue");
|
|
3059
|
-
function useActions(manifest, actions) {
|
|
3060
|
-
const registry = (0, import_vue28.computed)(() => {
|
|
3061
|
-
if (!manifest.value) return null;
|
|
3062
|
-
return new ActionRegistry(manifest.value, actions);
|
|
3063
|
-
});
|
|
3064
|
-
return { registry };
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
// src/use-tenant-action-flow.ts
|
|
3068
|
-
var import_vue30 = require("vue");
|
|
3069
|
-
|
|
3070
|
-
// src/use-super-admin-context.ts
|
|
3071
|
-
var import_vue29 = require("vue");
|
|
3072
|
-
function useSuperAdminExtensions() {
|
|
3073
|
-
return (0, import_vue29.inject)(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
3074
|
-
}
|
|
3075
|
-
function useSuperAdminActions() {
|
|
3076
|
-
return (0, import_vue29.inject)(SUPER_ADMIN_ACTIONS_KEY, {});
|
|
3077
|
-
}
|
|
3078
|
-
function useSuperAdminBrand() {
|
|
3079
|
-
const brand = (0, import_vue29.inject)(SUPER_ADMIN_BRAND_KEY);
|
|
3080
|
-
if (!brand) {
|
|
3081
|
-
throw new Error(
|
|
3082
|
-
"useSuperAdminBrand(): kein SuperAdmin-Branding im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
3083
|
-
);
|
|
3084
|
-
}
|
|
3085
|
-
return brand;
|
|
3086
|
-
}
|
|
3087
|
-
function useSuperAdminEndpoints() {
|
|
3088
|
-
const endpoints = (0, import_vue29.inject)(SUPER_ADMIN_ENDPOINTS_KEY);
|
|
3089
|
-
if (!endpoints) {
|
|
3090
|
-
throw new Error(
|
|
3091
|
-
"useSuperAdminEndpoints(): keine Endpoints im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
3092
|
-
);
|
|
3093
|
-
}
|
|
3094
|
-
return endpoints;
|
|
3095
|
-
}
|
|
3096
|
-
function useSuperAdminManifest() {
|
|
3097
|
-
const accessor = (0, import_vue29.inject)(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
3098
|
-
return accessor ? accessor() : null;
|
|
3099
|
-
}
|
|
3100
|
-
function useSuperAdminLoginAdapter() {
|
|
3101
|
-
const adapter = (0, import_vue29.inject)(SUPER_ADMIN_LOGIN_ADAPTER_KEY);
|
|
3102
|
-
if (!adapter) {
|
|
3103
|
-
throw new Error(
|
|
3104
|
-
"useSuperAdminLoginAdapter(): kein Login-Adapter registriert. Reiche ihn via createSuperAdminApp({ loginAdapter }) ein."
|
|
3105
|
-
);
|
|
3106
|
-
}
|
|
3107
|
-
return adapter;
|
|
3110
|
+
function clearCache() {
|
|
3111
|
+
loader.clearCache();
|
|
3112
|
+
manifest.value = null;
|
|
3113
|
+
}
|
|
3114
|
+
return { manifest, loading, error, load, reload, clearCache };
|
|
3108
3115
|
}
|
|
3109
|
-
|
|
3110
|
-
|
|
3116
|
+
|
|
3117
|
+
// src/vue/use-nav.ts
|
|
3118
|
+
var import_vue27 = require("vue");
|
|
3119
|
+
function useNav(manifest, options = {}) {
|
|
3120
|
+
const routes = (0, import_vue27.computed)(() => {
|
|
3121
|
+
if (!manifest.value) return [];
|
|
3122
|
+
return buildRoutes(manifest.value, options);
|
|
3123
|
+
});
|
|
3124
|
+
const sidebar = (0, import_vue27.computed)(() => buildSidebar(routes.value));
|
|
3125
|
+
return { routes, sidebar };
|
|
3111
3126
|
}
|
|
3112
3127
|
|
|
3113
|
-
// src/use-
|
|
3128
|
+
// src/vue/use-actions.ts
|
|
3129
|
+
var import_vue28 = require("vue");
|
|
3130
|
+
function useActions(manifest, actions) {
|
|
3131
|
+
const registry = (0, import_vue28.computed)(() => {
|
|
3132
|
+
if (!manifest.value) return null;
|
|
3133
|
+
return new ActionRegistry(manifest.value, actions);
|
|
3134
|
+
});
|
|
3135
|
+
return { registry };
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
// src/vue/use-tenant-action-flow.ts
|
|
3139
|
+
var import_vue29 = require("vue");
|
|
3114
3140
|
function useTenantActionFlow(manifest, providers = {}) {
|
|
3115
3141
|
const handlers = useSuperAdminActions();
|
|
3116
|
-
const registry = (0,
|
|
3142
|
+
const registry = (0, import_vue29.computed)(() => {
|
|
3117
3143
|
if (!manifest.value) return null;
|
|
3118
3144
|
return new ActionRegistry(manifest.value, handlers);
|
|
3119
3145
|
});
|
|
3120
|
-
const orphanedDefs = (0,
|
|
3146
|
+
const orphanedDefs = (0, import_vue29.computed)(
|
|
3121
3147
|
() => registry.value ? registry.value.listOrphanedDefs() : []
|
|
3122
3148
|
);
|
|
3123
|
-
const availableActions = (0,
|
|
3149
|
+
const availableActions = (0, import_vue29.computed)(() => {
|
|
3124
3150
|
const m = manifest.value;
|
|
3125
3151
|
const reg = registry.value;
|
|
3126
3152
|
if (!m || !reg) return [];
|
|
@@ -3192,8 +3218,8 @@ async function runFlow(def, row, registry, providers) {
|
|
|
3192
3218
|
}
|
|
3193
3219
|
}
|
|
3194
3220
|
|
|
3195
|
-
// src/use-platform-tenant-actions.ts
|
|
3196
|
-
var
|
|
3221
|
+
// src/vue/use-platform-tenant-actions.ts
|
|
3222
|
+
var import_vue30 = require("vue");
|
|
3197
3223
|
var DEFAULT_VISIBLE_FOR_ROW = (def, row) => {
|
|
3198
3224
|
if (def.actionKey === "tenants.suspend") return row.isActive;
|
|
3199
3225
|
if (def.actionKey === "tenants.reactivate") return !row.isActive;
|
|
@@ -3225,7 +3251,7 @@ function usePlatformTenantActions(options) {
|
|
|
3225
3251
|
const iconForActionKey = options.iconForActionKey ?? DEFAULT_ICON_FOR_ACTION_KEY;
|
|
3226
3252
|
const toneForActionKey = options.toneForActionKey ?? DEFAULT_TONE_FOR_ACTION_KEY;
|
|
3227
3253
|
const visibleForRow = options.visibleForRow ?? DEFAULT_VISIBLE_FOR_ROW;
|
|
3228
|
-
const mfa = (0,
|
|
3254
|
+
const mfa = (0, import_vue30.ref)({ show: false, description: "", error: "" });
|
|
3229
3255
|
let pendingMfaResolve = null;
|
|
3230
3256
|
function showMfaDialog(def, ctx) {
|
|
3231
3257
|
return new Promise((resolve) => {
|
|
@@ -3250,7 +3276,7 @@ function usePlatformTenantActions(options) {
|
|
|
3250
3276
|
pendingMfaResolve(null);
|
|
3251
3277
|
}
|
|
3252
3278
|
}
|
|
3253
|
-
const confirmDialog = (0,
|
|
3279
|
+
const confirmDialog = (0, import_vue30.ref)({
|
|
3254
3280
|
show: false,
|
|
3255
3281
|
def: null,
|
|
3256
3282
|
row: null
|
|
@@ -3292,7 +3318,7 @@ function usePlatformTenantActions(options) {
|
|
|
3292
3318
|
},
|
|
3293
3319
|
visibleForRow
|
|
3294
3320
|
});
|
|
3295
|
-
const manifestActions = (0,
|
|
3321
|
+
const manifestActions = (0, import_vue30.computed)(
|
|
3296
3322
|
() => flow.availableActions.value.map((def) => ({
|
|
3297
3323
|
id: def.id,
|
|
3298
3324
|
label: def.label,
|
|
@@ -3306,7 +3332,7 @@ function usePlatformTenantActions(options) {
|
|
|
3306
3332
|
}
|
|
3307
3333
|
}))
|
|
3308
3334
|
);
|
|
3309
|
-
const realOrphans = (0,
|
|
3335
|
+
const realOrphans = (0, import_vue30.computed)(() => {
|
|
3310
3336
|
const caps = options.manifest.value?.capabilities ?? {};
|
|
3311
3337
|
const defs = options.manifest.value?.tenants?.actions ?? [];
|
|
3312
3338
|
const defByActionKey = new Map(defs.map((d) => [d.actionKey, d]));
|
|
@@ -3314,298 +3340,52 @@ function usePlatformTenantActions(options) {
|
|
|
3314
3340
|
const def = defByActionKey.get(actionKey);
|
|
3315
3341
|
const requiredCap = def?.requiredCapability;
|
|
3316
3342
|
if (!requiredCap) return true;
|
|
3317
|
-
return caps[requiredCap] === true;
|
|
3318
|
-
});
|
|
3319
|
-
});
|
|
3320
|
-
return {
|
|
3321
|
-
manifestActions,
|
|
3322
|
-
realOrphans,
|
|
3323
|
-
mfa,
|
|
3324
|
-
onMfaConfirm,
|
|
3325
|
-
onMfaDialogVisibility,
|
|
3326
|
-
confirmDialog,
|
|
3327
|
-
onConfirmSubmit,
|
|
3328
|
-
onConfirmCancel,
|
|
3329
|
-
onConfirmDialogVisibility
|
|
3330
|
-
};
|
|
3331
|
-
}
|
|
3332
|
-
|
|
3333
|
-
// src/use-batch-columns.ts
|
|
3334
|
-
var import_vue32 = require("vue");
|
|
3335
|
-
function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
3336
|
-
const fetcher = new BatchColumnFetcher(options);
|
|
3337
|
-
const data = (0, import_vue32.ref)({});
|
|
3338
|
-
const loading = (0, import_vue32.ref)(false);
|
|
3339
|
-
const error = (0, import_vue32.ref)(null);
|
|
3340
|
-
async function load() {
|
|
3341
|
-
if (!manifest.value || tenantIds.value.length === 0) {
|
|
3342
|
-
data.value = {};
|
|
3343
|
-
return;
|
|
3344
|
-
}
|
|
3345
|
-
loading.value = true;
|
|
3346
|
-
error.value = null;
|
|
3347
|
-
try {
|
|
3348
|
-
data.value = await fetcher.fetchAll(manifest.value, tenantIds.value);
|
|
3349
|
-
} catch (err) {
|
|
3350
|
-
error.value = err instanceof Error ? err : new Error(String(err));
|
|
3351
|
-
data.value = {};
|
|
3352
|
-
} finally {
|
|
3353
|
-
loading.value = false;
|
|
3354
|
-
}
|
|
3355
|
-
}
|
|
3356
|
-
(0, import_vue32.watch)([manifest, tenantIds], () => {
|
|
3357
|
-
void load();
|
|
3358
|
-
});
|
|
3359
|
-
return { data, loading, error, reload: load };
|
|
3360
|
-
}
|
|
3361
|
-
|
|
3362
|
-
// src/plan-versions-catalog.ts
|
|
3363
|
-
var dec = (s) => Number(s);
|
|
3364
|
-
function extractQuotas(p) {
|
|
3365
|
-
if (p.quotas && Object.keys(p.quotas).length > 0) {
|
|
3366
|
-
return { ...p.quotas };
|
|
3367
|
-
}
|
|
3368
|
-
const out = {};
|
|
3369
|
-
if (typeof p.maxUsers === "number") out.users = p.maxUsers;
|
|
3370
|
-
if (typeof p.maxVehicles === "number") out.vehicles = p.maxVehicles;
|
|
3371
|
-
if (typeof p.maxStorageGb === "number") out.storageGb = p.maxStorageGb;
|
|
3372
|
-
return out;
|
|
3373
|
-
}
|
|
3374
|
-
var sortByPublishedDesc = (rows) => [...rows].sort((a, b) => {
|
|
3375
|
-
const at = a.publishedAt ? Date.parse(a.publishedAt) : Number.POSITIVE_INFINITY;
|
|
3376
|
-
const bt = b.publishedAt ? Date.parse(b.publishedAt) : Number.POSITIVE_INFINITY;
|
|
3377
|
-
if (at !== bt) return bt - at;
|
|
3378
|
-
return b.version - a.version;
|
|
3379
|
-
});
|
|
3380
|
-
function findLiveAt(rows, asOfMs) {
|
|
3381
|
-
const candidates = rows.filter((r) => {
|
|
3382
|
-
if (r.publishedAt === null) return false;
|
|
3383
|
-
if (Date.parse(r.publishedAt) > asOfMs) return false;
|
|
3384
|
-
if (r.supersededAt !== null && Date.parse(r.supersededAt) <= asOfMs) return false;
|
|
3385
|
-
return true;
|
|
3386
|
-
});
|
|
3387
|
-
if (candidates.length === 0) return null;
|
|
3388
|
-
return [...candidates].sort((a, b) => b.version - a.version)[0] ?? null;
|
|
3389
|
-
}
|
|
3390
|
-
function findCurrentLive(rows) {
|
|
3391
|
-
return rows.find((r) => r.publishedAt !== null && r.supersededAt === null) ?? null;
|
|
3392
|
-
}
|
|
3393
|
-
function findDraft(rows) {
|
|
3394
|
-
return rows.find((r) => r.publishedAt === null) ?? null;
|
|
3395
|
-
}
|
|
3396
|
-
function groupBy(rows, keyOf) {
|
|
3397
|
-
const out = /* @__PURE__ */ new Map();
|
|
3398
|
-
for (const r of rows) {
|
|
3399
|
-
const k = keyOf(r);
|
|
3400
|
-
const list = out.get(k) ?? [];
|
|
3401
|
-
list.push(r);
|
|
3402
|
-
out.set(k, list);
|
|
3403
|
-
}
|
|
3404
|
-
return out;
|
|
3405
|
-
}
|
|
3406
|
-
function resolvePlan(source, liveBase) {
|
|
3407
|
-
const quotas = extractQuotas(source);
|
|
3408
|
-
return {
|
|
3409
|
-
source,
|
|
3410
|
-
liveBase,
|
|
3411
|
-
isDraft: source.publishedAt === null,
|
|
3412
|
-
planId: source.planId,
|
|
3413
|
-
features: source.features,
|
|
3414
|
-
quotas,
|
|
3415
|
-
monthlyNet: dec(source.monthlyNet),
|
|
3416
|
-
yearlyNet: dec(source.yearlyNet),
|
|
3417
|
-
marketed: source.marketed,
|
|
3418
|
-
version: source.version,
|
|
3419
|
-
maxUsers: quotas.users,
|
|
3420
|
-
maxVehicles: quotas.vehicles,
|
|
3421
|
-
maxStorageGb: quotas.storageGb
|
|
3422
|
-
};
|
|
3423
|
-
}
|
|
3424
|
-
function dateLabelDe(iso) {
|
|
3425
|
-
return new Date(iso).toLocaleDateString("de-DE", {
|
|
3426
|
-
day: "2-digit",
|
|
3427
|
-
month: "short",
|
|
3428
|
-
year: "numeric"
|
|
3429
|
-
});
|
|
3430
|
-
}
|
|
3431
|
-
function buildDraftsSnapshot(data, sortPlansFn) {
|
|
3432
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3433
|
-
const plans = [];
|
|
3434
|
-
for (const [, rows] of planByKey) {
|
|
3435
|
-
const draft = findDraft(rows);
|
|
3436
|
-
const live = findCurrentLive(rows);
|
|
3437
|
-
if (draft) plans.push(resolvePlan(draft, live));
|
|
3438
|
-
else if (live) plans.push(resolvePlan(live, null));
|
|
3439
|
-
}
|
|
3440
|
-
const draftCount = plans.filter((p) => p.isDraft).length;
|
|
3441
|
-
return {
|
|
3442
|
-
id: "drafts",
|
|
3443
|
-
kind: "drafts",
|
|
3444
|
-
status: "DRAFT",
|
|
3445
|
-
label: "Arbeitsstand",
|
|
3446
|
-
title: draftCount === 0 ? "Keine offenen Drafts" : `${draftCount} offene${draftCount === 1 ? "r" : ""} Draft${draftCount === 1 ? "" : "s"} bereit f\xFCr Publish`,
|
|
3447
|
-
description: draftCount === 0 ? "Lege einen Draft an, um Limits, Preise oder Features zu \xE4ndern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam." : "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.",
|
|
3448
|
-
asOf: null,
|
|
3449
|
-
createdAt: null,
|
|
3450
|
-
publishedAt: null,
|
|
3451
|
-
authorEmail: null,
|
|
3452
|
-
plans: sortPlansFn(plans),
|
|
3453
|
-
draftCount,
|
|
3454
|
-
regressionCount: 0
|
|
3455
|
-
};
|
|
3456
|
-
}
|
|
3457
|
-
function buildActiveSnapshot(data, sortPlansFn) {
|
|
3458
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3459
|
-
const plans = [];
|
|
3460
|
-
for (const [, rows] of planByKey) {
|
|
3461
|
-
const live = findCurrentLive(rows);
|
|
3462
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
3463
|
-
}
|
|
3464
|
-
if (plans.length === 0) return null;
|
|
3465
|
-
const publishedDates = plans.map((p) => p.source.publishedAt).filter((t) => t !== null).sort();
|
|
3466
|
-
const latestPublished = publishedDates[publishedDates.length - 1];
|
|
3467
|
-
return {
|
|
3468
|
-
id: "active",
|
|
3469
|
-
kind: "active",
|
|
3470
|
-
status: "ACTIVE",
|
|
3471
|
-
label: "Aktuell",
|
|
3472
|
-
title: "Live-Catalog",
|
|
3473
|
-
description: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
|
|
3474
|
-
asOf: latestPublished ?? null,
|
|
3475
|
-
createdAt: null,
|
|
3476
|
-
publishedAt: latestPublished ?? null,
|
|
3477
|
-
authorEmail: null,
|
|
3478
|
-
plans: sortPlansFn(plans),
|
|
3479
|
-
draftCount: 0,
|
|
3480
|
-
regressionCount: 0
|
|
3481
|
-
};
|
|
3482
|
-
}
|
|
3483
|
-
function buildHistoricalSnapshots(data, sortPlansFn) {
|
|
3484
|
-
const allPublishedAt = /* @__PURE__ */ new Set();
|
|
3485
|
-
for (const r of data.planVersions) if (r.publishedAt) allPublishedAt.add(r.publishedAt);
|
|
3486
|
-
if (allPublishedAt.size === 0) return [];
|
|
3487
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3488
|
-
const liveTimestamps = /* @__PURE__ */ new Set();
|
|
3489
|
-
for (const rows of planByKey.values()) {
|
|
3490
|
-
const live = findCurrentLive(rows);
|
|
3491
|
-
if (live?.publishedAt) liveTimestamps.add(live.publishedAt);
|
|
3492
|
-
}
|
|
3493
|
-
const liveSorted = [...liveTimestamps].sort();
|
|
3494
|
-
const latestLive = liveSorted[liveSorted.length - 1];
|
|
3495
|
-
const sortedDesc = [...allPublishedAt].sort((a, b) => Date.parse(b) - Date.parse(a));
|
|
3496
|
-
const out = [];
|
|
3497
|
-
for (const ts of sortedDesc) {
|
|
3498
|
-
if (latestLive && Date.parse(ts) >= Date.parse(latestLive)) continue;
|
|
3499
|
-
const tMs = Date.parse(ts) + 1;
|
|
3500
|
-
const plans = [];
|
|
3501
|
-
for (const [, rows] of planByKey) {
|
|
3502
|
-
const live = findLiveAt(rows, tMs);
|
|
3503
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
3504
|
-
}
|
|
3505
|
-
if (plans.length === 0) continue;
|
|
3506
|
-
const publishedAtThisEvent = data.planVersions.filter((r) => r.publishedAt === ts);
|
|
3507
|
-
const regressionCount = publishedAtThisEvent.filter((r) => !r.nonRegressive).length;
|
|
3508
|
-
const author = publishedAtThisEvent[0]?.publishedByUserId ?? null;
|
|
3509
|
-
out.push({
|
|
3510
|
-
id: `hist-${ts}`,
|
|
3511
|
-
kind: "historical",
|
|
3512
|
-
status: "ARCHIVED",
|
|
3513
|
-
label: dateLabelDe(ts),
|
|
3514
|
-
title: summarizeEvent(publishedAtThisEvent),
|
|
3515
|
-
description: detailEvent(publishedAtThisEvent),
|
|
3516
|
-
asOf: ts,
|
|
3517
|
-
createdAt: ts,
|
|
3518
|
-
publishedAt: ts,
|
|
3519
|
-
authorEmail: author,
|
|
3520
|
-
plans: sortPlansFn(plans),
|
|
3521
|
-
draftCount: 0,
|
|
3522
|
-
regressionCount
|
|
3523
|
-
});
|
|
3524
|
-
}
|
|
3525
|
-
return out;
|
|
3526
|
-
}
|
|
3527
|
-
function summarizeEvent(rows) {
|
|
3528
|
-
if (rows.length === 0) return "Publish-Event";
|
|
3529
|
-
if (rows.length === 1) {
|
|
3530
|
-
const r = rows[0];
|
|
3531
|
-
return `${r.planId} v${r.version} publiziert`;
|
|
3532
|
-
}
|
|
3533
|
-
return `${rows.length} Versionen publiziert`;
|
|
3534
|
-
}
|
|
3535
|
-
function detailEvent(rows) {
|
|
3536
|
-
if (rows.length === 0) return "";
|
|
3537
|
-
const note = rows[0]?.changeNote ?? "";
|
|
3538
|
-
return note.length > 0 ? note : "Snapshot rekonstruiert aus per-Entity-Versionen.";
|
|
3539
|
-
}
|
|
3540
|
-
function sortPlansBy(order) {
|
|
3541
|
-
if (!order || order.length === 0) {
|
|
3542
|
-
return (rows) => [...rows].sort((a, b) => a.planId.localeCompare(b.planId));
|
|
3543
|
-
}
|
|
3544
|
-
const idx = {};
|
|
3545
|
-
for (let i = 0; i < order.length; i++) idx[order[i]] = i;
|
|
3546
|
-
return (rows) => [...rows].sort((a, b) => {
|
|
3547
|
-
const ai = idx[a.planId] ?? Number.POSITIVE_INFINITY;
|
|
3548
|
-
const bi = idx[b.planId] ?? Number.POSITIVE_INFINITY;
|
|
3549
|
-
if (ai !== bi) return ai - bi;
|
|
3550
|
-
return a.planId.localeCompare(b.planId);
|
|
3343
|
+
return caps[requiredCap] === true;
|
|
3344
|
+
});
|
|
3551
3345
|
});
|
|
3552
|
-
}
|
|
3553
|
-
function buildSnapshots(data, options = {}) {
|
|
3554
|
-
const sortPlansFn = sortPlansBy(options.planSortOrder);
|
|
3555
|
-
const drafts = buildDraftsSnapshot(data, sortPlansFn);
|
|
3556
|
-
const active = buildActiveSnapshot(data, sortPlansFn);
|
|
3557
|
-
const historical = buildHistoricalSnapshots(data, sortPlansFn);
|
|
3558
|
-
const out = [drafts];
|
|
3559
|
-
if (active) out.push(active);
|
|
3560
|
-
out.push(...historical);
|
|
3561
|
-
return out;
|
|
3562
|
-
}
|
|
3563
|
-
function listOpenDrafts(data) {
|
|
3564
3346
|
return {
|
|
3565
|
-
|
|
3347
|
+
manifestActions,
|
|
3348
|
+
realOrphans,
|
|
3349
|
+
mfa,
|
|
3350
|
+
onMfaConfirm,
|
|
3351
|
+
onMfaDialogVisibility,
|
|
3352
|
+
confirmDialog,
|
|
3353
|
+
onConfirmSubmit,
|
|
3354
|
+
onConfirmCancel,
|
|
3355
|
+
onConfirmDialogVisibility
|
|
3566
3356
|
};
|
|
3567
3357
|
}
|
|
3568
3358
|
|
|
3569
|
-
// src/
|
|
3570
|
-
var
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
}
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
}
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
for (const feature of featureCatalog) {
|
|
3592
|
-
const label = resolveLabel(feature.label, feature.i18n, locale);
|
|
3593
|
-
if (label) registry[feature.featureKey] = { label, core: feature.core };
|
|
3594
|
-
}
|
|
3595
|
-
return registry;
|
|
3596
|
-
}
|
|
3597
|
-
function buildQuotaRegistry(quotaCatalog, locale) {
|
|
3598
|
-
const registry = {};
|
|
3599
|
-
for (const quota of quotaCatalog) {
|
|
3600
|
-
registry[quota.quotaKey] = {
|
|
3601
|
-
label: resolveLabel(quota.label, quota.i18n, locale),
|
|
3602
|
-
unit: localized(quota.i18n, locale, "unit") ?? (quota.unit || void 0)
|
|
3603
|
-
};
|
|
3359
|
+
// src/vue/use-batch-columns.ts
|
|
3360
|
+
var import_vue31 = require("vue");
|
|
3361
|
+
function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
3362
|
+
const fetcher = new BatchColumnFetcher(options);
|
|
3363
|
+
const data = (0, import_vue31.ref)({});
|
|
3364
|
+
const loading = (0, import_vue31.ref)(false);
|
|
3365
|
+
const error = (0, import_vue31.ref)(null);
|
|
3366
|
+
async function load() {
|
|
3367
|
+
if (!manifest.value || tenantIds.value.length === 0) {
|
|
3368
|
+
data.value = {};
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3371
|
+
loading.value = true;
|
|
3372
|
+
error.value = null;
|
|
3373
|
+
try {
|
|
3374
|
+
data.value = await fetcher.fetchAll(manifest.value, tenantIds.value);
|
|
3375
|
+
} catch (err) {
|
|
3376
|
+
error.value = err instanceof Error ? err : new Error(String(err));
|
|
3377
|
+
data.value = {};
|
|
3378
|
+
} finally {
|
|
3379
|
+
loading.value = false;
|
|
3380
|
+
}
|
|
3604
3381
|
}
|
|
3605
|
-
|
|
3382
|
+
(0, import_vue31.watch)([manifest, tenantIds], () => {
|
|
3383
|
+
void load();
|
|
3384
|
+
});
|
|
3385
|
+
return { data, loading, error, reload: load };
|
|
3606
3386
|
}
|
|
3607
3387
|
|
|
3608
|
-
// src/platform-loaders.ts
|
|
3388
|
+
// src/vue/platform-loaders.ts
|
|
3609
3389
|
function resolveEndpoints(endpoints) {
|
|
3610
3390
|
return {
|
|
3611
3391
|
apiBase: endpoints.apiBase,
|
|
@@ -3629,15 +3409,15 @@ function createPlatformLoaders(options) {
|
|
|
3629
3409
|
return { bootLoader, manifestLoader };
|
|
3630
3410
|
}
|
|
3631
3411
|
|
|
3632
|
-
// src/manifest-store-factory.ts
|
|
3633
|
-
var
|
|
3634
|
-
var
|
|
3412
|
+
// src/vue/manifest-store-factory.ts
|
|
3413
|
+
var import_pinia = require("pinia");
|
|
3414
|
+
var import_vue32 = require("vue");
|
|
3635
3415
|
function createManifestStore(options) {
|
|
3636
|
-
return (0,
|
|
3637
|
-
const manifest = (0,
|
|
3638
|
-
const loading = (0,
|
|
3639
|
-
const error = (0,
|
|
3640
|
-
const loaded = (0,
|
|
3416
|
+
return (0, import_pinia.defineStore)(options.id ?? "admin-manifest", () => {
|
|
3417
|
+
const manifest = (0, import_vue32.ref)(null);
|
|
3418
|
+
const loading = (0, import_vue32.ref)(false);
|
|
3419
|
+
const error = (0, import_vue32.ref)(null);
|
|
3420
|
+
const loaded = (0, import_vue32.ref)(false);
|
|
3641
3421
|
let inflight = null;
|
|
3642
3422
|
async function load() {
|
|
3643
3423
|
loading.value = true;
|
|
@@ -3675,6 +3455,179 @@ function createManifestStore(options) {
|
|
|
3675
3455
|
return { manifest, loading, error, loaded, ensureLoaded, clearCache, reload };
|
|
3676
3456
|
});
|
|
3677
3457
|
}
|
|
3458
|
+
|
|
3459
|
+
// src/components/dialogs/types.ts
|
|
3460
|
+
var DEFAULT_PILOT_COPY = {
|
|
3461
|
+
tenantSubtitle: "Stammdaten des Mandanten",
|
|
3462
|
+
tenantNameLabel: "Name des Mandanten",
|
|
3463
|
+
tenantNamePlaceholder: "z. B. Muster GmbH",
|
|
3464
|
+
slugPlaceholder: "muster-mandant",
|
|
3465
|
+
adminEmailPlaceholder: "admin@example.com",
|
|
3466
|
+
notePlaceholder: "z. B. Sales-Pilot \xB7 Demo-Zugang"
|
|
3467
|
+
};
|
|
3468
|
+
|
|
3469
|
+
// src/components/bundle-editor/catalog-i18n.ts
|
|
3470
|
+
var CATALOG_DEFAULT_LOCALE = "de";
|
|
3471
|
+
function localized(i18n, locale, field) {
|
|
3472
|
+
if (locale === CATALOG_DEFAULT_LOCALE) return void 0;
|
|
3473
|
+
const value = i18n?.[locale]?.[field];
|
|
3474
|
+
return value && value.trim().length > 0 ? value : void 0;
|
|
3475
|
+
}
|
|
3476
|
+
function resolveLabel(baseLabel, i18n, locale) {
|
|
3477
|
+
return localized(i18n, locale, "label") ?? (baseLabel || void 0);
|
|
3478
|
+
}
|
|
3479
|
+
function buildFeatureRegistry(featureCatalog, locale) {
|
|
3480
|
+
const registry = {};
|
|
3481
|
+
for (const feature of featureCatalog) {
|
|
3482
|
+
const label = resolveLabel(feature.label, feature.i18n, locale);
|
|
3483
|
+
if (label) registry[feature.featureKey] = { label, core: feature.core };
|
|
3484
|
+
}
|
|
3485
|
+
return registry;
|
|
3486
|
+
}
|
|
3487
|
+
function buildQuotaRegistry(quotaCatalog, locale) {
|
|
3488
|
+
const registry = {};
|
|
3489
|
+
for (const quota of quotaCatalog) {
|
|
3490
|
+
registry[quota.quotaKey] = {
|
|
3491
|
+
label: resolveLabel(quota.label, quota.i18n, locale),
|
|
3492
|
+
unit: localized(quota.i18n, locale, "unit") ?? (quota.unit || void 0)
|
|
3493
|
+
};
|
|
3494
|
+
}
|
|
3495
|
+
return registry;
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// src/pages-tenant/default-i18n.ts
|
|
3499
|
+
var DEFAULT_I18N_DE = {
|
|
3500
|
+
sectionTitle: "Paket & Verbrauch",
|
|
3501
|
+
sectionSubtitle: "Aktuelles Paket, Verbrauch und Bundles.",
|
|
3502
|
+
loading: "Lade \u2026",
|
|
3503
|
+
noSubscription: "Keine Subscription f\xFCr diesen Mandanten gefunden.",
|
|
3504
|
+
activePlan: "Aktuelles Paket",
|
|
3505
|
+
cycleMonthly: "Monatlich",
|
|
3506
|
+
cycleYearly: "J\xE4hrlich",
|
|
3507
|
+
statusActive: "Aktiv",
|
|
3508
|
+
statusTrial: "Testphase",
|
|
3509
|
+
statusPastDue: "Zahlung \xFCberf\xE4llig",
|
|
3510
|
+
statusCanceled: "Gek\xFCndigt",
|
|
3511
|
+
statusPendingSales: "Vertrieb-Kl\xE4rung",
|
|
3512
|
+
trialEndsAt: "Testphase endet am",
|
|
3513
|
+
pilotEndsAt: "Pilot endet am",
|
|
3514
|
+
nextBillingDate: "N\xE4chste Abrechnung",
|
|
3515
|
+
pendingChange: "Ausstehender Plan-Wechsel",
|
|
3516
|
+
changeFromTo: "Wechsel zu",
|
|
3517
|
+
changeEffectiveAt: "wirksam ab",
|
|
3518
|
+
changePlanButton: "Paket wechseln",
|
|
3519
|
+
cancelSubscriptionButton: "Abonnement k\xFCndigen",
|
|
3520
|
+
usageTitle: "Verbrauch",
|
|
3521
|
+
featuresOverviewTitle: "Leistungsumfang",
|
|
3522
|
+
featuresActive: "Enthalten",
|
|
3523
|
+
featuresLocked: "Nicht enthalten",
|
|
3524
|
+
bundlesStoreTitle: "Bundles",
|
|
3525
|
+
bundlesBookedTitle: "Gebuchte Bundles",
|
|
3526
|
+
bundlesAvailableTitle: "Verf\xFCgbare Bundles",
|
|
3527
|
+
bundlesAvailableEmpty: "Aktuell sind keine zus\xE4tzlichen Bundles verf\xFCgbar.",
|
|
3528
|
+
bundlesPerMonth: "netto/Monat",
|
|
3529
|
+
bundleBookAction: "Bundle buchen",
|
|
3530
|
+
bundleBookInProgress: "Buchung l\xE4uft \u2026",
|
|
3531
|
+
bundleCancelAction: "K\xFCndigen",
|
|
3532
|
+
bundleReactivateAction: "Reaktivieren",
|
|
3533
|
+
bundleReactivateConfirmTitle: "Bundle reaktivieren",
|
|
3534
|
+
bundleReactivateConfirmBody: "Die K\xFCndigung wird r\xFCckg\xE4ngig gemacht. Das Bundle bleibt gebucht, l\xE4uft regul\xE4r weiter und wird wieder abgerechnet.",
|
|
3535
|
+
bundleCanceledAt: "Gek\xFCndigt zum",
|
|
3536
|
+
bundleMinimumTermUntil: "Mindestlaufzeit bis",
|
|
3537
|
+
bundleIncludesLabel: "Enth\xE4lt",
|
|
3538
|
+
bundleAlreadyBooked: "Bereits gebucht",
|
|
3539
|
+
bundleIncompatible: "Nicht kompatibel mit aktuellem Paket",
|
|
3540
|
+
bundleMissingRequires: "Ben\xF6tigt",
|
|
3541
|
+
bundlePreviewAddTitle: "Bundle buchen",
|
|
3542
|
+
bundlePreviewCancelTitle: "Bundle k\xFCndigen",
|
|
3543
|
+
bundlePreviewLoading: "Vorschau wird berechnet \u2026",
|
|
3544
|
+
bundlePreviewProrationTitle: "Anteilige Abrechnung",
|
|
3545
|
+
bundlePreviewProratedNow: "Heute anteilig f\xE4llig",
|
|
3546
|
+
bundlePreviewProrationDays: "Tage",
|
|
3547
|
+
bundlePreviewNextPeriod: "Regul\xE4r ab n\xE4chster Periode",
|
|
3548
|
+
bundlePreviewTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an \u2014 die Abrechnung beginnt mit der ersten bezahlten Periode.",
|
|
3549
|
+
bundlePreviewNoPrice: "F\xFCr den aktuellen Abrechnungszyklus ist kein Listenpreis gepflegt.",
|
|
3550
|
+
bundlePreviewMinimumTermLabel: "Mindestlaufzeit",
|
|
3551
|
+
bundlePreviewMinimumTermMonths: "Monate, bis",
|
|
3552
|
+
bundlePreviewMinimumTermNone: "Keine Mindestlaufzeit",
|
|
3553
|
+
bundlePreviewRedundantTitle: "Bereits enthaltene Features (w\xFCrden doppelt bezahlt)",
|
|
3554
|
+
bundlePreviewRedundantCoveredByPlan: "bereits im Plan",
|
|
3555
|
+
bundlePreviewRedundantCoveredByBundle: "bereits im Bundle",
|
|
3556
|
+
bundlePreviewMissingRequiresTitle: "Fehlende Voraussetzungen",
|
|
3557
|
+
bundlePreviewBlockersTitle: "Buchung nicht m\xF6glich",
|
|
3558
|
+
bundlePreviewWarningsTitle: "Hinweise",
|
|
3559
|
+
bundlePreviewEffectiveAt: "K\xFCndigung wirksam zum",
|
|
3560
|
+
bundlePreviewSavings: "Ersparnis pro Periode ab Wirksamkeit",
|
|
3561
|
+
bundlePreviewConfirmAdd: "Kostenpflichtig buchen",
|
|
3562
|
+
bundlePreviewConfirmCancel: "K\xFCndigung best\xE4tigen",
|
|
3563
|
+
bundlePreviewInProgress: "Wird ausgef\xFChrt \u2026",
|
|
3564
|
+
bundlePreviewClose: "Abbrechen",
|
|
3565
|
+
pendingVersionTitle: "Anstehende Plan-\xC4nderung",
|
|
3566
|
+
pendingVersionChipNonRegressive: "Verbessernd",
|
|
3567
|
+
pendingVersionChipRegressive: "Best\xE4tigung erforderlich",
|
|
3568
|
+
pendingVersionEffectiveAt: "Wirksam ab",
|
|
3569
|
+
pendingVersionAcceptAction: "\xC4nderungen akzeptieren",
|
|
3570
|
+
pendingVersionAcceptInProgress: "Akzeptiere \u2026",
|
|
3571
|
+
pendingVersionAcceptedAt: "Akzeptiert am",
|
|
3572
|
+
wizardTitle: "Paket wechseln",
|
|
3573
|
+
wizardClose: "Schlie\xDFen",
|
|
3574
|
+
wizardCurrent: "Aktuell",
|
|
3575
|
+
wizardBadgeCurrent: "aktiv",
|
|
3576
|
+
wizardBadgePopular: "beliebt",
|
|
3577
|
+
wizardPriceUnitMonthly: "netto/Monat",
|
|
3578
|
+
wizardPriceUnitYearly: "netto/Jahr",
|
|
3579
|
+
wizardPriceOnRequest: "auf Anfrage",
|
|
3580
|
+
wizardStepChoose: "Paket w\xE4hlen",
|
|
3581
|
+
wizardStepChooseIntro: "W\xE4hle dein Ziel-Paket und den Abrechnungszyklus. Im n\xE4chsten Schritt zeigen wir Verbrauchs-Check und Feature-Diff.",
|
|
3582
|
+
wizardStepPreview: "Vorschau",
|
|
3583
|
+
wizardStepConfirm: "Best\xE4tigen",
|
|
3584
|
+
wizardNext: "Weiter",
|
|
3585
|
+
wizardBack: "Zur\xFCck",
|
|
3586
|
+
wizardPreviewLoading: "Vorschau wird berechnet \u2026",
|
|
3587
|
+
wizardEffectiveAtLabel: "Wirksam ab",
|
|
3588
|
+
wizardEffectiveImmediate: "Wirksam sofort",
|
|
3589
|
+
wizardProrationTitle: "Anteilige Abrechnung",
|
|
3590
|
+
wizardProrationLine: "Mehrbetrag bis Periodenende:",
|
|
3591
|
+
wizardProrationDays: "Tage",
|
|
3592
|
+
wizardLimitsTitle: "Limit-Vergleich",
|
|
3593
|
+
wizardLimitsUsed: "Verbrauch",
|
|
3594
|
+
wizardLimitsCurrent: "Aktuell",
|
|
3595
|
+
wizardLimitsTarget: "Ziel",
|
|
3596
|
+
wizardFeaturesGained: "Neu freigeschaltet",
|
|
3597
|
+
wizardFeaturesLost: "Wegfallende Features",
|
|
3598
|
+
wizardBlockersTitle: "Verhinderungs-Gr\xFCnde",
|
|
3599
|
+
wizardConfirmImmediate: "Der Wechsel wird sofort wirksam.",
|
|
3600
|
+
wizardConfirmScheduled: "Der Wechsel wird wirksam zum",
|
|
3601
|
+
wizardConfirmAction: "Wechsel best\xE4tigen",
|
|
3602
|
+
wizardConfirmInProgress: "Wechsel l\xE4uft \u2026",
|
|
3603
|
+
wizardConfirmPriceTitle: "Preis\xFCbersicht",
|
|
3604
|
+
wizardConfirmProratedNow: "Heute anteilig f\xE4llig",
|
|
3605
|
+
wizardConfirmRecurringNext: "Regul\xE4r ab n\xE4chster Periode",
|
|
3606
|
+
wizardConfirmRecurringFrom: "Regul\xE4r f\xE4llig ab",
|
|
3607
|
+
wizardConfirmPerCycleMonthly: "pro Monat",
|
|
3608
|
+
wizardConfirmPerCycleYearly: "pro Jahr",
|
|
3609
|
+
wizardConfirmTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an.",
|
|
3610
|
+
wizardConfirmRecurringTrialEnd: "Regul\xE4r ab Ende der Testphase",
|
|
3611
|
+
wizardChangeTypeUpgrade: "Upgrade",
|
|
3612
|
+
wizardChangeTypeDowngrade: "Downgrade",
|
|
3613
|
+
wizardChangeTypeCycle: "Zyklus-Wechsel",
|
|
3614
|
+
wizardChangeTypeNoop: "Keine \xC4nderung",
|
|
3615
|
+
packageSnapshotTitle: "Gebuchtes Paket (Snapshot)",
|
|
3616
|
+
packageSnapshotSubtitle: "Schreibgesch\xFCtzte Kopie des Pakets, wie es beim Abschluss vermarktet wurde.",
|
|
3617
|
+
packageSnapshotCapturedAt: "Erfasst am",
|
|
3618
|
+
packageSnapshotOfferRef: "Angebots-Referenz",
|
|
3619
|
+
packageSnapshotPlanLabel: "Plan",
|
|
3620
|
+
packageSnapshotPlanVersionLabel: "Plan-Version",
|
|
3621
|
+
packageSnapshotCycleLabel: "Abrechnungszyklus",
|
|
3622
|
+
packageSnapshotBundlesLabel: "Enthaltene Bundles",
|
|
3623
|
+
packageSnapshotBundlesEmpty: "Keine Bundles im Paket.",
|
|
3624
|
+
packageSnapshotPriceMonthly: "Preis monatlich",
|
|
3625
|
+
packageSnapshotPriceYearly: "Preis j\xE4hrlich",
|
|
3626
|
+
packageSnapshotPriceTotal: "Gesamtpreis",
|
|
3627
|
+
packageSnapshotNone: "Diese Subscription wurde nicht \xFCber ein Webseiten-Angebot abgeschlossen.",
|
|
3628
|
+
packageSnapshotShowRaw: "Rohdaten anzeigen",
|
|
3629
|
+
packageSnapshotHideRaw: "Rohdaten ausblenden"
|
|
3630
|
+
};
|
|
3678
3631
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3679
3632
|
0 && (module.exports = {
|
|
3680
3633
|
ADMIN_UI_VERSION,
|
|
@@ -3711,6 +3664,7 @@ function createManifestStore(options) {
|
|
|
3711
3664
|
SUPER_ADMIN_HTTP_KEY,
|
|
3712
3665
|
SUPER_ADMIN_LOGIN_ADAPTER_KEY,
|
|
3713
3666
|
SUPER_ADMIN_MANIFEST_KEY,
|
|
3667
|
+
SUPER_ADMIN_NOTIFY_KEY,
|
|
3714
3668
|
TenantSubscriptionBundlesApiError,
|
|
3715
3669
|
buildFeatureRegistry,
|
|
3716
3670
|
buildFeatureRouterGuard,
|
|
@@ -3723,7 +3677,6 @@ function createManifestStore(options) {
|
|
|
3723
3677
|
createManifestStore,
|
|
3724
3678
|
createPlatformLoaders,
|
|
3725
3679
|
createProjectPageHostRoute,
|
|
3726
|
-
createSuperAdminApp,
|
|
3727
3680
|
defaultHttpClient,
|
|
3728
3681
|
defaultIconForActionKey,
|
|
3729
3682
|
defaultKvStore,
|