@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.js
CHANGED
|
@@ -1,174 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ADMIN_UI_VERSION,
|
|
3
|
+
ActionDefNotInManifestError,
|
|
4
|
+
ActionRegistry,
|
|
5
|
+
BatchColumnDriftError,
|
|
6
|
+
BatchColumnFetcher,
|
|
7
|
+
BootLoadError,
|
|
8
|
+
BootLoader,
|
|
9
|
+
DEFAULT_SECTION_ORDER,
|
|
10
|
+
DEFAULT_STANDARD_PAGE_ROUTES,
|
|
11
|
+
HttpJsonError,
|
|
12
|
+
ManifestLoadError,
|
|
13
|
+
ManifestLoader,
|
|
14
|
+
MissingHandlerError,
|
|
15
|
+
buildRoutes,
|
|
16
|
+
buildSidebar,
|
|
17
|
+
buildSnapshots,
|
|
18
|
+
getJson,
|
|
19
|
+
listOpenDrafts,
|
|
20
|
+
postJson,
|
|
21
|
+
resolveExtension,
|
|
22
|
+
trimTrailingSlashes
|
|
23
|
+
} from "./chunk-EH7TOD4H.js";
|
|
24
|
+
import {
|
|
25
|
+
SUPER_ADMIN_ACTIONS_KEY,
|
|
26
|
+
SUPER_ADMIN_BRAND_KEY,
|
|
27
|
+
SUPER_ADMIN_ENDPOINTS_KEY,
|
|
28
|
+
SUPER_ADMIN_EXTENSIONS_KEY,
|
|
29
|
+
SUPER_ADMIN_HTTP_KEY,
|
|
30
|
+
SUPER_ADMIN_LOGIN_ADAPTER_KEY,
|
|
31
|
+
SUPER_ADMIN_MANIFEST_KEY,
|
|
32
|
+
SUPER_ADMIN_NOTIFY_KEY,
|
|
33
|
+
buildNavigationGuard
|
|
34
|
+
} from "./chunk-3YP2ZAOD.js";
|
|
35
|
+
import {
|
|
36
|
+
defaultHttpClient,
|
|
37
|
+
defaultKvStore
|
|
38
|
+
} from "./chunk-LVGUSD3T.js";
|
|
3
39
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
get: () => null,
|
|
9
|
-
set: () => {
|
|
10
|
-
},
|
|
11
|
-
remove: () => {
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
const ls = globalThis.localStorage;
|
|
16
|
-
return {
|
|
17
|
-
get: (k) => ls.getItem(k),
|
|
18
|
-
set: (k, v) => ls.setItem(k, v),
|
|
19
|
-
remove: (k) => ls.removeItem(k)
|
|
20
|
-
};
|
|
40
|
+
// src/vue/use-super-admin-context.ts
|
|
41
|
+
import { inject } from "vue";
|
|
42
|
+
function useSuperAdminExtensions() {
|
|
43
|
+
return inject(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
21
44
|
}
|
|
22
|
-
function
|
|
23
|
-
return (
|
|
45
|
+
function useSuperAdminActions() {
|
|
46
|
+
return inject(SUPER_ADMIN_ACTIONS_KEY, {});
|
|
24
47
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.code = code;
|
|
32
|
-
this.name = "HttpJsonError";
|
|
33
|
-
}
|
|
34
|
-
status;
|
|
35
|
-
code;
|
|
36
|
-
};
|
|
37
|
-
async function extractCode(res) {
|
|
38
|
-
try {
|
|
39
|
-
const body = await res.json();
|
|
40
|
-
return typeof body?.code === "string" ? body.code : void 0;
|
|
41
|
-
} catch {
|
|
42
|
-
return void 0;
|
|
48
|
+
function useSuperAdminBrand() {
|
|
49
|
+
const brand = inject(SUPER_ADMIN_BRAND_KEY);
|
|
50
|
+
if (!brand) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
"useSuperAdminBrand(): kein SuperAdmin-Branding im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
53
|
+
);
|
|
43
54
|
}
|
|
55
|
+
return brand;
|
|
44
56
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const res = await http(url);
|
|
52
|
-
if (res.status < 200 || res.status >= 300) {
|
|
53
|
-
throw new HttpJsonError(res.status, await extractCode(res));
|
|
57
|
+
function useSuperAdminEndpoints() {
|
|
58
|
+
const endpoints = inject(SUPER_ADMIN_ENDPOINTS_KEY);
|
|
59
|
+
if (!endpoints) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"useSuperAdminEndpoints(): keine Endpoints im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
62
|
+
);
|
|
54
63
|
}
|
|
55
|
-
return
|
|
64
|
+
return endpoints;
|
|
56
65
|
}
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
headers: { "Content-Type": "application/json" },
|
|
61
|
-
body: JSON.stringify(body)
|
|
62
|
-
});
|
|
63
|
-
if (res.status < 200 || res.status >= 300) {
|
|
64
|
-
throw new HttpJsonError(res.status, await extractCode(res));
|
|
65
|
-
}
|
|
66
|
-
return await res.json();
|
|
66
|
+
function useSuperAdminManifest() {
|
|
67
|
+
const accessor = inject(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
68
|
+
return accessor ? accessor() : null;
|
|
67
69
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
import { createApp } from "vue";
|
|
75
|
-
import { Quasar, Notify, Dialog, Loading } from "quasar";
|
|
76
|
-
import { createPinia } from "pinia";
|
|
77
|
-
import {
|
|
78
|
-
createRouter,
|
|
79
|
-
createWebHistory
|
|
80
|
-
} from "vue-router";
|
|
81
|
-
var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
|
|
82
|
-
"@saasicat/ui-vue/SUPER_ADMIN_BRAND"
|
|
83
|
-
);
|
|
84
|
-
var SUPER_ADMIN_ENDPOINTS_KEY = /* @__PURE__ */ Symbol.for(
|
|
85
|
-
"@saasicat/ui-vue/SUPER_ADMIN_ENDPOINTS"
|
|
86
|
-
);
|
|
87
|
-
var SUPER_ADMIN_EXTENSIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
88
|
-
"@saasicat/ui-vue/SUPER_ADMIN_EXTENSIONS"
|
|
89
|
-
);
|
|
90
|
-
var SUPER_ADMIN_ACTIONS_KEY = /* @__PURE__ */ Symbol.for(
|
|
91
|
-
"@saasicat/ui-vue/SUPER_ADMIN_ACTIONS"
|
|
92
|
-
);
|
|
93
|
-
var SUPER_ADMIN_MANIFEST_KEY = /* @__PURE__ */ Symbol.for(
|
|
94
|
-
"@saasicat/ui-vue/SUPER_ADMIN_MANIFEST"
|
|
95
|
-
);
|
|
96
|
-
var SUPER_ADMIN_LOGIN_ADAPTER_KEY = /* @__PURE__ */ Symbol.for(
|
|
97
|
-
"@saasicat/ui-vue/SUPER_ADMIN_LOGIN_ADAPTER"
|
|
98
|
-
);
|
|
99
|
-
var SUPER_ADMIN_HTTP_KEY = /* @__PURE__ */ Symbol.for(
|
|
100
|
-
"@saasicat/ui-vue/SUPER_ADMIN_HTTP"
|
|
101
|
-
);
|
|
102
|
-
var DEFAULT_QUASAR_OPTIONS = {
|
|
103
|
-
plugins: { Notify, Dialog, Loading },
|
|
104
|
-
config: { notify: { position: "top-right", timeout: 3e3 } }
|
|
105
|
-
};
|
|
106
|
-
function createSuperAdminApp(options) {
|
|
107
|
-
const app = createApp(options.rootComponent);
|
|
108
|
-
app.use(Quasar, options.quasarOptions ?? DEFAULT_QUASAR_OPTIONS);
|
|
109
|
-
const pinia = createPinia();
|
|
110
|
-
app.use(pinia);
|
|
111
|
-
const router = createRouter({
|
|
112
|
-
history: options.routerHistory ?? createWebHistory(),
|
|
113
|
-
routes: options.appRoutes
|
|
114
|
-
});
|
|
115
|
-
const navGuard = buildNavigationGuard(options);
|
|
116
|
-
if (navGuard) {
|
|
117
|
-
router.beforeEach(navGuard);
|
|
118
|
-
}
|
|
119
|
-
app.use(router);
|
|
120
|
-
const endpoints = {
|
|
121
|
-
apiBase: options.endpoints.apiBase,
|
|
122
|
-
publicBootEndpoint: options.endpoints.publicBootEndpoint ?? `${options.endpoints.apiBase}/boot`,
|
|
123
|
-
manifestEndpoint: options.endpoints.manifestEndpoint ?? `${options.endpoints.apiBase}/manifest`
|
|
124
|
-
};
|
|
125
|
-
app.provide(SUPER_ADMIN_BRAND_KEY, { tag: "SuperAdmin", ...options.brand });
|
|
126
|
-
app.provide(SUPER_ADMIN_ENDPOINTS_KEY, endpoints);
|
|
127
|
-
app.provide(SUPER_ADMIN_EXTENSIONS_KEY, options.extensions ?? {});
|
|
128
|
-
app.provide(SUPER_ADMIN_ACTIONS_KEY, options.actions ?? {});
|
|
129
|
-
if (options.manifestGuard?.getManifest) {
|
|
130
|
-
app.provide(SUPER_ADMIN_MANIFEST_KEY, options.manifestGuard.getManifest);
|
|
131
|
-
}
|
|
132
|
-
if (options.loginAdapter) {
|
|
133
|
-
app.provide(SUPER_ADMIN_LOGIN_ADAPTER_KEY, options.loginAdapter);
|
|
134
|
-
}
|
|
135
|
-
app.provide(SUPER_ADMIN_HTTP_KEY, options.http ?? defaultHttpClient());
|
|
136
|
-
for (const plugin of options.installPlugins ?? []) {
|
|
137
|
-
plugin(app);
|
|
70
|
+
function useSuperAdminLoginAdapter() {
|
|
71
|
+
const adapter = inject(SUPER_ADMIN_LOGIN_ADAPTER_KEY);
|
|
72
|
+
if (!adapter) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
"useSuperAdminLoginAdapter(): kein Login-Adapter registriert. Reiche ihn via createSuperAdminApp({ loginAdapter }) ein."
|
|
75
|
+
);
|
|
138
76
|
}
|
|
139
|
-
return
|
|
140
|
-
app,
|
|
141
|
-
router,
|
|
142
|
-
pinia,
|
|
143
|
-
mount: (selector) => app.mount(selector)
|
|
144
|
-
};
|
|
77
|
+
return adapter;
|
|
145
78
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
if (!authGuard && !manifestGuard) return null;
|
|
149
|
-
return async (to) => {
|
|
150
|
-
if (to.meta?.public === true) return true;
|
|
151
|
-
if (authGuard) {
|
|
152
|
-
if (!authGuard.isAuthenticated()) return authGuard.onUnauthenticated();
|
|
153
|
-
if (authGuard.isSuperAdmin && !authGuard.isSuperAdmin()) {
|
|
154
|
-
return authGuard.onUnauthenticated();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (manifestGuard) {
|
|
158
|
-
try {
|
|
159
|
-
await manifestGuard.ensureLoaded();
|
|
160
|
-
} catch (err) {
|
|
161
|
-
if (manifestGuard.errorRoute && to.path !== manifestGuard.errorRoute) {
|
|
162
|
-
return manifestGuard.errorRoute;
|
|
163
|
-
}
|
|
164
|
-
console.error("[SuperAdmin] manifest load failed", err);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return true;
|
|
168
|
-
};
|
|
79
|
+
function useSuperAdminHttp() {
|
|
80
|
+
return inject(SUPER_ADMIN_HTTP_KEY, defaultHttpClient());
|
|
169
81
|
}
|
|
170
82
|
|
|
171
|
-
// src/project-page-host.ts
|
|
83
|
+
// src/vue/project-page-host.ts
|
|
84
|
+
import { computed, defineAsyncComponent, defineComponent, h, inject as inject2 } from "vue";
|
|
85
|
+
import { useRoute } from "vue-router";
|
|
172
86
|
var asyncComponentCache = /* @__PURE__ */ new WeakMap();
|
|
173
87
|
function resolveAsync(extensions, key) {
|
|
174
88
|
let bucket = asyncComponentCache.get(extensions);
|
|
@@ -188,8 +102,8 @@ var ProjectPageHost = defineComponent({
|
|
|
188
102
|
name: "ProjectPageHost",
|
|
189
103
|
setup() {
|
|
190
104
|
const route = useRoute();
|
|
191
|
-
const extensions =
|
|
192
|
-
const manifestAccessor =
|
|
105
|
+
const extensions = inject2(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
106
|
+
const manifestAccessor = inject2(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
193
107
|
const matchingPage = computed(() => {
|
|
194
108
|
const manifest = manifestAccessor ? manifestAccessor() : null;
|
|
195
109
|
if (!manifest) return null;
|
|
@@ -223,7 +137,7 @@ function createProjectPageHostRoute(options) {
|
|
|
223
137
|
};
|
|
224
138
|
}
|
|
225
139
|
|
|
226
|
-
// src/create-admin-routes.ts
|
|
140
|
+
// src/vue/create-admin-routes.ts
|
|
227
141
|
function createAdminRoutes(options) {
|
|
228
142
|
return [
|
|
229
143
|
{
|
|
@@ -257,444 +171,7 @@ function createAdminRoutes(options) {
|
|
|
257
171
|
];
|
|
258
172
|
}
|
|
259
173
|
|
|
260
|
-
// src/
|
|
261
|
-
var BootLoadError = class extends Error {
|
|
262
|
-
constructor(status, message) {
|
|
263
|
-
super(message);
|
|
264
|
-
this.status = status;
|
|
265
|
-
this.name = "BootLoadError";
|
|
266
|
-
}
|
|
267
|
-
status;
|
|
268
|
-
};
|
|
269
|
-
var BootLoader = class {
|
|
270
|
-
endpoint;
|
|
271
|
-
http;
|
|
272
|
-
constructor(options) {
|
|
273
|
-
if (!options?.endpoint) {
|
|
274
|
-
throw new Error(
|
|
275
|
-
'BootLoader: `endpoint` ist Pflicht (z. B. "/api/admin/boot" oder "/api/v1/admin/boot"). Plattform hat keinen Default, weil Apps unterschiedliche globalPrefix-Konventionen haben.'
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
this.endpoint = options.endpoint;
|
|
279
|
-
this.http = options.http ?? defaultHttpClient();
|
|
280
|
-
}
|
|
281
|
-
async load() {
|
|
282
|
-
const res = await this.http(this.endpoint);
|
|
283
|
-
if (res.status !== 200) {
|
|
284
|
-
throw new BootLoadError(res.status, `Boot-Endpunkt antwortete HTTP ${res.status}`);
|
|
285
|
-
}
|
|
286
|
-
return await res.json();
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// src/manifest-loader.ts
|
|
291
|
-
var ManifestLoadError = class extends Error {
|
|
292
|
-
constructor(status, message) {
|
|
293
|
-
super(message);
|
|
294
|
-
this.status = status;
|
|
295
|
-
this.name = "ManifestLoadError";
|
|
296
|
-
}
|
|
297
|
-
status;
|
|
298
|
-
};
|
|
299
|
-
var ManifestLoader = class {
|
|
300
|
-
endpoint;
|
|
301
|
-
http;
|
|
302
|
-
storage;
|
|
303
|
-
bodyKey;
|
|
304
|
-
etagKey;
|
|
305
|
-
getAuthToken;
|
|
306
|
-
constructor(options) {
|
|
307
|
-
if (!options?.endpoint) {
|
|
308
|
-
throw new Error(
|
|
309
|
-
'ManifestLoader: `endpoint` ist Pflicht (z. B. "/api/admin/manifest" oder "/api/v1/admin/manifest"). Plattform hat keinen Default, weil Apps unterschiedliche globalPrefix-Konventionen haben.'
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
this.endpoint = options.endpoint;
|
|
313
|
-
this.http = options.http ?? defaultHttpClient();
|
|
314
|
-
this.storage = options.storage ?? defaultKvStore();
|
|
315
|
-
const prefix = options.storageKeyPrefix ?? "";
|
|
316
|
-
this.bodyKey = `${prefix}manifest:body`;
|
|
317
|
-
this.etagKey = `${prefix}manifest:etag`;
|
|
318
|
-
this.getAuthToken = options.getAuthToken;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Loads the current manifest. On a cache hit (304) the cached
|
|
322
|
-
* body is returned — otherwise the fresh server body.
|
|
323
|
-
*/
|
|
324
|
-
async load() {
|
|
325
|
-
const cachedEtag = this.storage.get(this.etagKey);
|
|
326
|
-
const headers = {};
|
|
327
|
-
const token = this.getAuthToken?.();
|
|
328
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
329
|
-
if (cachedEtag) headers["If-None-Match"] = cachedEtag;
|
|
330
|
-
const res = await this.http(this.endpoint, { method: "GET", headers });
|
|
331
|
-
if (res.status === 304) {
|
|
332
|
-
const cachedBody = this.readCachedBody();
|
|
333
|
-
if (!cachedBody) {
|
|
334
|
-
throw new ManifestLoadError(
|
|
335
|
-
304,
|
|
336
|
-
"Server lieferte 304, aber Cache-Body fehlt \u2014 bitte clearCache() + reload"
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
return cachedBody.body;
|
|
340
|
-
}
|
|
341
|
-
if (res.status !== 200) {
|
|
342
|
-
throw new ManifestLoadError(
|
|
343
|
-
res.status,
|
|
344
|
-
`Manifest-Endpunkt antwortete HTTP ${res.status}`
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
const body = await res.json();
|
|
348
|
-
const etag = res.headers.get("ETag") ?? res.headers.get("etag");
|
|
349
|
-
if (etag) {
|
|
350
|
-
this.storage.set(this.etagKey, etag);
|
|
351
|
-
this.storage.set(this.bodyKey, JSON.stringify(body));
|
|
352
|
-
}
|
|
353
|
-
return body;
|
|
354
|
-
}
|
|
355
|
-
/** Reads the cached manifest body from storage; null if absent. */
|
|
356
|
-
readCachedBody() {
|
|
357
|
-
const etag = this.storage.get(this.etagKey);
|
|
358
|
-
const bodyStr = this.storage.get(this.bodyKey);
|
|
359
|
-
if (!etag || !bodyStr) return null;
|
|
360
|
-
try {
|
|
361
|
-
return { etag, body: JSON.parse(bodyStr) };
|
|
362
|
-
} catch {
|
|
363
|
-
return null;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
/** Clears the cache — e.g. on logout or after `manifest reload`. */
|
|
367
|
-
clearCache() {
|
|
368
|
-
this.storage.remove(this.etagKey);
|
|
369
|
-
this.storage.remove(this.bodyKey);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
// src/nav-builder.ts
|
|
374
|
-
var DEFAULT_STANDARD_PAGE_ROUTES = {
|
|
375
|
-
dashboard: "/admin/dashboard",
|
|
376
|
-
tenants: "/admin/tenants",
|
|
377
|
-
subscriptions: "/admin/subscriptions",
|
|
378
|
-
promoCodes: "/admin/promo-codes",
|
|
379
|
-
plans: "/admin/plans",
|
|
380
|
-
planVersions: "/admin/plan-versions",
|
|
381
|
-
audit: "/admin/audit",
|
|
382
|
-
users: "/admin/users",
|
|
383
|
-
pilots: "/admin/pilots",
|
|
384
|
-
discovery: "/admin/discovery",
|
|
385
|
-
bundles: "/admin/bundles",
|
|
386
|
-
businessTypes: "/admin/business-types",
|
|
387
|
-
marketingCatalog: "/admin/marketing-catalog",
|
|
388
|
-
platformEmail: "/admin/platform-email",
|
|
389
|
-
platformEmailHistory: "/admin/platform-email-history"
|
|
390
|
-
};
|
|
391
|
-
var DEFAULT_LABELS = {
|
|
392
|
-
dashboard: "Dashboard",
|
|
393
|
-
tenants: "Mandanten",
|
|
394
|
-
subscriptions: "Abonnements",
|
|
395
|
-
promoCodes: "Promo-Codes",
|
|
396
|
-
plans: "Pl\xE4ne & Versionen",
|
|
397
|
-
planVersions: "Plan-Versionen",
|
|
398
|
-
audit: "Audit-Log",
|
|
399
|
-
users: "Benutzer",
|
|
400
|
-
pilots: "Piloten",
|
|
401
|
-
discovery: "Discovery",
|
|
402
|
-
bundles: "Bundles",
|
|
403
|
-
businessTypes: "Gesch\xE4ftstypen",
|
|
404
|
-
marketingCatalog: "Marketing-Catalog",
|
|
405
|
-
platformEmail: "Plattform-E-Mail",
|
|
406
|
-
platformEmailHistory: "E-Mail-Verlauf"
|
|
407
|
-
};
|
|
408
|
-
var DEFAULT_ICONS = {
|
|
409
|
-
dashboard: "dashboard",
|
|
410
|
-
tenants: "business",
|
|
411
|
-
subscriptions: "card_membership",
|
|
412
|
-
promoCodes: "local_activity",
|
|
413
|
-
plans: "workspace_premium",
|
|
414
|
-
planVersions: "history_edu",
|
|
415
|
-
audit: "history",
|
|
416
|
-
users: "people",
|
|
417
|
-
pilots: "flight_takeoff",
|
|
418
|
-
discovery: "travel_explore",
|
|
419
|
-
bundles: "inventory_2",
|
|
420
|
-
businessTypes: "category",
|
|
421
|
-
marketingCatalog: "campaign",
|
|
422
|
-
platformEmail: "mail",
|
|
423
|
-
platformEmailHistory: "mark_email_read"
|
|
424
|
-
};
|
|
425
|
-
var DEFAULT_NAV_SECTIONS = {
|
|
426
|
-
dashboard: "\xDCbersicht",
|
|
427
|
-
discovery: "Produktkatalog",
|
|
428
|
-
businessTypes: "Produktkatalog",
|
|
429
|
-
bundles: "Produktkatalog",
|
|
430
|
-
plans: "Produktkatalog",
|
|
431
|
-
planVersions: "Produktkatalog",
|
|
432
|
-
marketingCatalog: "Produktkatalog",
|
|
433
|
-
promoCodes: "Produktkatalog",
|
|
434
|
-
tenants: "Kunden",
|
|
435
|
-
subscriptions: "Kunden",
|
|
436
|
-
users: "Kunden",
|
|
437
|
-
pilots: "Kunden",
|
|
438
|
-
audit: "System",
|
|
439
|
-
platformEmail: "System",
|
|
440
|
-
platformEmailHistory: "System"
|
|
441
|
-
};
|
|
442
|
-
var DEFAULT_SECTION_ORDER = [
|
|
443
|
-
"\xDCbersicht",
|
|
444
|
-
"Produktkatalog",
|
|
445
|
-
"Kunden",
|
|
446
|
-
"System"
|
|
447
|
-
];
|
|
448
|
-
function buildRoutes(manifest, options = {}) {
|
|
449
|
-
const routes = [];
|
|
450
|
-
const capabilities = manifest.capabilities ?? {};
|
|
451
|
-
const standard = manifest.navigation?.standardPages ?? {};
|
|
452
|
-
const overrideRoutes = { ...DEFAULT_STANDARD_PAGE_ROUTES, ...options.standardPageRoutes };
|
|
453
|
-
const overrideLabels = { ...DEFAULT_LABELS, ...options.standardPageLabels };
|
|
454
|
-
const overrideIcons = { ...DEFAULT_ICONS, ...options.standardPageIcons };
|
|
455
|
-
const overrideNavSection = { ...DEFAULT_NAV_SECTIONS, ...options.standardPageNavSection };
|
|
456
|
-
for (const key of Object.keys(standard)) {
|
|
457
|
-
const def = standard[key];
|
|
458
|
-
if (!def?.enabled) continue;
|
|
459
|
-
const cap = def.requiredCapability ?? null;
|
|
460
|
-
if (cap && capabilities[cap] !== true) continue;
|
|
461
|
-
routes.push({
|
|
462
|
-
id: key,
|
|
463
|
-
path: overrideRoutes[key],
|
|
464
|
-
label: overrideLabels[key],
|
|
465
|
-
icon: overrideIcons[key],
|
|
466
|
-
navSection: overrideNavSection[key],
|
|
467
|
-
componentKey: `platform-${key}`,
|
|
468
|
-
requiredCapability: cap,
|
|
469
|
-
isStandard: true
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
const projectPages = manifest.navigation?.projectPages ?? [];
|
|
473
|
-
const exts = options.availableExtensions;
|
|
474
|
-
for (const p of projectPages) {
|
|
475
|
-
const cap = p.requiredCapability ?? null;
|
|
476
|
-
if (cap && capabilities[cap] !== true) continue;
|
|
477
|
-
if (exts && !exts.has(p.componentKey)) continue;
|
|
478
|
-
routes.push({
|
|
479
|
-
id: p.id,
|
|
480
|
-
path: p.route,
|
|
481
|
-
label: p.label,
|
|
482
|
-
icon: p.icon,
|
|
483
|
-
navSection: p.navSection,
|
|
484
|
-
componentKey: p.componentKey,
|
|
485
|
-
requiredCapability: cap,
|
|
486
|
-
isStandard: false,
|
|
487
|
-
prefetchOnIdle: p.prefetchOnIdle
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
return routes;
|
|
491
|
-
}
|
|
492
|
-
function buildSidebar(routes, sectionOrder = DEFAULT_SECTION_ORDER) {
|
|
493
|
-
const bySection = /* @__PURE__ */ new Map();
|
|
494
|
-
for (const r of routes) {
|
|
495
|
-
const section = r.navSection ?? null;
|
|
496
|
-
const list = bySection.get(section) ?? [];
|
|
497
|
-
list.push({ id: r.id, path: r.path, label: r.label, icon: r.icon });
|
|
498
|
-
bySection.set(section, list);
|
|
499
|
-
}
|
|
500
|
-
const sections = [];
|
|
501
|
-
if (bySection.has(null)) {
|
|
502
|
-
sections.push({ section: null, items: bySection.get(null) });
|
|
503
|
-
}
|
|
504
|
-
const ordered = /* @__PURE__ */ new Set();
|
|
505
|
-
for (const name of sectionOrder) {
|
|
506
|
-
if (bySection.has(name)) {
|
|
507
|
-
sections.push({ section: name, items: bySection.get(name) });
|
|
508
|
-
ordered.add(name);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
const remaining = [...bySection.entries()].filter(([s]) => s !== null && !ordered.has(s)).sort((a, b) => a[0].localeCompare(b[0]));
|
|
512
|
-
for (const [section, items] of remaining) {
|
|
513
|
-
sections.push({ section, items });
|
|
514
|
-
}
|
|
515
|
-
return sections;
|
|
516
|
-
}
|
|
517
|
-
function resolveExtension(componentKey, extensions) {
|
|
518
|
-
return extensions[componentKey] ?? null;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// src/action-registry.ts
|
|
522
|
-
var MissingHandlerError = class extends Error {
|
|
523
|
-
constructor(actionKey) {
|
|
524
|
-
super(
|
|
525
|
-
`Kein Handler f\xFCr actionKey "${actionKey}" registriert. Konsument-Shell muss \`actions["${actionKey}"]\` bereitstellen.`
|
|
526
|
-
);
|
|
527
|
-
this.name = "MissingHandlerError";
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
var ActionDefNotInManifestError = class extends Error {
|
|
531
|
-
constructor(actionKey) {
|
|
532
|
-
super(
|
|
533
|
-
`actionKey "${actionKey}" ist im Manifest nicht deklariert. Bitte als TenantAction in einer ManifestContribution registrieren.`
|
|
534
|
-
);
|
|
535
|
-
this.name = "ActionDefNotInManifestError";
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
var ActionRegistry = class {
|
|
539
|
-
defs = /* @__PURE__ */ new Map();
|
|
540
|
-
handlers = /* @__PURE__ */ new Map();
|
|
541
|
-
constructor(manifest, handlers = {}) {
|
|
542
|
-
for (const def of manifest.tenants?.actions ?? []) {
|
|
543
|
-
this.defs.set(def.actionKey, def);
|
|
544
|
-
}
|
|
545
|
-
for (const [key, handler] of Object.entries(handlers)) {
|
|
546
|
-
this.handlers.set(key, handler);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Registers a handler after the fact (e.g. when consumer code loads
|
|
551
|
-
* lazily). Throws `ActionDefNotInManifestError` if the `actionKey` is not
|
|
552
|
-
* declared in the manifest — prevents dead registrations.
|
|
553
|
-
*/
|
|
554
|
-
register(actionKey, handler) {
|
|
555
|
-
if (!this.defs.has(actionKey)) {
|
|
556
|
-
throw new ActionDefNotInManifestError(actionKey);
|
|
557
|
-
}
|
|
558
|
-
this.handlers.set(actionKey, handler);
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Returns the `{def, handler}` pair. Throws if the key is missing from
|
|
562
|
-
* the manifest or no handler is registered. The shell's UI layer calls
|
|
563
|
-
* the method, checks `def.requiresMfa` / `def.confirmType` for the
|
|
564
|
-
* pre-flow, and then calls `handler(input)`.
|
|
565
|
-
*/
|
|
566
|
-
get(actionKey) {
|
|
567
|
-
const def = this.defs.get(actionKey);
|
|
568
|
-
if (!def) throw new ActionDefNotInManifestError(actionKey);
|
|
569
|
-
const handler = this.handlers.get(actionKey);
|
|
570
|
-
if (!handler) throw new MissingHandlerError(actionKey);
|
|
571
|
-
return { def, handler };
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Convenience: `get(key).handler(input)`. UI convenience for actions
|
|
575
|
-
* that need neither MFA nor confirm.
|
|
576
|
-
*/
|
|
577
|
-
async dispatch(actionKey, input) {
|
|
578
|
-
return this.get(actionKey).handler(input);
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* List of actionKeys that are declared in the manifest but have no
|
|
582
|
-
* handler. Consumers use this in a doctor check to detect drift between
|
|
583
|
-
* the manifest and the shell build.
|
|
584
|
-
*/
|
|
585
|
-
listOrphanedDefs() {
|
|
586
|
-
return [...this.defs.keys()].filter((k) => !this.handlers.has(k));
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* List of registered handlers that are missing from the manifest. Drift
|
|
590
|
-
* in the other direction.
|
|
591
|
-
*/
|
|
592
|
-
listOrphanedHandlers() {
|
|
593
|
-
return [...this.handlers.keys()].filter((k) => !this.defs.has(k));
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
// src/batch-column-fetcher.ts
|
|
598
|
-
var BatchColumnDriftError = class extends Error {
|
|
599
|
-
constructor(column, reason) {
|
|
600
|
-
super(`Spalte "${column.key}": ${reason}`);
|
|
601
|
-
this.column = column;
|
|
602
|
-
this.name = "BatchColumnDriftError";
|
|
603
|
-
}
|
|
604
|
-
column;
|
|
605
|
-
};
|
|
606
|
-
var BatchColumnFetcher = class {
|
|
607
|
-
http;
|
|
608
|
-
paramStyle;
|
|
609
|
-
getAuthToken;
|
|
610
|
-
constructor(options = {}) {
|
|
611
|
-
this.http = options.http ?? defaultHttpClient();
|
|
612
|
-
this.paramStyle = options.paramStyle ?? "comma";
|
|
613
|
-
this.getAuthToken = options.getAuthToken;
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Loads the data for all columns declared in the manifest in parallel
|
|
617
|
-
* (one request per column, all `tenantIds` in the batch). Columns without
|
|
618
|
-
* a satisfied capability are ignored.
|
|
619
|
-
*/
|
|
620
|
-
async fetchAll(manifest, tenantIds) {
|
|
621
|
-
if (tenantIds.length === 0) return {};
|
|
622
|
-
const cols = this.eligibleColumns(manifest);
|
|
623
|
-
const results = await Promise.all(
|
|
624
|
-
cols.map(
|
|
625
|
-
(col) => this.fetchOne(col, tenantIds).then((data) => [col.key, data])
|
|
626
|
-
)
|
|
627
|
-
);
|
|
628
|
-
const out = {};
|
|
629
|
-
for (const [key, data] of results) out[key] = data;
|
|
630
|
-
return out;
|
|
631
|
-
}
|
|
632
|
-
/** Fetch a single column (consumers may also use this directly). */
|
|
633
|
-
async fetchOne(column, tenantIds) {
|
|
634
|
-
this.validateBatchEndpoint(column);
|
|
635
|
-
if (tenantIds.length === 0) return {};
|
|
636
|
-
const url = this.buildUrl(column.endpoint, tenantIds);
|
|
637
|
-
const headers = {};
|
|
638
|
-
const token = this.getAuthToken?.();
|
|
639
|
-
if (token) headers.Authorization = `Bearer ${token}`;
|
|
640
|
-
const res = await this.http(url, { method: "GET", headers });
|
|
641
|
-
if (res.status !== 200) {
|
|
642
|
-
throw new Error(
|
|
643
|
-
`Spalte "${column.key}" \u2014 Endpoint ${column.endpoint} antwortete HTTP ${res.status}`
|
|
644
|
-
);
|
|
645
|
-
}
|
|
646
|
-
const body = await res.json();
|
|
647
|
-
return body;
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Column drift against the manifest. Consumers use this for CI smoke
|
|
651
|
-
* tests of the manifest-vs-shell build.
|
|
652
|
-
*/
|
|
653
|
-
listDriftIssues(manifest) {
|
|
654
|
-
const issues = [];
|
|
655
|
-
for (const col of manifest.tenants?.columns ?? []) {
|
|
656
|
-
try {
|
|
657
|
-
this.validateBatchEndpoint(col);
|
|
658
|
-
} catch (err) {
|
|
659
|
-
if (err instanceof BatchColumnDriftError) issues.push(err);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
return issues;
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* Which columns have a satisfied `requiredCapability`? Manifest =
|
|
666
|
-
* discovery, so a local check is enough.
|
|
667
|
-
*/
|
|
668
|
-
eligibleColumns(manifest) {
|
|
669
|
-
const caps = manifest.capabilities ?? {};
|
|
670
|
-
return (manifest.tenants?.columns ?? []).filter((col) => {
|
|
671
|
-
if (!col.requiredCapability) return true;
|
|
672
|
-
return caps[col.requiredCapability] === true;
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
validateBatchEndpoint(col) {
|
|
676
|
-
if (!col.endpoint || col.endpoint.trim().length === 0) {
|
|
677
|
-
throw new BatchColumnDriftError(col, "endpoint ist leer");
|
|
678
|
-
}
|
|
679
|
-
if (col.endpoint.includes("{slug}") || col.endpoint.includes("{tenantId}")) {
|
|
680
|
-
throw new BatchColumnDriftError(
|
|
681
|
-
col,
|
|
682
|
-
"endpoint enth\xE4lt per-Tenant-Placeholder ({slug}/{tenantId}). Spalten-Endpoints m\xFCssen batchf\xE4hig sein \u2014 bitte Backend auf `?tenantIds=...`-Parameter umstellen."
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
buildUrl(endpoint, tenantIds) {
|
|
687
|
-
const sep = endpoint.includes("?") ? "&" : "?";
|
|
688
|
-
if (this.paramStyle === "comma") {
|
|
689
|
-
const enc = tenantIds.map(encodeURIComponent).join(",");
|
|
690
|
-
return `${endpoint}${sep}tenantIds=${enc}`;
|
|
691
|
-
}
|
|
692
|
-
const params = tenantIds.map((id) => `tenantIds=${encodeURIComponent(id)}`).join("&");
|
|
693
|
-
return `${endpoint}${sep}${params}`;
|
|
694
|
-
}
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
// src/use-api-list.ts
|
|
174
|
+
// src/vue/use-api-list.ts
|
|
698
175
|
import { ref, watch } from "vue";
|
|
699
176
|
function useApiList(options) {
|
|
700
177
|
const http = options.http ?? defaultHttpClient();
|
|
@@ -784,7 +261,7 @@ function useApiList(options) {
|
|
|
784
261
|
};
|
|
785
262
|
}
|
|
786
263
|
|
|
787
|
-
// src/use-tenants.ts
|
|
264
|
+
// src/vue/use-tenants.ts
|
|
788
265
|
import { ref as ref2 } from "vue";
|
|
789
266
|
function useTenants(options) {
|
|
790
267
|
if (!options?.endpoint) {
|
|
@@ -803,7 +280,7 @@ function useTenants(options) {
|
|
|
803
280
|
return { ...list, filter };
|
|
804
281
|
}
|
|
805
282
|
|
|
806
|
-
// src/use-audit-entries.ts
|
|
283
|
+
// src/vue/use-audit-entries.ts
|
|
807
284
|
import { ref as ref3 } from "vue";
|
|
808
285
|
function useAuditEntries(options) {
|
|
809
286
|
if (!options?.endpoint) {
|
|
@@ -822,7 +299,7 @@ function useAuditEntries(options) {
|
|
|
822
299
|
return { ...list, filter };
|
|
823
300
|
}
|
|
824
301
|
|
|
825
|
-
// src/use-entitlement.ts
|
|
302
|
+
// src/vue/use-entitlement.ts
|
|
826
303
|
import { ref as ref4 } from "vue";
|
|
827
304
|
function useEntitlement(options) {
|
|
828
305
|
if (!options?.endpoint) {
|
|
@@ -863,7 +340,7 @@ function useEntitlement(options) {
|
|
|
863
340
|
return { entitlement, loading, error, load, hasFeature };
|
|
864
341
|
}
|
|
865
342
|
|
|
866
|
-
// src/use-tenant-manifest.ts
|
|
343
|
+
// src/vue/use-tenant-manifest.ts
|
|
867
344
|
import { ref as ref5 } from "vue";
|
|
868
345
|
function useTenantManifest(options) {
|
|
869
346
|
if (!options?.endpoint) {
|
|
@@ -907,8 +384,8 @@ function useTenantManifest(options) {
|
|
|
907
384
|
return { manifest, loading, error, load, hasFeature, quotaLimit };
|
|
908
385
|
}
|
|
909
386
|
|
|
910
|
-
// src/entitlement-provider.ts
|
|
911
|
-
import { inject as
|
|
387
|
+
// src/vue/entitlement-provider.ts
|
|
388
|
+
import { inject as inject3 } from "vue";
|
|
912
389
|
var ENTITLEMENT_INJECTION_KEY = /* @__PURE__ */ Symbol.for(
|
|
913
390
|
"@saasicat/ui-vue/ENTITLEMENT"
|
|
914
391
|
);
|
|
@@ -916,10 +393,10 @@ function provideEntitlement(app, entitlement) {
|
|
|
916
393
|
app.provide(ENTITLEMENT_INJECTION_KEY, entitlement);
|
|
917
394
|
}
|
|
918
395
|
function useInjectedEntitlement() {
|
|
919
|
-
return
|
|
396
|
+
return inject3(ENTITLEMENT_INJECTION_KEY, null);
|
|
920
397
|
}
|
|
921
398
|
|
|
922
|
-
// src/feature-router-guard.ts
|
|
399
|
+
// src/vue/feature-router-guard.ts
|
|
923
400
|
function extractRequired(to) {
|
|
924
401
|
const raw = to.meta?.requiresFeature;
|
|
925
402
|
if (!raw) return [];
|
|
@@ -944,7 +421,7 @@ function buildFeatureRouterGuard(options) {
|
|
|
944
421
|
};
|
|
945
422
|
}
|
|
946
423
|
|
|
947
|
-
// src/use-tenant-billing-catalog.ts
|
|
424
|
+
// src/vue/use-tenant-billing-catalog.ts
|
|
948
425
|
import { ref as ref6 } from "vue";
|
|
949
426
|
function useTenantBillingCatalog(options = {}) {
|
|
950
427
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
@@ -1002,7 +479,7 @@ function useTenantBillingCatalog(options = {}) {
|
|
|
1002
479
|
return { plans, featureRegistry, bundles, loading, error, load };
|
|
1003
480
|
}
|
|
1004
481
|
|
|
1005
|
-
// src/use-tenant-billing.ts
|
|
482
|
+
// src/vue/use-tenant-billing.ts
|
|
1006
483
|
import { ref as ref7 } from "vue";
|
|
1007
484
|
function useTenantBilling(options = {}) {
|
|
1008
485
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
@@ -1143,7 +620,7 @@ function useTenantBilling(options = {}) {
|
|
|
1143
620
|
};
|
|
1144
621
|
}
|
|
1145
622
|
|
|
1146
|
-
// src/use-subscription-draft.ts
|
|
623
|
+
// src/vue/use-subscription-draft.ts
|
|
1147
624
|
import { computed as computed2, ref as ref8 } from "vue";
|
|
1148
625
|
import {
|
|
1149
626
|
selectChargeableBundles
|
|
@@ -1337,141 +814,7 @@ function useSubscriptionDraft(options) {
|
|
|
1337
814
|
};
|
|
1338
815
|
}
|
|
1339
816
|
|
|
1340
|
-
// src/
|
|
1341
|
-
var DEFAULT_I18N_DE = {
|
|
1342
|
-
sectionTitle: "Paket & Verbrauch",
|
|
1343
|
-
sectionSubtitle: "Aktuelles Paket, Verbrauch und Bundles.",
|
|
1344
|
-
loading: "Lade \u2026",
|
|
1345
|
-
noSubscription: "Keine Subscription f\xFCr diesen Mandanten gefunden.",
|
|
1346
|
-
activePlan: "Aktuelles Paket",
|
|
1347
|
-
cycleMonthly: "Monatlich",
|
|
1348
|
-
cycleYearly: "J\xE4hrlich",
|
|
1349
|
-
statusActive: "Aktiv",
|
|
1350
|
-
statusTrial: "Testphase",
|
|
1351
|
-
statusPastDue: "Zahlung \xFCberf\xE4llig",
|
|
1352
|
-
statusCanceled: "Gek\xFCndigt",
|
|
1353
|
-
statusPendingSales: "Vertrieb-Kl\xE4rung",
|
|
1354
|
-
trialEndsAt: "Testphase endet am",
|
|
1355
|
-
pilotEndsAt: "Pilot endet am",
|
|
1356
|
-
nextBillingDate: "N\xE4chste Abrechnung",
|
|
1357
|
-
pendingChange: "Ausstehender Plan-Wechsel",
|
|
1358
|
-
changeFromTo: "Wechsel zu",
|
|
1359
|
-
changeEffectiveAt: "wirksam ab",
|
|
1360
|
-
changePlanButton: "Paket wechseln",
|
|
1361
|
-
cancelSubscriptionButton: "Abonnement k\xFCndigen",
|
|
1362
|
-
usageTitle: "Verbrauch",
|
|
1363
|
-
featuresOverviewTitle: "Leistungsumfang",
|
|
1364
|
-
featuresActive: "Enthalten",
|
|
1365
|
-
featuresLocked: "Nicht enthalten",
|
|
1366
|
-
bundlesStoreTitle: "Bundles",
|
|
1367
|
-
bundlesBookedTitle: "Gebuchte Bundles",
|
|
1368
|
-
bundlesAvailableTitle: "Verf\xFCgbare Bundles",
|
|
1369
|
-
bundlesAvailableEmpty: "Aktuell sind keine zus\xE4tzlichen Bundles verf\xFCgbar.",
|
|
1370
|
-
bundlesPerMonth: "netto/Monat",
|
|
1371
|
-
bundleBookAction: "Bundle buchen",
|
|
1372
|
-
bundleBookInProgress: "Buchung l\xE4uft \u2026",
|
|
1373
|
-
bundleCancelAction: "K\xFCndigen",
|
|
1374
|
-
bundleReactivateAction: "Reaktivieren",
|
|
1375
|
-
bundleReactivateConfirmTitle: "Bundle reaktivieren",
|
|
1376
|
-
bundleReactivateConfirmBody: "Die K\xFCndigung wird r\xFCckg\xE4ngig gemacht. Das Bundle bleibt gebucht, l\xE4uft regul\xE4r weiter und wird wieder abgerechnet.",
|
|
1377
|
-
bundleCanceledAt: "Gek\xFCndigt zum",
|
|
1378
|
-
bundleMinimumTermUntil: "Mindestlaufzeit bis",
|
|
1379
|
-
bundleIncludesLabel: "Enth\xE4lt",
|
|
1380
|
-
bundleAlreadyBooked: "Bereits gebucht",
|
|
1381
|
-
bundleIncompatible: "Nicht kompatibel mit aktuellem Paket",
|
|
1382
|
-
bundleMissingRequires: "Ben\xF6tigt",
|
|
1383
|
-
bundlePreviewAddTitle: "Bundle buchen",
|
|
1384
|
-
bundlePreviewCancelTitle: "Bundle k\xFCndigen",
|
|
1385
|
-
bundlePreviewLoading: "Vorschau wird berechnet \u2026",
|
|
1386
|
-
bundlePreviewProrationTitle: "Anteilige Abrechnung",
|
|
1387
|
-
bundlePreviewProratedNow: "Heute anteilig f\xE4llig",
|
|
1388
|
-
bundlePreviewProrationDays: "Tage",
|
|
1389
|
-
bundlePreviewNextPeriod: "Regul\xE4r ab n\xE4chster Periode",
|
|
1390
|
-
bundlePreviewTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an \u2014 die Abrechnung beginnt mit der ersten bezahlten Periode.",
|
|
1391
|
-
bundlePreviewNoPrice: "F\xFCr den aktuellen Abrechnungszyklus ist kein Listenpreis gepflegt.",
|
|
1392
|
-
bundlePreviewMinimumTermLabel: "Mindestlaufzeit",
|
|
1393
|
-
bundlePreviewMinimumTermMonths: "Monate, bis",
|
|
1394
|
-
bundlePreviewMinimumTermNone: "Keine Mindestlaufzeit",
|
|
1395
|
-
bundlePreviewRedundantTitle: "Bereits enthaltene Features (w\xFCrden doppelt bezahlt)",
|
|
1396
|
-
bundlePreviewRedundantCoveredByPlan: "bereits im Plan",
|
|
1397
|
-
bundlePreviewRedundantCoveredByBundle: "bereits im Bundle",
|
|
1398
|
-
bundlePreviewMissingRequiresTitle: "Fehlende Voraussetzungen",
|
|
1399
|
-
bundlePreviewBlockersTitle: "Buchung nicht m\xF6glich",
|
|
1400
|
-
bundlePreviewWarningsTitle: "Hinweise",
|
|
1401
|
-
bundlePreviewEffectiveAt: "K\xFCndigung wirksam zum",
|
|
1402
|
-
bundlePreviewSavings: "Ersparnis pro Periode ab Wirksamkeit",
|
|
1403
|
-
bundlePreviewConfirmAdd: "Kostenpflichtig buchen",
|
|
1404
|
-
bundlePreviewConfirmCancel: "K\xFCndigung best\xE4tigen",
|
|
1405
|
-
bundlePreviewInProgress: "Wird ausgef\xFChrt \u2026",
|
|
1406
|
-
bundlePreviewClose: "Abbrechen",
|
|
1407
|
-
pendingVersionTitle: "Anstehende Plan-\xC4nderung",
|
|
1408
|
-
pendingVersionChipNonRegressive: "Verbessernd",
|
|
1409
|
-
pendingVersionChipRegressive: "Best\xE4tigung erforderlich",
|
|
1410
|
-
pendingVersionEffectiveAt: "Wirksam ab",
|
|
1411
|
-
pendingVersionAcceptAction: "\xC4nderungen akzeptieren",
|
|
1412
|
-
pendingVersionAcceptInProgress: "Akzeptiere \u2026",
|
|
1413
|
-
pendingVersionAcceptedAt: "Akzeptiert am",
|
|
1414
|
-
wizardTitle: "Paket wechseln",
|
|
1415
|
-
wizardClose: "Schlie\xDFen",
|
|
1416
|
-
wizardCurrent: "Aktuell",
|
|
1417
|
-
wizardBadgeCurrent: "aktiv",
|
|
1418
|
-
wizardBadgePopular: "beliebt",
|
|
1419
|
-
wizardPriceUnitMonthly: "netto/Monat",
|
|
1420
|
-
wizardPriceUnitYearly: "netto/Jahr",
|
|
1421
|
-
wizardPriceOnRequest: "auf Anfrage",
|
|
1422
|
-
wizardStepChoose: "Paket w\xE4hlen",
|
|
1423
|
-
wizardStepChooseIntro: "W\xE4hle dein Ziel-Paket und den Abrechnungszyklus. Im n\xE4chsten Schritt zeigen wir Verbrauchs-Check und Feature-Diff.",
|
|
1424
|
-
wizardStepPreview: "Vorschau",
|
|
1425
|
-
wizardStepConfirm: "Best\xE4tigen",
|
|
1426
|
-
wizardNext: "Weiter",
|
|
1427
|
-
wizardBack: "Zur\xFCck",
|
|
1428
|
-
wizardPreviewLoading: "Vorschau wird berechnet \u2026",
|
|
1429
|
-
wizardEffectiveAtLabel: "Wirksam ab",
|
|
1430
|
-
wizardEffectiveImmediate: "Wirksam sofort",
|
|
1431
|
-
wizardProrationTitle: "Anteilige Abrechnung",
|
|
1432
|
-
wizardProrationLine: "Mehrbetrag bis Periodenende:",
|
|
1433
|
-
wizardProrationDays: "Tage",
|
|
1434
|
-
wizardLimitsTitle: "Limit-Vergleich",
|
|
1435
|
-
wizardLimitsUsed: "Verbrauch",
|
|
1436
|
-
wizardLimitsCurrent: "Aktuell",
|
|
1437
|
-
wizardLimitsTarget: "Ziel",
|
|
1438
|
-
wizardFeaturesGained: "Neu freigeschaltet",
|
|
1439
|
-
wizardFeaturesLost: "Wegfallende Features",
|
|
1440
|
-
wizardBlockersTitle: "Verhinderungs-Gr\xFCnde",
|
|
1441
|
-
wizardConfirmImmediate: "Der Wechsel wird sofort wirksam.",
|
|
1442
|
-
wizardConfirmScheduled: "Der Wechsel wird wirksam zum",
|
|
1443
|
-
wizardConfirmAction: "Wechsel best\xE4tigen",
|
|
1444
|
-
wizardConfirmInProgress: "Wechsel l\xE4uft \u2026",
|
|
1445
|
-
wizardConfirmPriceTitle: "Preis\xFCbersicht",
|
|
1446
|
-
wizardConfirmProratedNow: "Heute anteilig f\xE4llig",
|
|
1447
|
-
wizardConfirmRecurringNext: "Regul\xE4r ab n\xE4chster Periode",
|
|
1448
|
-
wizardConfirmRecurringFrom: "Regul\xE4r f\xE4llig ab",
|
|
1449
|
-
wizardConfirmPerCycleMonthly: "pro Monat",
|
|
1450
|
-
wizardConfirmPerCycleYearly: "pro Jahr",
|
|
1451
|
-
wizardConfirmTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an.",
|
|
1452
|
-
wizardConfirmRecurringTrialEnd: "Regul\xE4r ab Ende der Testphase",
|
|
1453
|
-
wizardChangeTypeUpgrade: "Upgrade",
|
|
1454
|
-
wizardChangeTypeDowngrade: "Downgrade",
|
|
1455
|
-
wizardChangeTypeCycle: "Zyklus-Wechsel",
|
|
1456
|
-
wizardChangeTypeNoop: "Keine \xC4nderung",
|
|
1457
|
-
packageSnapshotTitle: "Gebuchtes Paket (Snapshot)",
|
|
1458
|
-
packageSnapshotSubtitle: "Schreibgesch\xFCtzte Kopie des Pakets, wie es beim Abschluss vermarktet wurde.",
|
|
1459
|
-
packageSnapshotCapturedAt: "Erfasst am",
|
|
1460
|
-
packageSnapshotOfferRef: "Angebots-Referenz",
|
|
1461
|
-
packageSnapshotPlanLabel: "Plan",
|
|
1462
|
-
packageSnapshotPlanVersionLabel: "Plan-Version",
|
|
1463
|
-
packageSnapshotCycleLabel: "Abrechnungszyklus",
|
|
1464
|
-
packageSnapshotBundlesLabel: "Enthaltene Bundles",
|
|
1465
|
-
packageSnapshotBundlesEmpty: "Keine Bundles im Paket.",
|
|
1466
|
-
packageSnapshotPriceMonthly: "Preis monatlich",
|
|
1467
|
-
packageSnapshotPriceYearly: "Preis j\xE4hrlich",
|
|
1468
|
-
packageSnapshotPriceTotal: "Gesamtpreis",
|
|
1469
|
-
packageSnapshotNone: "Diese Subscription wurde nicht \xFCber ein Webseiten-Angebot abgeschlossen.",
|
|
1470
|
-
packageSnapshotShowRaw: "Rohdaten anzeigen",
|
|
1471
|
-
packageSnapshotHideRaw: "Rohdaten ausblenden"
|
|
1472
|
-
};
|
|
1473
|
-
|
|
1474
|
-
// src/use-plan-versions.ts
|
|
817
|
+
// src/vue/use-plan-versions.ts
|
|
1475
818
|
import { ref as ref9 } from "vue";
|
|
1476
819
|
function buildVersionsComposable(label) {
|
|
1477
820
|
return function(options) {
|
|
@@ -1493,7 +836,7 @@ function buildVersionsComposable(label) {
|
|
|
1493
836
|
}
|
|
1494
837
|
var usePlanVersionsCatalog = buildVersionsComposable("plan-versions");
|
|
1495
838
|
|
|
1496
|
-
// src/use-bulk-publish.ts
|
|
839
|
+
// src/vue/use-bulk-publish.ts
|
|
1497
840
|
import { computed as computed3, ref as ref10 } from "vue";
|
|
1498
841
|
function useBulkPublish(options) {
|
|
1499
842
|
if (!options?.endpoints) {
|
|
@@ -1568,7 +911,7 @@ function useBulkPublish(options) {
|
|
|
1568
911
|
};
|
|
1569
912
|
}
|
|
1570
913
|
|
|
1571
|
-
// src/use-plan-editor.ts
|
|
914
|
+
// src/vue/use-plan-editor.ts
|
|
1572
915
|
import { computed as computed4, ref as ref11 } from "vue";
|
|
1573
916
|
var PlannedOnlyFeatureError = class extends Error {
|
|
1574
917
|
constructor(violations) {
|
|
@@ -1645,7 +988,7 @@ function usePlanEditor(manifest, options = {}) {
|
|
|
1645
988
|
};
|
|
1646
989
|
}
|
|
1647
990
|
|
|
1648
|
-
// src/use-public-boot.ts
|
|
991
|
+
// src/vue/use-public-boot.ts
|
|
1649
992
|
import { ref as ref12 } from "vue";
|
|
1650
993
|
function usePublicBoot(options) {
|
|
1651
994
|
const loader = new BootLoader(options);
|
|
@@ -1667,7 +1010,7 @@ function usePublicBoot(options) {
|
|
|
1667
1010
|
return { boot, loading, error, load };
|
|
1668
1011
|
}
|
|
1669
1012
|
|
|
1670
|
-
// src/use-discovery.ts
|
|
1013
|
+
// src/vue/use-discovery.ts
|
|
1671
1014
|
import { ref as ref13 } from "vue";
|
|
1672
1015
|
var DiscoveryLoadError = class extends Error {
|
|
1673
1016
|
constructor(status, message) {
|
|
@@ -1753,7 +1096,7 @@ function useDiscovery(options) {
|
|
|
1753
1096
|
return { snapshot, etag, loading, error, load, reload, rescan };
|
|
1754
1097
|
}
|
|
1755
1098
|
|
|
1756
|
-
// src/use-catalog-entries.ts
|
|
1099
|
+
// src/vue/use-catalog-entries.ts
|
|
1757
1100
|
import { ref as ref14 } from "vue";
|
|
1758
1101
|
var CatalogEntriesApiError = class extends Error {
|
|
1759
1102
|
constructor(status, body, message) {
|
|
@@ -1902,7 +1245,7 @@ function useCatalogEntries(options) {
|
|
|
1902
1245
|
};
|
|
1903
1246
|
}
|
|
1904
1247
|
|
|
1905
|
-
// src/use-bundles.ts
|
|
1248
|
+
// src/vue/use-bundles.ts
|
|
1906
1249
|
import { ref as ref15 } from "vue";
|
|
1907
1250
|
var BundlesApiError = class extends Error {
|
|
1908
1251
|
constructor(status, body, message) {
|
|
@@ -2073,7 +1416,7 @@ function useBundleVersions(options) {
|
|
|
2073
1416
|
return { versions, loading, error, load, createDraft, updateDraft, publish, discardDraft };
|
|
2074
1417
|
}
|
|
2075
1418
|
|
|
2076
|
-
// src/use-bundle-versions-map.ts
|
|
1419
|
+
// src/vue/use-bundle-versions-map.ts
|
|
2077
1420
|
import { ref as ref16, watch as watch2 } from "vue";
|
|
2078
1421
|
function useBundleVersionsMap(options) {
|
|
2079
1422
|
if (!options?.adminEndpoint) {
|
|
@@ -2144,7 +1487,7 @@ function useBundleVersionsMap(options) {
|
|
|
2144
1487
|
return { versionsByBundle, loading, error, refresh, refreshOne };
|
|
2145
1488
|
}
|
|
2146
1489
|
|
|
2147
|
-
// src/use-tenant-subscription-bundles.ts
|
|
1490
|
+
// src/vue/use-tenant-subscription-bundles.ts
|
|
2148
1491
|
import { ref as ref17 } from "vue";
|
|
2149
1492
|
var TenantSubscriptionBundlesApiError = class extends Error {
|
|
2150
1493
|
constructor(status, body, message) {
|
|
@@ -2239,7 +1582,7 @@ function rehydrateDates(raw) {
|
|
|
2239
1582
|
};
|
|
2240
1583
|
}
|
|
2241
1584
|
|
|
2242
|
-
// src/use-business-types.ts
|
|
1585
|
+
// src/vue/use-business-types.ts
|
|
2243
1586
|
import { ref as ref18 } from "vue";
|
|
2244
1587
|
var BusinessTypesApiError = class extends Error {
|
|
2245
1588
|
constructor(status, body, message) {
|
|
@@ -2408,7 +1751,7 @@ function useBusinessTypeVersions(options) {
|
|
|
2408
1751
|
return { versions, loading, error, load, createDraft, updateDraft, publish };
|
|
2409
1752
|
}
|
|
2410
1753
|
|
|
2411
|
-
// src/use-marketing-projections.ts
|
|
1754
|
+
// src/vue/use-marketing-projections.ts
|
|
2412
1755
|
import { ref as ref19 } from "vue";
|
|
2413
1756
|
var MarketingProjectionsApiError = class extends Error {
|
|
2414
1757
|
constructor(status, body, message) {
|
|
@@ -2511,7 +1854,7 @@ function useMarketingProjections(options) {
|
|
|
2511
1854
|
return { projections, filter, loading, error, setFilter, load, create, update, remove };
|
|
2512
1855
|
}
|
|
2513
1856
|
|
|
2514
|
-
// src/use-promotions.ts
|
|
1857
|
+
// src/vue/use-promotions.ts
|
|
2515
1858
|
import { ref as ref20 } from "vue";
|
|
2516
1859
|
var PromotionsApiError = class extends Error {
|
|
2517
1860
|
constructor(status, body, message) {
|
|
@@ -2597,7 +1940,7 @@ function usePromotions(options) {
|
|
|
2597
1940
|
return { promotions, loading, error, load, create, update, remove };
|
|
2598
1941
|
}
|
|
2599
1942
|
|
|
2600
|
-
// src/use-plans.ts
|
|
1943
|
+
// src/vue/use-plans.ts
|
|
2601
1944
|
import { ref as ref21 } from "vue";
|
|
2602
1945
|
var PlansApiError = class extends Error {
|
|
2603
1946
|
constructor(status, body, message) {
|
|
@@ -2821,7 +2164,7 @@ function usePlanVersions(options) {
|
|
|
2821
2164
|
};
|
|
2822
2165
|
}
|
|
2823
2166
|
|
|
2824
|
-
// src/use-live-plan-versions.ts
|
|
2167
|
+
// src/vue/use-live-plan-versions.ts
|
|
2825
2168
|
import { ref as ref22, watch as watch3 } from "vue";
|
|
2826
2169
|
function useLivePlanVersions(options) {
|
|
2827
2170
|
if (!options?.adminEndpoint) {
|
|
@@ -2896,7 +2239,7 @@ function findLatestLive(versions) {
|
|
|
2896
2239
|
})[0];
|
|
2897
2240
|
}
|
|
2898
2241
|
|
|
2899
|
-
// src/use-manifest.ts
|
|
2242
|
+
// src/vue/use-manifest.ts
|
|
2900
2243
|
import { ref as ref23 } from "vue";
|
|
2901
2244
|
function useManifest(options) {
|
|
2902
2245
|
const loader = new ManifestLoader(options);
|
|
@@ -2927,7 +2270,7 @@ function useManifest(options) {
|
|
|
2927
2270
|
return { manifest, loading, error, load, reload, clearCache };
|
|
2928
2271
|
}
|
|
2929
2272
|
|
|
2930
|
-
// src/use-nav.ts
|
|
2273
|
+
// src/vue/use-nav.ts
|
|
2931
2274
|
import { computed as computed5 } from "vue";
|
|
2932
2275
|
function useNav(manifest, options = {}) {
|
|
2933
2276
|
const routes = computed5(() => {
|
|
@@ -2938,7 +2281,7 @@ function useNav(manifest, options = {}) {
|
|
|
2938
2281
|
return { routes, sidebar };
|
|
2939
2282
|
}
|
|
2940
2283
|
|
|
2941
|
-
// src/use-actions.ts
|
|
2284
|
+
// src/vue/use-actions.ts
|
|
2942
2285
|
import { computed as computed6 } from "vue";
|
|
2943
2286
|
function useActions(manifest, actions) {
|
|
2944
2287
|
const registry = computed6(() => {
|
|
@@ -2948,53 +2291,8 @@ function useActions(manifest, actions) {
|
|
|
2948
2291
|
return { registry };
|
|
2949
2292
|
}
|
|
2950
2293
|
|
|
2951
|
-
// src/use-tenant-action-flow.ts
|
|
2294
|
+
// src/vue/use-tenant-action-flow.ts
|
|
2952
2295
|
import { computed as computed7 } from "vue";
|
|
2953
|
-
|
|
2954
|
-
// src/use-super-admin-context.ts
|
|
2955
|
-
import { inject as inject3 } from "vue";
|
|
2956
|
-
function useSuperAdminExtensions() {
|
|
2957
|
-
return inject3(SUPER_ADMIN_EXTENSIONS_KEY, {});
|
|
2958
|
-
}
|
|
2959
|
-
function useSuperAdminActions() {
|
|
2960
|
-
return inject3(SUPER_ADMIN_ACTIONS_KEY, {});
|
|
2961
|
-
}
|
|
2962
|
-
function useSuperAdminBrand() {
|
|
2963
|
-
const brand = inject3(SUPER_ADMIN_BRAND_KEY);
|
|
2964
|
-
if (!brand) {
|
|
2965
|
-
throw new Error(
|
|
2966
|
-
"useSuperAdminBrand(): kein SuperAdmin-Branding im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
2967
|
-
);
|
|
2968
|
-
}
|
|
2969
|
-
return brand;
|
|
2970
|
-
}
|
|
2971
|
-
function useSuperAdminEndpoints() {
|
|
2972
|
-
const endpoints = inject3(SUPER_ADMIN_ENDPOINTS_KEY);
|
|
2973
|
-
if (!endpoints) {
|
|
2974
|
-
throw new Error(
|
|
2975
|
-
"useSuperAdminEndpoints(): keine Endpoints im Inject-Scope. Wurde die Komponente innerhalb createSuperAdminApp() gemounted?"
|
|
2976
|
-
);
|
|
2977
|
-
}
|
|
2978
|
-
return endpoints;
|
|
2979
|
-
}
|
|
2980
|
-
function useSuperAdminManifest() {
|
|
2981
|
-
const accessor = inject3(SUPER_ADMIN_MANIFEST_KEY, null);
|
|
2982
|
-
return accessor ? accessor() : null;
|
|
2983
|
-
}
|
|
2984
|
-
function useSuperAdminLoginAdapter() {
|
|
2985
|
-
const adapter = inject3(SUPER_ADMIN_LOGIN_ADAPTER_KEY);
|
|
2986
|
-
if (!adapter) {
|
|
2987
|
-
throw new Error(
|
|
2988
|
-
"useSuperAdminLoginAdapter(): kein Login-Adapter registriert. Reiche ihn via createSuperAdminApp({ loginAdapter }) ein."
|
|
2989
|
-
);
|
|
2990
|
-
}
|
|
2991
|
-
return adapter;
|
|
2992
|
-
}
|
|
2993
|
-
function useSuperAdminHttp() {
|
|
2994
|
-
return inject3(SUPER_ADMIN_HTTP_KEY, defaultHttpClient());
|
|
2995
|
-
}
|
|
2996
|
-
|
|
2997
|
-
// src/use-tenant-action-flow.ts
|
|
2998
2296
|
function useTenantActionFlow(manifest, providers = {}) {
|
|
2999
2297
|
const handlers = useSuperAdminActions();
|
|
3000
2298
|
const registry = computed7(() => {
|
|
@@ -3076,7 +2374,7 @@ async function runFlow(def, row, registry, providers) {
|
|
|
3076
2374
|
}
|
|
3077
2375
|
}
|
|
3078
2376
|
|
|
3079
|
-
// src/use-platform-tenant-actions.ts
|
|
2377
|
+
// src/vue/use-platform-tenant-actions.ts
|
|
3080
2378
|
import { computed as computed8, ref as ref24 } from "vue";
|
|
3081
2379
|
var DEFAULT_VISIBLE_FOR_ROW = (def, row) => {
|
|
3082
2380
|
if (def.actionKey === "tenants.suspend") return row.isActive;
|
|
@@ -3214,7 +2512,7 @@ function usePlatformTenantActions(options) {
|
|
|
3214
2512
|
};
|
|
3215
2513
|
}
|
|
3216
2514
|
|
|
3217
|
-
// src/use-batch-columns.ts
|
|
2515
|
+
// src/vue/use-batch-columns.ts
|
|
3218
2516
|
import { ref as ref25, watch as watch4 } from "vue";
|
|
3219
2517
|
function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
3220
2518
|
const fetcher = new BatchColumnFetcher(options);
|
|
@@ -3243,253 +2541,7 @@ function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
|
3243
2541
|
return { data, loading, error, reload: load };
|
|
3244
2542
|
}
|
|
3245
2543
|
|
|
3246
|
-
// src/
|
|
3247
|
-
var dec = (s) => Number(s);
|
|
3248
|
-
function extractQuotas(p) {
|
|
3249
|
-
if (p.quotas && Object.keys(p.quotas).length > 0) {
|
|
3250
|
-
return { ...p.quotas };
|
|
3251
|
-
}
|
|
3252
|
-
const out = {};
|
|
3253
|
-
if (typeof p.maxUsers === "number") out.users = p.maxUsers;
|
|
3254
|
-
if (typeof p.maxVehicles === "number") out.vehicles = p.maxVehicles;
|
|
3255
|
-
if (typeof p.maxStorageGb === "number") out.storageGb = p.maxStorageGb;
|
|
3256
|
-
return out;
|
|
3257
|
-
}
|
|
3258
|
-
var sortByPublishedDesc = (rows) => [...rows].sort((a, b) => {
|
|
3259
|
-
const at = a.publishedAt ? Date.parse(a.publishedAt) : Number.POSITIVE_INFINITY;
|
|
3260
|
-
const bt = b.publishedAt ? Date.parse(b.publishedAt) : Number.POSITIVE_INFINITY;
|
|
3261
|
-
if (at !== bt) return bt - at;
|
|
3262
|
-
return b.version - a.version;
|
|
3263
|
-
});
|
|
3264
|
-
function findLiveAt(rows, asOfMs) {
|
|
3265
|
-
const candidates = rows.filter((r) => {
|
|
3266
|
-
if (r.publishedAt === null) return false;
|
|
3267
|
-
if (Date.parse(r.publishedAt) > asOfMs) return false;
|
|
3268
|
-
if (r.supersededAt !== null && Date.parse(r.supersededAt) <= asOfMs) return false;
|
|
3269
|
-
return true;
|
|
3270
|
-
});
|
|
3271
|
-
if (candidates.length === 0) return null;
|
|
3272
|
-
return [...candidates].sort((a, b) => b.version - a.version)[0] ?? null;
|
|
3273
|
-
}
|
|
3274
|
-
function findCurrentLive(rows) {
|
|
3275
|
-
return rows.find((r) => r.publishedAt !== null && r.supersededAt === null) ?? null;
|
|
3276
|
-
}
|
|
3277
|
-
function findDraft(rows) {
|
|
3278
|
-
return rows.find((r) => r.publishedAt === null) ?? null;
|
|
3279
|
-
}
|
|
3280
|
-
function groupBy(rows, keyOf) {
|
|
3281
|
-
const out = /* @__PURE__ */ new Map();
|
|
3282
|
-
for (const r of rows) {
|
|
3283
|
-
const k = keyOf(r);
|
|
3284
|
-
const list = out.get(k) ?? [];
|
|
3285
|
-
list.push(r);
|
|
3286
|
-
out.set(k, list);
|
|
3287
|
-
}
|
|
3288
|
-
return out;
|
|
3289
|
-
}
|
|
3290
|
-
function resolvePlan(source, liveBase) {
|
|
3291
|
-
const quotas = extractQuotas(source);
|
|
3292
|
-
return {
|
|
3293
|
-
source,
|
|
3294
|
-
liveBase,
|
|
3295
|
-
isDraft: source.publishedAt === null,
|
|
3296
|
-
planId: source.planId,
|
|
3297
|
-
features: source.features,
|
|
3298
|
-
quotas,
|
|
3299
|
-
monthlyNet: dec(source.monthlyNet),
|
|
3300
|
-
yearlyNet: dec(source.yearlyNet),
|
|
3301
|
-
marketed: source.marketed,
|
|
3302
|
-
version: source.version,
|
|
3303
|
-
maxUsers: quotas.users,
|
|
3304
|
-
maxVehicles: quotas.vehicles,
|
|
3305
|
-
maxStorageGb: quotas.storageGb
|
|
3306
|
-
};
|
|
3307
|
-
}
|
|
3308
|
-
function dateLabelDe(iso) {
|
|
3309
|
-
return new Date(iso).toLocaleDateString("de-DE", {
|
|
3310
|
-
day: "2-digit",
|
|
3311
|
-
month: "short",
|
|
3312
|
-
year: "numeric"
|
|
3313
|
-
});
|
|
3314
|
-
}
|
|
3315
|
-
function buildDraftsSnapshot(data, sortPlansFn) {
|
|
3316
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3317
|
-
const plans = [];
|
|
3318
|
-
for (const [, rows] of planByKey) {
|
|
3319
|
-
const draft = findDraft(rows);
|
|
3320
|
-
const live = findCurrentLive(rows);
|
|
3321
|
-
if (draft) plans.push(resolvePlan(draft, live));
|
|
3322
|
-
else if (live) plans.push(resolvePlan(live, null));
|
|
3323
|
-
}
|
|
3324
|
-
const draftCount = plans.filter((p) => p.isDraft).length;
|
|
3325
|
-
return {
|
|
3326
|
-
id: "drafts",
|
|
3327
|
-
kind: "drafts",
|
|
3328
|
-
status: "DRAFT",
|
|
3329
|
-
label: "Arbeitsstand",
|
|
3330
|
-
title: draftCount === 0 ? "Keine offenen Drafts" : `${draftCount} offene${draftCount === 1 ? "r" : ""} Draft${draftCount === 1 ? "" : "s"} bereit f\xFCr Publish`,
|
|
3331
|
-
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.",
|
|
3332
|
-
asOf: null,
|
|
3333
|
-
createdAt: null,
|
|
3334
|
-
publishedAt: null,
|
|
3335
|
-
authorEmail: null,
|
|
3336
|
-
plans: sortPlansFn(plans),
|
|
3337
|
-
draftCount,
|
|
3338
|
-
regressionCount: 0
|
|
3339
|
-
};
|
|
3340
|
-
}
|
|
3341
|
-
function buildActiveSnapshot(data, sortPlansFn) {
|
|
3342
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3343
|
-
const plans = [];
|
|
3344
|
-
for (const [, rows] of planByKey) {
|
|
3345
|
-
const live = findCurrentLive(rows);
|
|
3346
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
3347
|
-
}
|
|
3348
|
-
if (plans.length === 0) return null;
|
|
3349
|
-
const publishedDates = plans.map((p) => p.source.publishedAt).filter((t) => t !== null).sort();
|
|
3350
|
-
const latestPublished = publishedDates[publishedDates.length - 1];
|
|
3351
|
-
return {
|
|
3352
|
-
id: "active",
|
|
3353
|
-
kind: "active",
|
|
3354
|
-
status: "ACTIVE",
|
|
3355
|
-
label: "Aktuell",
|
|
3356
|
-
title: "Live-Catalog",
|
|
3357
|
-
description: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
|
|
3358
|
-
asOf: latestPublished ?? null,
|
|
3359
|
-
createdAt: null,
|
|
3360
|
-
publishedAt: latestPublished ?? null,
|
|
3361
|
-
authorEmail: null,
|
|
3362
|
-
plans: sortPlansFn(plans),
|
|
3363
|
-
draftCount: 0,
|
|
3364
|
-
regressionCount: 0
|
|
3365
|
-
};
|
|
3366
|
-
}
|
|
3367
|
-
function buildHistoricalSnapshots(data, sortPlansFn) {
|
|
3368
|
-
const allPublishedAt = /* @__PURE__ */ new Set();
|
|
3369
|
-
for (const r of data.planVersions) if (r.publishedAt) allPublishedAt.add(r.publishedAt);
|
|
3370
|
-
if (allPublishedAt.size === 0) return [];
|
|
3371
|
-
const planByKey = groupBy(data.planVersions, (r) => r.planId);
|
|
3372
|
-
const liveTimestamps = /* @__PURE__ */ new Set();
|
|
3373
|
-
for (const rows of planByKey.values()) {
|
|
3374
|
-
const live = findCurrentLive(rows);
|
|
3375
|
-
if (live?.publishedAt) liveTimestamps.add(live.publishedAt);
|
|
3376
|
-
}
|
|
3377
|
-
const liveSorted = [...liveTimestamps].sort();
|
|
3378
|
-
const latestLive = liveSorted[liveSorted.length - 1];
|
|
3379
|
-
const sortedDesc = [...allPublishedAt].sort((a, b) => Date.parse(b) - Date.parse(a));
|
|
3380
|
-
const out = [];
|
|
3381
|
-
for (const ts of sortedDesc) {
|
|
3382
|
-
if (latestLive && Date.parse(ts) >= Date.parse(latestLive)) continue;
|
|
3383
|
-
const tMs = Date.parse(ts) + 1;
|
|
3384
|
-
const plans = [];
|
|
3385
|
-
for (const [, rows] of planByKey) {
|
|
3386
|
-
const live = findLiveAt(rows, tMs);
|
|
3387
|
-
if (live) plans.push(resolvePlan(live, null));
|
|
3388
|
-
}
|
|
3389
|
-
if (plans.length === 0) continue;
|
|
3390
|
-
const publishedAtThisEvent = data.planVersions.filter((r) => r.publishedAt === ts);
|
|
3391
|
-
const regressionCount = publishedAtThisEvent.filter((r) => !r.nonRegressive).length;
|
|
3392
|
-
const author = publishedAtThisEvent[0]?.publishedByUserId ?? null;
|
|
3393
|
-
out.push({
|
|
3394
|
-
id: `hist-${ts}`,
|
|
3395
|
-
kind: "historical",
|
|
3396
|
-
status: "ARCHIVED",
|
|
3397
|
-
label: dateLabelDe(ts),
|
|
3398
|
-
title: summarizeEvent(publishedAtThisEvent),
|
|
3399
|
-
description: detailEvent(publishedAtThisEvent),
|
|
3400
|
-
asOf: ts,
|
|
3401
|
-
createdAt: ts,
|
|
3402
|
-
publishedAt: ts,
|
|
3403
|
-
authorEmail: author,
|
|
3404
|
-
plans: sortPlansFn(plans),
|
|
3405
|
-
draftCount: 0,
|
|
3406
|
-
regressionCount
|
|
3407
|
-
});
|
|
3408
|
-
}
|
|
3409
|
-
return out;
|
|
3410
|
-
}
|
|
3411
|
-
function summarizeEvent(rows) {
|
|
3412
|
-
if (rows.length === 0) return "Publish-Event";
|
|
3413
|
-
if (rows.length === 1) {
|
|
3414
|
-
const r = rows[0];
|
|
3415
|
-
return `${r.planId} v${r.version} publiziert`;
|
|
3416
|
-
}
|
|
3417
|
-
return `${rows.length} Versionen publiziert`;
|
|
3418
|
-
}
|
|
3419
|
-
function detailEvent(rows) {
|
|
3420
|
-
if (rows.length === 0) return "";
|
|
3421
|
-
const note = rows[0]?.changeNote ?? "";
|
|
3422
|
-
return note.length > 0 ? note : "Snapshot rekonstruiert aus per-Entity-Versionen.";
|
|
3423
|
-
}
|
|
3424
|
-
function sortPlansBy(order) {
|
|
3425
|
-
if (!order || order.length === 0) {
|
|
3426
|
-
return (rows) => [...rows].sort((a, b) => a.planId.localeCompare(b.planId));
|
|
3427
|
-
}
|
|
3428
|
-
const idx = {};
|
|
3429
|
-
for (let i = 0; i < order.length; i++) idx[order[i]] = i;
|
|
3430
|
-
return (rows) => [...rows].sort((a, b) => {
|
|
3431
|
-
const ai = idx[a.planId] ?? Number.POSITIVE_INFINITY;
|
|
3432
|
-
const bi = idx[b.planId] ?? Number.POSITIVE_INFINITY;
|
|
3433
|
-
if (ai !== bi) return ai - bi;
|
|
3434
|
-
return a.planId.localeCompare(b.planId);
|
|
3435
|
-
});
|
|
3436
|
-
}
|
|
3437
|
-
function buildSnapshots(data, options = {}) {
|
|
3438
|
-
const sortPlansFn = sortPlansBy(options.planSortOrder);
|
|
3439
|
-
const drafts = buildDraftsSnapshot(data, sortPlansFn);
|
|
3440
|
-
const active = buildActiveSnapshot(data, sortPlansFn);
|
|
3441
|
-
const historical = buildHistoricalSnapshots(data, sortPlansFn);
|
|
3442
|
-
const out = [drafts];
|
|
3443
|
-
if (active) out.push(active);
|
|
3444
|
-
out.push(...historical);
|
|
3445
|
-
return out;
|
|
3446
|
-
}
|
|
3447
|
-
function listOpenDrafts(data) {
|
|
3448
|
-
return {
|
|
3449
|
-
plans: sortByPublishedDesc(data.planVersions).filter((r) => r.publishedAt === null)
|
|
3450
|
-
};
|
|
3451
|
-
}
|
|
3452
|
-
|
|
3453
|
-
// src/components/dialogs/types.ts
|
|
3454
|
-
var DEFAULT_PILOT_COPY = {
|
|
3455
|
-
tenantSubtitle: "Stammdaten des Mandanten",
|
|
3456
|
-
tenantNameLabel: "Name des Mandanten",
|
|
3457
|
-
tenantNamePlaceholder: "z. B. Muster GmbH",
|
|
3458
|
-
slugPlaceholder: "muster-mandant",
|
|
3459
|
-
adminEmailPlaceholder: "admin@example.com",
|
|
3460
|
-
notePlaceholder: "z. B. Sales-Pilot \xB7 Demo-Zugang"
|
|
3461
|
-
};
|
|
3462
|
-
|
|
3463
|
-
// src/components/bundle-editor/catalog-i18n.ts
|
|
3464
|
-
var CATALOG_DEFAULT_LOCALE = "de";
|
|
3465
|
-
function localized(i18n, locale, field) {
|
|
3466
|
-
if (locale === CATALOG_DEFAULT_LOCALE) return void 0;
|
|
3467
|
-
const value = i18n?.[locale]?.[field];
|
|
3468
|
-
return value && value.trim().length > 0 ? value : void 0;
|
|
3469
|
-
}
|
|
3470
|
-
function resolveLabel(baseLabel, i18n, locale) {
|
|
3471
|
-
return localized(i18n, locale, "label") ?? (baseLabel || void 0);
|
|
3472
|
-
}
|
|
3473
|
-
function buildFeatureRegistry(featureCatalog, locale) {
|
|
3474
|
-
const registry = {};
|
|
3475
|
-
for (const feature of featureCatalog) {
|
|
3476
|
-
const label = resolveLabel(feature.label, feature.i18n, locale);
|
|
3477
|
-
if (label) registry[feature.featureKey] = { label, core: feature.core };
|
|
3478
|
-
}
|
|
3479
|
-
return registry;
|
|
3480
|
-
}
|
|
3481
|
-
function buildQuotaRegistry(quotaCatalog, locale) {
|
|
3482
|
-
const registry = {};
|
|
3483
|
-
for (const quota of quotaCatalog) {
|
|
3484
|
-
registry[quota.quotaKey] = {
|
|
3485
|
-
label: resolveLabel(quota.label, quota.i18n, locale),
|
|
3486
|
-
unit: localized(quota.i18n, locale, "unit") ?? (quota.unit || void 0)
|
|
3487
|
-
};
|
|
3488
|
-
}
|
|
3489
|
-
return registry;
|
|
3490
|
-
}
|
|
3491
|
-
|
|
3492
|
-
// src/platform-loaders.ts
|
|
2544
|
+
// src/vue/platform-loaders.ts
|
|
3493
2545
|
function resolveEndpoints(endpoints) {
|
|
3494
2546
|
return {
|
|
3495
2547
|
apiBase: endpoints.apiBase,
|
|
@@ -3513,7 +2565,7 @@ function createPlatformLoaders(options) {
|
|
|
3513
2565
|
return { bootLoader, manifestLoader };
|
|
3514
2566
|
}
|
|
3515
2567
|
|
|
3516
|
-
// src/manifest-store-factory.ts
|
|
2568
|
+
// src/vue/manifest-store-factory.ts
|
|
3517
2569
|
import { defineStore } from "pinia";
|
|
3518
2570
|
import { ref as ref26 } from "vue";
|
|
3519
2571
|
function createManifestStore(options) {
|
|
@@ -3559,6 +2611,179 @@ function createManifestStore(options) {
|
|
|
3559
2611
|
return { manifest, loading, error, loaded, ensureLoaded, clearCache, reload };
|
|
3560
2612
|
});
|
|
3561
2613
|
}
|
|
2614
|
+
|
|
2615
|
+
// src/components/dialogs/types.ts
|
|
2616
|
+
var DEFAULT_PILOT_COPY = {
|
|
2617
|
+
tenantSubtitle: "Stammdaten des Mandanten",
|
|
2618
|
+
tenantNameLabel: "Name des Mandanten",
|
|
2619
|
+
tenantNamePlaceholder: "z. B. Muster GmbH",
|
|
2620
|
+
slugPlaceholder: "muster-mandant",
|
|
2621
|
+
adminEmailPlaceholder: "admin@example.com",
|
|
2622
|
+
notePlaceholder: "z. B. Sales-Pilot \xB7 Demo-Zugang"
|
|
2623
|
+
};
|
|
2624
|
+
|
|
2625
|
+
// src/components/bundle-editor/catalog-i18n.ts
|
|
2626
|
+
var CATALOG_DEFAULT_LOCALE = "de";
|
|
2627
|
+
function localized(i18n, locale, field) {
|
|
2628
|
+
if (locale === CATALOG_DEFAULT_LOCALE) return void 0;
|
|
2629
|
+
const value = i18n?.[locale]?.[field];
|
|
2630
|
+
return value && value.trim().length > 0 ? value : void 0;
|
|
2631
|
+
}
|
|
2632
|
+
function resolveLabel(baseLabel, i18n, locale) {
|
|
2633
|
+
return localized(i18n, locale, "label") ?? (baseLabel || void 0);
|
|
2634
|
+
}
|
|
2635
|
+
function buildFeatureRegistry(featureCatalog, locale) {
|
|
2636
|
+
const registry = {};
|
|
2637
|
+
for (const feature of featureCatalog) {
|
|
2638
|
+
const label = resolveLabel(feature.label, feature.i18n, locale);
|
|
2639
|
+
if (label) registry[feature.featureKey] = { label, core: feature.core };
|
|
2640
|
+
}
|
|
2641
|
+
return registry;
|
|
2642
|
+
}
|
|
2643
|
+
function buildQuotaRegistry(quotaCatalog, locale) {
|
|
2644
|
+
const registry = {};
|
|
2645
|
+
for (const quota of quotaCatalog) {
|
|
2646
|
+
registry[quota.quotaKey] = {
|
|
2647
|
+
label: resolveLabel(quota.label, quota.i18n, locale),
|
|
2648
|
+
unit: localized(quota.i18n, locale, "unit") ?? (quota.unit || void 0)
|
|
2649
|
+
};
|
|
2650
|
+
}
|
|
2651
|
+
return registry;
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
// src/pages-tenant/default-i18n.ts
|
|
2655
|
+
var DEFAULT_I18N_DE = {
|
|
2656
|
+
sectionTitle: "Paket & Verbrauch",
|
|
2657
|
+
sectionSubtitle: "Aktuelles Paket, Verbrauch und Bundles.",
|
|
2658
|
+
loading: "Lade \u2026",
|
|
2659
|
+
noSubscription: "Keine Subscription f\xFCr diesen Mandanten gefunden.",
|
|
2660
|
+
activePlan: "Aktuelles Paket",
|
|
2661
|
+
cycleMonthly: "Monatlich",
|
|
2662
|
+
cycleYearly: "J\xE4hrlich",
|
|
2663
|
+
statusActive: "Aktiv",
|
|
2664
|
+
statusTrial: "Testphase",
|
|
2665
|
+
statusPastDue: "Zahlung \xFCberf\xE4llig",
|
|
2666
|
+
statusCanceled: "Gek\xFCndigt",
|
|
2667
|
+
statusPendingSales: "Vertrieb-Kl\xE4rung",
|
|
2668
|
+
trialEndsAt: "Testphase endet am",
|
|
2669
|
+
pilotEndsAt: "Pilot endet am",
|
|
2670
|
+
nextBillingDate: "N\xE4chste Abrechnung",
|
|
2671
|
+
pendingChange: "Ausstehender Plan-Wechsel",
|
|
2672
|
+
changeFromTo: "Wechsel zu",
|
|
2673
|
+
changeEffectiveAt: "wirksam ab",
|
|
2674
|
+
changePlanButton: "Paket wechseln",
|
|
2675
|
+
cancelSubscriptionButton: "Abonnement k\xFCndigen",
|
|
2676
|
+
usageTitle: "Verbrauch",
|
|
2677
|
+
featuresOverviewTitle: "Leistungsumfang",
|
|
2678
|
+
featuresActive: "Enthalten",
|
|
2679
|
+
featuresLocked: "Nicht enthalten",
|
|
2680
|
+
bundlesStoreTitle: "Bundles",
|
|
2681
|
+
bundlesBookedTitle: "Gebuchte Bundles",
|
|
2682
|
+
bundlesAvailableTitle: "Verf\xFCgbare Bundles",
|
|
2683
|
+
bundlesAvailableEmpty: "Aktuell sind keine zus\xE4tzlichen Bundles verf\xFCgbar.",
|
|
2684
|
+
bundlesPerMonth: "netto/Monat",
|
|
2685
|
+
bundleBookAction: "Bundle buchen",
|
|
2686
|
+
bundleBookInProgress: "Buchung l\xE4uft \u2026",
|
|
2687
|
+
bundleCancelAction: "K\xFCndigen",
|
|
2688
|
+
bundleReactivateAction: "Reaktivieren",
|
|
2689
|
+
bundleReactivateConfirmTitle: "Bundle reaktivieren",
|
|
2690
|
+
bundleReactivateConfirmBody: "Die K\xFCndigung wird r\xFCckg\xE4ngig gemacht. Das Bundle bleibt gebucht, l\xE4uft regul\xE4r weiter und wird wieder abgerechnet.",
|
|
2691
|
+
bundleCanceledAt: "Gek\xFCndigt zum",
|
|
2692
|
+
bundleMinimumTermUntil: "Mindestlaufzeit bis",
|
|
2693
|
+
bundleIncludesLabel: "Enth\xE4lt",
|
|
2694
|
+
bundleAlreadyBooked: "Bereits gebucht",
|
|
2695
|
+
bundleIncompatible: "Nicht kompatibel mit aktuellem Paket",
|
|
2696
|
+
bundleMissingRequires: "Ben\xF6tigt",
|
|
2697
|
+
bundlePreviewAddTitle: "Bundle buchen",
|
|
2698
|
+
bundlePreviewCancelTitle: "Bundle k\xFCndigen",
|
|
2699
|
+
bundlePreviewLoading: "Vorschau wird berechnet \u2026",
|
|
2700
|
+
bundlePreviewProrationTitle: "Anteilige Abrechnung",
|
|
2701
|
+
bundlePreviewProratedNow: "Heute anteilig f\xE4llig",
|
|
2702
|
+
bundlePreviewProrationDays: "Tage",
|
|
2703
|
+
bundlePreviewNextPeriod: "Regul\xE4r ab n\xE4chster Periode",
|
|
2704
|
+
bundlePreviewTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an \u2014 die Abrechnung beginnt mit der ersten bezahlten Periode.",
|
|
2705
|
+
bundlePreviewNoPrice: "F\xFCr den aktuellen Abrechnungszyklus ist kein Listenpreis gepflegt.",
|
|
2706
|
+
bundlePreviewMinimumTermLabel: "Mindestlaufzeit",
|
|
2707
|
+
bundlePreviewMinimumTermMonths: "Monate, bis",
|
|
2708
|
+
bundlePreviewMinimumTermNone: "Keine Mindestlaufzeit",
|
|
2709
|
+
bundlePreviewRedundantTitle: "Bereits enthaltene Features (w\xFCrden doppelt bezahlt)",
|
|
2710
|
+
bundlePreviewRedundantCoveredByPlan: "bereits im Plan",
|
|
2711
|
+
bundlePreviewRedundantCoveredByBundle: "bereits im Bundle",
|
|
2712
|
+
bundlePreviewMissingRequiresTitle: "Fehlende Voraussetzungen",
|
|
2713
|
+
bundlePreviewBlockersTitle: "Buchung nicht m\xF6glich",
|
|
2714
|
+
bundlePreviewWarningsTitle: "Hinweise",
|
|
2715
|
+
bundlePreviewEffectiveAt: "K\xFCndigung wirksam zum",
|
|
2716
|
+
bundlePreviewSavings: "Ersparnis pro Periode ab Wirksamkeit",
|
|
2717
|
+
bundlePreviewConfirmAdd: "Kostenpflichtig buchen",
|
|
2718
|
+
bundlePreviewConfirmCancel: "K\xFCndigung best\xE4tigen",
|
|
2719
|
+
bundlePreviewInProgress: "Wird ausgef\xFChrt \u2026",
|
|
2720
|
+
bundlePreviewClose: "Abbrechen",
|
|
2721
|
+
pendingVersionTitle: "Anstehende Plan-\xC4nderung",
|
|
2722
|
+
pendingVersionChipNonRegressive: "Verbessernd",
|
|
2723
|
+
pendingVersionChipRegressive: "Best\xE4tigung erforderlich",
|
|
2724
|
+
pendingVersionEffectiveAt: "Wirksam ab",
|
|
2725
|
+
pendingVersionAcceptAction: "\xC4nderungen akzeptieren",
|
|
2726
|
+
pendingVersionAcceptInProgress: "Akzeptiere \u2026",
|
|
2727
|
+
pendingVersionAcceptedAt: "Akzeptiert am",
|
|
2728
|
+
wizardTitle: "Paket wechseln",
|
|
2729
|
+
wizardClose: "Schlie\xDFen",
|
|
2730
|
+
wizardCurrent: "Aktuell",
|
|
2731
|
+
wizardBadgeCurrent: "aktiv",
|
|
2732
|
+
wizardBadgePopular: "beliebt",
|
|
2733
|
+
wizardPriceUnitMonthly: "netto/Monat",
|
|
2734
|
+
wizardPriceUnitYearly: "netto/Jahr",
|
|
2735
|
+
wizardPriceOnRequest: "auf Anfrage",
|
|
2736
|
+
wizardStepChoose: "Paket w\xE4hlen",
|
|
2737
|
+
wizardStepChooseIntro: "W\xE4hle dein Ziel-Paket und den Abrechnungszyklus. Im n\xE4chsten Schritt zeigen wir Verbrauchs-Check und Feature-Diff.",
|
|
2738
|
+
wizardStepPreview: "Vorschau",
|
|
2739
|
+
wizardStepConfirm: "Best\xE4tigen",
|
|
2740
|
+
wizardNext: "Weiter",
|
|
2741
|
+
wizardBack: "Zur\xFCck",
|
|
2742
|
+
wizardPreviewLoading: "Vorschau wird berechnet \u2026",
|
|
2743
|
+
wizardEffectiveAtLabel: "Wirksam ab",
|
|
2744
|
+
wizardEffectiveImmediate: "Wirksam sofort",
|
|
2745
|
+
wizardProrationTitle: "Anteilige Abrechnung",
|
|
2746
|
+
wizardProrationLine: "Mehrbetrag bis Periodenende:",
|
|
2747
|
+
wizardProrationDays: "Tage",
|
|
2748
|
+
wizardLimitsTitle: "Limit-Vergleich",
|
|
2749
|
+
wizardLimitsUsed: "Verbrauch",
|
|
2750
|
+
wizardLimitsCurrent: "Aktuell",
|
|
2751
|
+
wizardLimitsTarget: "Ziel",
|
|
2752
|
+
wizardFeaturesGained: "Neu freigeschaltet",
|
|
2753
|
+
wizardFeaturesLost: "Wegfallende Features",
|
|
2754
|
+
wizardBlockersTitle: "Verhinderungs-Gr\xFCnde",
|
|
2755
|
+
wizardConfirmImmediate: "Der Wechsel wird sofort wirksam.",
|
|
2756
|
+
wizardConfirmScheduled: "Der Wechsel wird wirksam zum",
|
|
2757
|
+
wizardConfirmAction: "Wechsel best\xE4tigen",
|
|
2758
|
+
wizardConfirmInProgress: "Wechsel l\xE4uft \u2026",
|
|
2759
|
+
wizardConfirmPriceTitle: "Preis\xFCbersicht",
|
|
2760
|
+
wizardConfirmProratedNow: "Heute anteilig f\xE4llig",
|
|
2761
|
+
wizardConfirmRecurringNext: "Regul\xE4r ab n\xE4chster Periode",
|
|
2762
|
+
wizardConfirmRecurringFrom: "Regul\xE4r f\xE4llig ab",
|
|
2763
|
+
wizardConfirmPerCycleMonthly: "pro Monat",
|
|
2764
|
+
wizardConfirmPerCycleYearly: "pro Jahr",
|
|
2765
|
+
wizardConfirmTrialNote: "W\xE4hrend der Testphase f\xE4llt nichts an.",
|
|
2766
|
+
wizardConfirmRecurringTrialEnd: "Regul\xE4r ab Ende der Testphase",
|
|
2767
|
+
wizardChangeTypeUpgrade: "Upgrade",
|
|
2768
|
+
wizardChangeTypeDowngrade: "Downgrade",
|
|
2769
|
+
wizardChangeTypeCycle: "Zyklus-Wechsel",
|
|
2770
|
+
wizardChangeTypeNoop: "Keine \xC4nderung",
|
|
2771
|
+
packageSnapshotTitle: "Gebuchtes Paket (Snapshot)",
|
|
2772
|
+
packageSnapshotSubtitle: "Schreibgesch\xFCtzte Kopie des Pakets, wie es beim Abschluss vermarktet wurde.",
|
|
2773
|
+
packageSnapshotCapturedAt: "Erfasst am",
|
|
2774
|
+
packageSnapshotOfferRef: "Angebots-Referenz",
|
|
2775
|
+
packageSnapshotPlanLabel: "Plan",
|
|
2776
|
+
packageSnapshotPlanVersionLabel: "Plan-Version",
|
|
2777
|
+
packageSnapshotCycleLabel: "Abrechnungszyklus",
|
|
2778
|
+
packageSnapshotBundlesLabel: "Enthaltene Bundles",
|
|
2779
|
+
packageSnapshotBundlesEmpty: "Keine Bundles im Paket.",
|
|
2780
|
+
packageSnapshotPriceMonthly: "Preis monatlich",
|
|
2781
|
+
packageSnapshotPriceYearly: "Preis j\xE4hrlich",
|
|
2782
|
+
packageSnapshotPriceTotal: "Gesamtpreis",
|
|
2783
|
+
packageSnapshotNone: "Diese Subscription wurde nicht \xFCber ein Webseiten-Angebot abgeschlossen.",
|
|
2784
|
+
packageSnapshotShowRaw: "Rohdaten anzeigen",
|
|
2785
|
+
packageSnapshotHideRaw: "Rohdaten ausblenden"
|
|
2786
|
+
};
|
|
3562
2787
|
export {
|
|
3563
2788
|
ADMIN_UI_VERSION,
|
|
3564
2789
|
ActionDefNotInManifestError,
|
|
@@ -3594,6 +2819,7 @@ export {
|
|
|
3594
2819
|
SUPER_ADMIN_HTTP_KEY,
|
|
3595
2820
|
SUPER_ADMIN_LOGIN_ADAPTER_KEY,
|
|
3596
2821
|
SUPER_ADMIN_MANIFEST_KEY,
|
|
2822
|
+
SUPER_ADMIN_NOTIFY_KEY,
|
|
3597
2823
|
TenantSubscriptionBundlesApiError,
|
|
3598
2824
|
buildFeatureRegistry,
|
|
3599
2825
|
buildFeatureRouterGuard,
|
|
@@ -3606,7 +2832,6 @@ export {
|
|
|
3606
2832
|
createManifestStore,
|
|
3607
2833
|
createPlatformLoaders,
|
|
3608
2834
|
createProjectPageHostRoute,
|
|
3609
|
-
createSuperAdminApp,
|
|
3610
2835
|
defaultHttpClient,
|
|
3611
2836
|
defaultIconForActionKey,
|
|
3612
2837
|
defaultKvStore,
|