@saasicat/ui-vue 0.24.2 → 0.26.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 +32 -8
- package/dist/{catalog-DJcfm5N2.d.cts → catalog-Dch1Ryw0.d.cts} +353 -69
- package/dist/{catalog-DJcfm5N2.d.ts → catalog-Dch1Ryw0.d.ts} +353 -69
- package/dist/{chunk-F7NRM6KI.js → chunk-BPF2BMCQ.js} +748 -24
- package/dist/{chunk-D74FFCCP.js → chunk-NEXTZZRQ.js} +95 -177
- package/dist/{chunk-TQQMKWN6.js → chunk-O3J3ITF2.js} +119 -7
- package/dist/client/index.cjs +758 -83
- package/dist/client/index.d.cts +414 -9
- package/dist/client/index.d.ts +414 -9
- package/dist/client/index.js +84 -12
- package/dist/index.cjs +1325 -294
- package/dist/index.d.cts +205 -15
- package/dist/index.d.ts +205 -15
- package/dist/index.js +566 -240
- package/dist/quasar/index.cjs +574 -62
- package/dist/quasar/index.d.cts +61 -6
- package/dist/quasar/index.d.ts +61 -6
- package/dist/quasar/index.js +83 -19
- package/dist/{use-sa-theme-OUBlaqgl.d.ts → resource-registry-D7Xjs-5f.d.cts} +157 -7
- package/dist/{use-sa-theme-B5t7oXph.d.cts → resource-registry-TaR7rtq0.d.ts} +157 -7
- package/package.json +4 -3
- package/src/client/admin-error.ts +552 -0
- package/src/client/admin-resource-client.ts +9 -12
- package/src/client/batch-column-fetcher.ts +2 -2
- package/src/client/boot-loader.ts +12 -1
- package/src/client/http/axios-http-client.ts +383 -0
- package/src/client/http/fetch-http-client.ts +89 -0
- package/src/client/http/index.ts +6 -0
- package/src/client/http-json.ts +82 -16
- package/src/client/i18n/messages/discovery.ts +0 -6
- package/src/client/i18n/messages/errors.ts +44 -0
- package/src/client/i18n/messages/marketing.ts +0 -6
- package/src/client/i18n/messages/promos.ts +0 -2
- package/src/client/i18n/messages/shell.ts +12 -0
- package/src/client/i18n/messages.ts +3 -0
- package/src/client/index.ts +6 -0
- package/src/client/manifest-loader.ts +65 -15
- package/src/client/resources/audit.resource.ts +25 -0
- package/src/client/resources/define-resource.ts +166 -0
- package/src/client/resources/index.ts +42 -0
- package/src/client/resources/list-resource.ts +176 -0
- package/src/client/resources/plans.resource.ts +169 -0
- package/src/client/resources/resource-request.ts +117 -0
- package/src/client/resources/tenants.resource.ts +27 -0
- package/src/client/types.ts +10 -3
- package/src/components/BundleVersionPublishDialog.vue +1 -1
- package/src/components/MarketingPromotionsTab.vue +263 -241
- package/src/components/ThemeSwitcher.vue +85 -0
- package/src/components/admin-page/AdminAccordion.vue +125 -0
- package/src/components/bundle-editor/BundleCreatePanel.vue +1 -1
- package/src/components/dialogs/PromoCodeDialogFields.vue +20 -20
- package/src/components/plan/PlanCycleToggle.vue +1 -1
- package/src/components/plan-detail/PlanVersionsPanel.vue +5 -2
- package/src/index.ts +5 -0
- package/src/pages-standard/AdminLayout.vue +57 -0
- package/src/pages-standard/AdminManifestErrorPage.vue +4 -3
- package/src/pages-standard/BundlesPage.vue +5 -35
- package/src/pages-standard/DiscoveryPage.vue +8 -1
- package/src/pages-standard/MarketingCatalogPage.vue +14 -3
- package/src/pages-standard/SuperAdminLoginPage.vue +23 -2
- package/src/pages-standard/SuperAdminSetupWizard.vue +37 -3
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +30 -32
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +80 -88
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +73 -79
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +44 -6
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +8 -2
- package/src/pages-tenant/PackageSnapshotPanel.vue +31 -2
- package/src/quasar/confirm.ts +83 -0
- package/src/quasar/create-super-admin-app.ts +84 -10
- package/src/quasar/dark-bridge.ts +47 -10
- package/src/quasar/index.ts +1 -0
- package/src/ui/theme/components/accordion.css +118 -0
- package/src/ui/theme/index.css +1 -0
- package/src/vue/create-admin-routes.ts +9 -1
- package/src/vue/platform-loaders.ts +12 -2
- package/src/vue/resource-registry.ts +211 -0
- package/src/vue/super-admin-context.ts +20 -5
- package/src/vue/ui-confirm.ts +76 -0
- package/src/vue/use-api-list.ts +50 -45
- package/src/vue/use-async-action.ts +170 -0
- package/src/vue/use-async-data.ts +83 -0
- package/src/vue/use-bundles.ts +34 -7
- package/src/vue/use-catalog-entries.ts +37 -12
- package/src/vue/use-discovery.ts +27 -6
- package/src/vue/use-marketing-projections.ts +29 -7
- package/src/vue/use-plans.ts +36 -8
- package/src/vue/use-promotions.ts +27 -7
- package/src/vue/use-resource-list.ts +272 -0
- package/src/vue/use-sa-theme.ts +34 -5
- package/src/vue/use-tenant-subscription-bundles.ts +22 -3
package/dist/index.js
CHANGED
|
@@ -4,23 +4,18 @@ import {
|
|
|
4
4
|
ActionRegistry,
|
|
5
5
|
BatchColumnDriftError,
|
|
6
6
|
BatchColumnFetcher,
|
|
7
|
-
BootLoadError,
|
|
8
|
-
BootLoader,
|
|
9
7
|
DEFAULT_STANDARD_PAGE_ROUTES,
|
|
10
|
-
HttpJsonError,
|
|
11
8
|
IDENTITY_ACCENTS,
|
|
12
9
|
IDENTITY_ACCENT_VALUES,
|
|
13
10
|
IDENTITY_NEUTRAL,
|
|
14
11
|
IDENTITY_NEUTRAL_VALUE,
|
|
15
|
-
ManifestLoadError,
|
|
16
|
-
ManifestLoader,
|
|
17
12
|
MissingHandlerError,
|
|
18
13
|
buildRoutes,
|
|
19
14
|
buildSidebar,
|
|
20
15
|
countPlans,
|
|
21
16
|
createAdminResourceClient,
|
|
17
|
+
createAxiosHttpClient,
|
|
22
18
|
defaultSectionOrder,
|
|
23
|
-
getJson,
|
|
24
19
|
identityAccentAt,
|
|
25
20
|
identityAccentFor,
|
|
26
21
|
identityChipStyle,
|
|
@@ -28,18 +23,19 @@ import {
|
|
|
28
23
|
isExpired,
|
|
29
24
|
isFutureScheduled,
|
|
30
25
|
isProductionBoot,
|
|
31
|
-
postJson,
|
|
32
26
|
resolveExtension,
|
|
33
27
|
resolveLoginBranding,
|
|
34
28
|
resolvePlans,
|
|
35
|
-
todayIsoDate
|
|
36
|
-
|
|
37
|
-
} from "./chunk-D74FFCCP.js";
|
|
29
|
+
todayIsoDate
|
|
30
|
+
} from "./chunk-NEXTZZRQ.js";
|
|
38
31
|
import {
|
|
32
|
+
SA_COLOR_SCHEMES,
|
|
39
33
|
SA_LOCALE_STORAGE_KEY,
|
|
40
34
|
SA_THEME_KEY,
|
|
35
|
+
SA_THEME_STORAGE_KEY,
|
|
41
36
|
SUPER_ADMIN_ACTIONS_KEY,
|
|
42
37
|
SUPER_ADMIN_BRAND_KEY,
|
|
38
|
+
SUPER_ADMIN_CONFIRM_KEY,
|
|
43
39
|
SUPER_ADMIN_ENDPOINTS_KEY,
|
|
44
40
|
SUPER_ADMIN_EXTENSIONS_KEY,
|
|
45
41
|
SUPER_ADMIN_HTTP_KEY,
|
|
@@ -48,29 +44,77 @@ import {
|
|
|
48
44
|
SUPER_ADMIN_MANIFEST_CLEAR_CACHE_KEY,
|
|
49
45
|
SUPER_ADMIN_MANIFEST_KEY,
|
|
50
46
|
SUPER_ADMIN_NOTIFY_KEY,
|
|
47
|
+
SUPER_ADMIN_RESOURCES_KEY,
|
|
51
48
|
buildNavigationGuard,
|
|
49
|
+
createPlatformLoaders,
|
|
50
|
+
createResourceRegistry,
|
|
52
51
|
createSaTheme,
|
|
53
52
|
createSuperAdminI18n,
|
|
53
|
+
resolveSuperAdminEndpoints,
|
|
54
|
+
useResource,
|
|
54
55
|
useSaMessages,
|
|
55
56
|
useSaTheme,
|
|
56
57
|
useSuperAdminI18n
|
|
57
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-O3J3ITF2.js";
|
|
58
59
|
import {
|
|
60
|
+
AdminError,
|
|
61
|
+
BootLoadError,
|
|
62
|
+
BootLoader,
|
|
59
63
|
DEFAULT_SA_LOCALE,
|
|
64
|
+
HttpJsonError,
|
|
65
|
+
LIST_FIRST_PAGE,
|
|
66
|
+
LIST_PAGE_SIZE_DEFAULT,
|
|
67
|
+
LIST_PAGE_SIZE_MAX,
|
|
68
|
+
LIST_PAGINATION_PARAMS,
|
|
69
|
+
ManifestLoadError,
|
|
70
|
+
ManifestLoader,
|
|
60
71
|
SA_INTL_LOCALES,
|
|
61
72
|
SA_LOCALES,
|
|
62
73
|
SA_LOCALE_LABELS,
|
|
63
74
|
SA_MESSAGES,
|
|
75
|
+
adminErrorMessage,
|
|
76
|
+
auditResource,
|
|
77
|
+
bindResource,
|
|
78
|
+
clampListPage,
|
|
79
|
+
clampListPageSize,
|
|
80
|
+
createFetchHttpClient,
|
|
64
81
|
createSaCatalog,
|
|
65
82
|
defaultHttpClient,
|
|
66
83
|
defaultKvStore,
|
|
84
|
+
defineListOp,
|
|
67
85
|
defineMessages,
|
|
86
|
+
defineResource,
|
|
87
|
+
filterQueryString,
|
|
68
88
|
formatCurrency,
|
|
69
89
|
formatMessage,
|
|
90
|
+
getJson,
|
|
91
|
+
isAdminError,
|
|
92
|
+
isAxiosNoResponseError,
|
|
93
|
+
isEmptyResponse,
|
|
94
|
+
isPlatformError,
|
|
70
95
|
isSaBuiltinLocale,
|
|
96
|
+
isSentInQuery,
|
|
97
|
+
isTransportFailure,
|
|
98
|
+
listUrl,
|
|
99
|
+
markEmptyResponse,
|
|
100
|
+
markPlatformError,
|
|
101
|
+
markTransportFailure,
|
|
71
102
|
mergeMessages,
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
planVersionsResource,
|
|
104
|
+
plansResource,
|
|
105
|
+
platformResources,
|
|
106
|
+
postJson,
|
|
107
|
+
readErrorCode,
|
|
108
|
+
readErrorDetail,
|
|
109
|
+
readListPage,
|
|
110
|
+
requestJson,
|
|
111
|
+
requestJsonBody,
|
|
112
|
+
requireServerAnswer,
|
|
113
|
+
resolveMessages,
|
|
114
|
+
tenantsResource,
|
|
115
|
+
toAdminError,
|
|
116
|
+
trimTrailingSlashes
|
|
117
|
+
} from "./chunk-BPF2BMCQ.js";
|
|
74
118
|
|
|
75
119
|
// src/vue/use-super-admin-context.ts
|
|
76
120
|
import { inject } from "vue";
|
|
@@ -211,22 +255,17 @@ import { ref, watch } from "vue";
|
|
|
211
255
|
function useApiList(options) {
|
|
212
256
|
const http = options.http ?? defaultHttpClient();
|
|
213
257
|
const items = ref([]);
|
|
214
|
-
const page = ref(
|
|
215
|
-
const pageSize = ref(
|
|
258
|
+
const page = ref(LIST_FIRST_PAGE);
|
|
259
|
+
const pageSize = ref(LIST_PAGE_SIZE_DEFAULT);
|
|
216
260
|
const total = ref(0);
|
|
217
261
|
const loading = ref(false);
|
|
218
262
|
const error = ref(null);
|
|
219
263
|
function buildUrl() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (v === void 0 || v === null || v === "") continue;
|
|
226
|
-
params.set(k, String(v));
|
|
227
|
-
}
|
|
228
|
-
const sep = options.endpoint.includes("?") ? "&" : "?";
|
|
229
|
-
return `${options.endpoint}${sep}${params.toString()}`;
|
|
264
|
+
return listUrl(options.endpoint, {
|
|
265
|
+
page: page.value,
|
|
266
|
+
pageSize: pageSize.value,
|
|
267
|
+
filter: options.filter?.value
|
|
268
|
+
});
|
|
230
269
|
}
|
|
231
270
|
async function load() {
|
|
232
271
|
loading.value = true;
|
|
@@ -239,20 +278,11 @@ function useApiList(options) {
|
|
|
239
278
|
if (res.status !== 200) {
|
|
240
279
|
throw new Error(`Endpoint ${options.endpoint} \u2192 HTTP ${res.status}`);
|
|
241
280
|
}
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const body = raw;
|
|
248
|
-
items.value = body.items ?? [];
|
|
249
|
-
if (typeof body.page === "number") page.value = body.page;
|
|
250
|
-
if (typeof body.pageSize === "number") pageSize.value = body.pageSize;
|
|
251
|
-
if (typeof body.total === "number") total.value = body.total;
|
|
252
|
-
} else {
|
|
253
|
-
items.value = [];
|
|
254
|
-
total.value = 0;
|
|
255
|
-
}
|
|
281
|
+
const body = readListPage(await res.json());
|
|
282
|
+
items.value = body.items;
|
|
283
|
+
if (typeof body.page === "number") page.value = body.page;
|
|
284
|
+
if (typeof body.pageSize === "number") pageSize.value = body.pageSize;
|
|
285
|
+
if (typeof body.total === "number") total.value = body.total;
|
|
256
286
|
} catch (err) {
|
|
257
287
|
error.value = err instanceof Error ? err : new Error(String(err));
|
|
258
288
|
items.value = [];
|
|
@@ -262,19 +292,19 @@ function useApiList(options) {
|
|
|
262
292
|
}
|
|
263
293
|
}
|
|
264
294
|
async function goToPage(p) {
|
|
265
|
-
page.value =
|
|
295
|
+
page.value = clampListPage(p);
|
|
266
296
|
await load();
|
|
267
297
|
}
|
|
268
298
|
async function setPageSize(size) {
|
|
269
|
-
pageSize.value =
|
|
270
|
-
page.value =
|
|
299
|
+
pageSize.value = clampListPageSize(size);
|
|
300
|
+
page.value = LIST_FIRST_PAGE;
|
|
271
301
|
await load();
|
|
272
302
|
}
|
|
273
303
|
if (options.filter) {
|
|
274
304
|
watch(
|
|
275
305
|
options.filter,
|
|
276
306
|
() => {
|
|
277
|
-
page.value =
|
|
307
|
+
page.value = LIST_FIRST_PAGE;
|
|
278
308
|
void load();
|
|
279
309
|
},
|
|
280
310
|
{ deep: true }
|
|
@@ -320,15 +350,189 @@ function usePagination(rows, initialRowsPerPage = DEFAULT_ROWS_PER_PAGE) {
|
|
|
320
350
|
return { page, rowsPerPage, total, pagedRows };
|
|
321
351
|
}
|
|
322
352
|
|
|
353
|
+
// src/vue/use-async-action.ts
|
|
354
|
+
import { inject as inject3, ref as ref3 } from "vue";
|
|
355
|
+
function report(announce) {
|
|
356
|
+
try {
|
|
357
|
+
announce();
|
|
358
|
+
} catch (err) {
|
|
359
|
+
queueMicrotask(() => {
|
|
360
|
+
throw err;
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function useAsyncAction(fn, options = {}) {
|
|
365
|
+
const pending = ref3(false);
|
|
366
|
+
const error = ref3(null);
|
|
367
|
+
const notify = options.notify ?? inject3(SUPER_ADMIN_NOTIFY_KEY, void 0);
|
|
368
|
+
const messages = useSaMessages("errors");
|
|
369
|
+
const notifyOn = options.notifyOn ?? "error";
|
|
370
|
+
let inFlight = 0;
|
|
371
|
+
let generation = 0;
|
|
372
|
+
async function run(...args) {
|
|
373
|
+
const mine = ++generation;
|
|
374
|
+
inFlight++;
|
|
375
|
+
pending.value = true;
|
|
376
|
+
error.value = null;
|
|
377
|
+
try {
|
|
378
|
+
const result = await fn(...args);
|
|
379
|
+
await options.onSuccess?.(result);
|
|
380
|
+
if (notifyOn === "both") {
|
|
381
|
+
report(() => {
|
|
382
|
+
const message = typeof options.successMessage === "function" ? options.successMessage() : options.successMessage;
|
|
383
|
+
if (message) notify?.("positive", message);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return { ok: true, value: result };
|
|
387
|
+
} catch (err) {
|
|
388
|
+
const adminError = toAdminError(err);
|
|
389
|
+
if (mine === generation) error.value = adminError;
|
|
390
|
+
if (notifyOn !== "none") {
|
|
391
|
+
report(
|
|
392
|
+
() => notify?.(
|
|
393
|
+
"negative",
|
|
394
|
+
options.errorMessage?.(adminError) ?? adminErrorMessage(adminError, messages.value)
|
|
395
|
+
)
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
return { ok: false, error: adminError };
|
|
399
|
+
} finally {
|
|
400
|
+
if (--inFlight === 0) pending.value = false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
run,
|
|
405
|
+
pending,
|
|
406
|
+
error,
|
|
407
|
+
reset: () => {
|
|
408
|
+
error.value = null;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/vue/use-async-data.ts
|
|
414
|
+
import { ref as ref4, watch as watch3 } from "vue";
|
|
415
|
+
function useAsyncData(fn, options) {
|
|
416
|
+
const data = ref4(options.initial);
|
|
417
|
+
const pending = ref4(false);
|
|
418
|
+
const error = ref4(null);
|
|
419
|
+
let generation = 0;
|
|
420
|
+
async function reload() {
|
|
421
|
+
const mine = ++generation;
|
|
422
|
+
pending.value = true;
|
|
423
|
+
error.value = null;
|
|
424
|
+
try {
|
|
425
|
+
const result = await fn();
|
|
426
|
+
if (mine !== generation) return;
|
|
427
|
+
data.value = result;
|
|
428
|
+
} catch (err) {
|
|
429
|
+
if (mine !== generation) return;
|
|
430
|
+
error.value = toAdminError(err);
|
|
431
|
+
data.value = options.initial;
|
|
432
|
+
} finally {
|
|
433
|
+
if (mine === generation) pending.value = false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (options.watch?.length) {
|
|
437
|
+
watch3(options.watch, () => void reload());
|
|
438
|
+
}
|
|
439
|
+
if (options.immediate !== false) {
|
|
440
|
+
void Promise.resolve().then(() => reload());
|
|
441
|
+
}
|
|
442
|
+
return { data, pending, error, reload };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// src/vue/use-resource-list.ts
|
|
446
|
+
import { computed as computed3, ref as ref5, watch as watch4 } from "vue";
|
|
447
|
+
var DEFAULT_LIST_OP = "list";
|
|
448
|
+
var EMPTY_PAGE = Object.freeze({
|
|
449
|
+
items: Object.freeze([]),
|
|
450
|
+
total: 0
|
|
451
|
+
});
|
|
452
|
+
function paginationCollision(key, op, claimed) {
|
|
453
|
+
return new AdminError({
|
|
454
|
+
message: `useResourceList("${key}", { op: "${op}" }): the filter carries ${claimed.join(" and ")}, which the list already sends. The filter is serialised after the pagination, so its value wins on the wire while page.value keeps the one goToPage() set \u2014 the list would report a page it is not showing. Drive the page with goToPage()/setPageSize() and leave those keys out of the filter.`
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
function paginationKeysIn(filter) {
|
|
458
|
+
return LIST_PAGINATION_PARAMS.filter((param) => isSentInQuery(filter[param]));
|
|
459
|
+
}
|
|
460
|
+
function readListOp(key, ops, name) {
|
|
461
|
+
const op = Object.hasOwn(ops, name) ? ops[name] : void 0;
|
|
462
|
+
if (typeof op !== "function") {
|
|
463
|
+
throw new Error(
|
|
464
|
+
`useResourceList("${key}", { op: "${name}" }): that resource has no such operation. It offers: ${Object.keys(ops).join(", ")}.`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
return op;
|
|
468
|
+
}
|
|
469
|
+
function useResourceList(key, opts) {
|
|
470
|
+
const ops = useResource(key);
|
|
471
|
+
const opName = opts?.op ?? DEFAULT_LIST_OP;
|
|
472
|
+
const load = readListOp(key, ops, opName);
|
|
473
|
+
if (opts?.filter) {
|
|
474
|
+
const claimed = paginationKeysIn(opts.filter.value);
|
|
475
|
+
if (claimed.length > 0) throw paginationCollision(key, opName, claimed);
|
|
476
|
+
}
|
|
477
|
+
const page = ref5(LIST_FIRST_PAGE);
|
|
478
|
+
const pageSize = ref5(clampListPageSize(opts?.pageSize ?? LIST_PAGE_SIZE_DEFAULT));
|
|
479
|
+
function query() {
|
|
480
|
+
const filter = opts?.filter?.value;
|
|
481
|
+
if (filter) {
|
|
482
|
+
const claimed = paginationKeysIn(filter);
|
|
483
|
+
if (claimed.length > 0) throw paginationCollision(key, opName, claimed);
|
|
484
|
+
}
|
|
485
|
+
return { page: page.value, pageSize: pageSize.value, filter };
|
|
486
|
+
}
|
|
487
|
+
const state = useAsyncData(() => load(query()), {
|
|
488
|
+
initial: EMPTY_PAGE,
|
|
489
|
+
immediate: opts?.immediate
|
|
490
|
+
});
|
|
491
|
+
watch4(state.data, (answer) => {
|
|
492
|
+
if (typeof answer.page === "number") page.value = answer.page;
|
|
493
|
+
if (typeof answer.pageSize === "number") pageSize.value = answer.pageSize;
|
|
494
|
+
});
|
|
495
|
+
async function goToPage(next) {
|
|
496
|
+
page.value = clampListPage(next);
|
|
497
|
+
await state.reload();
|
|
498
|
+
}
|
|
499
|
+
async function setPageSize(size) {
|
|
500
|
+
pageSize.value = clampListPageSize(size);
|
|
501
|
+
page.value = LIST_FIRST_PAGE;
|
|
502
|
+
await state.reload();
|
|
503
|
+
}
|
|
504
|
+
if (opts?.filter) {
|
|
505
|
+
watch4(
|
|
506
|
+
opts.filter,
|
|
507
|
+
() => {
|
|
508
|
+
page.value = LIST_FIRST_PAGE;
|
|
509
|
+
void state.reload();
|
|
510
|
+
},
|
|
511
|
+
{ deep: true }
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
items: computed3(() => state.data.value.items),
|
|
516
|
+
total: computed3(() => state.data.value.total ?? state.data.value.items.length),
|
|
517
|
+
page,
|
|
518
|
+
pageSize,
|
|
519
|
+
pending: state.pending,
|
|
520
|
+
error: state.error,
|
|
521
|
+
reload: state.reload,
|
|
522
|
+
goToPage,
|
|
523
|
+
setPageSize
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
323
527
|
// src/vue/use-tenants.ts
|
|
324
|
-
import { ref as
|
|
528
|
+
import { ref as ref6 } from "vue";
|
|
325
529
|
function useTenants(options) {
|
|
326
530
|
if (!options?.endpoint) {
|
|
327
531
|
throw new Error(
|
|
328
532
|
'useTenants: `endpoint` is required (e.g. "/api/v1/admin/tenants" or "/api/admin/tenants"). The platform has no default because apps use different globalPrefix conventions.'
|
|
329
533
|
);
|
|
330
534
|
}
|
|
331
|
-
const filter = options.filter ??
|
|
535
|
+
const filter = options.filter ?? ref6({});
|
|
332
536
|
const list = useApiList({
|
|
333
537
|
endpoint: options.endpoint,
|
|
334
538
|
filter,
|
|
@@ -340,14 +544,14 @@ function useTenants(options) {
|
|
|
340
544
|
}
|
|
341
545
|
|
|
342
546
|
// src/vue/use-audit-entries.ts
|
|
343
|
-
import { ref as
|
|
547
|
+
import { ref as ref7 } from "vue";
|
|
344
548
|
function useAuditEntries(options) {
|
|
345
549
|
if (!options?.endpoint) {
|
|
346
550
|
throw new Error(
|
|
347
551
|
'useAuditEntries: `endpoint` is required (e.g. "/api/admin/audit" or "/api/v1/admin/audit"). The platform has no default because apps use different globalPrefix conventions.'
|
|
348
552
|
);
|
|
349
553
|
}
|
|
350
|
-
const filter = options.filter ??
|
|
554
|
+
const filter = options.filter ?? ref7({});
|
|
351
555
|
const list = useApiList({
|
|
352
556
|
endpoint: options.endpoint,
|
|
353
557
|
filter,
|
|
@@ -359,7 +563,7 @@ function useAuditEntries(options) {
|
|
|
359
563
|
}
|
|
360
564
|
|
|
361
565
|
// src/vue/use-entitlement.ts
|
|
362
|
-
import { ref as
|
|
566
|
+
import { ref as ref8 } from "vue";
|
|
363
567
|
function useEntitlement(options) {
|
|
364
568
|
if (!options?.endpoint) {
|
|
365
569
|
throw new Error(
|
|
@@ -368,9 +572,9 @@ function useEntitlement(options) {
|
|
|
368
572
|
}
|
|
369
573
|
const endpoint = options.endpoint;
|
|
370
574
|
const http = options.http ?? defaultHttpClient();
|
|
371
|
-
const entitlement =
|
|
372
|
-
const loading =
|
|
373
|
-
const error =
|
|
575
|
+
const entitlement = ref8(null);
|
|
576
|
+
const loading = ref8(false);
|
|
577
|
+
const error = ref8(null);
|
|
374
578
|
async function load() {
|
|
375
579
|
loading.value = true;
|
|
376
580
|
error.value = null;
|
|
@@ -400,15 +604,15 @@ function useEntitlement(options) {
|
|
|
400
604
|
}
|
|
401
605
|
|
|
402
606
|
// src/vue/use-tenant-manifest.ts
|
|
403
|
-
import { ref as
|
|
607
|
+
import { ref as ref9 } from "vue";
|
|
404
608
|
function useTenantManifest(options) {
|
|
405
609
|
if (!options?.endpoint) {
|
|
406
610
|
throw new Error('useTenantManifest: `endpoint` is required (e.g. "/api/tenant/manifest").');
|
|
407
611
|
}
|
|
408
612
|
const http = options.http ?? defaultHttpClient();
|
|
409
|
-
const manifest =
|
|
410
|
-
const loading =
|
|
411
|
-
const error =
|
|
613
|
+
const manifest = ref9(null);
|
|
614
|
+
const loading = ref9(false);
|
|
615
|
+
const error = ref9(null);
|
|
412
616
|
async function load() {
|
|
413
617
|
loading.value = true;
|
|
414
618
|
error.value = null;
|
|
@@ -442,7 +646,7 @@ function useTenantManifest(options) {
|
|
|
442
646
|
}
|
|
443
647
|
|
|
444
648
|
// src/vue/entitlement-provider.ts
|
|
445
|
-
import { inject as
|
|
649
|
+
import { inject as inject4 } from "vue";
|
|
446
650
|
var ENTITLEMENT_INJECTION_KEY = /* @__PURE__ */ Symbol.for(
|
|
447
651
|
"@saasicat/ui-vue/ENTITLEMENT"
|
|
448
652
|
);
|
|
@@ -450,7 +654,7 @@ function provideEntitlement(app, entitlement) {
|
|
|
450
654
|
app.provide(ENTITLEMENT_INJECTION_KEY, entitlement);
|
|
451
655
|
}
|
|
452
656
|
function useInjectedEntitlement() {
|
|
453
|
-
return
|
|
657
|
+
return inject4(ENTITLEMENT_INJECTION_KEY, null);
|
|
454
658
|
}
|
|
455
659
|
|
|
456
660
|
// src/vue/feature-router-guard.ts
|
|
@@ -479,15 +683,15 @@ function buildFeatureRouterGuard(options) {
|
|
|
479
683
|
}
|
|
480
684
|
|
|
481
685
|
// src/vue/use-tenant-billing-catalog.ts
|
|
482
|
-
import { ref as
|
|
686
|
+
import { ref as ref10 } from "vue";
|
|
483
687
|
function useTenantBillingCatalog(options = {}) {
|
|
484
688
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
485
689
|
const http = options.http ?? defaultHttpClient();
|
|
486
|
-
const plans =
|
|
487
|
-
const featureRegistry =
|
|
488
|
-
const bundles =
|
|
489
|
-
const loading =
|
|
490
|
-
const error =
|
|
690
|
+
const plans = ref10(null);
|
|
691
|
+
const featureRegistry = ref10(null);
|
|
692
|
+
const bundles = ref10(null);
|
|
693
|
+
const loading = ref10(false);
|
|
694
|
+
const error = ref10(null);
|
|
491
695
|
async function fetchJson(path) {
|
|
492
696
|
const res = await http(`${apiPrefix}${path}`, { method: "GET" });
|
|
493
697
|
if (res.status !== 200) {
|
|
@@ -537,14 +741,14 @@ function useTenantBillingCatalog(options = {}) {
|
|
|
537
741
|
}
|
|
538
742
|
|
|
539
743
|
// src/vue/use-tenant-billing.ts
|
|
540
|
-
import { ref as
|
|
744
|
+
import { ref as ref11 } from "vue";
|
|
541
745
|
function useTenantBilling(options = {}) {
|
|
542
746
|
const apiPrefix = trimTrailingSlashes(options.apiPrefix ?? "/billing");
|
|
543
747
|
const http = options.http ?? defaultHttpClient();
|
|
544
|
-
const usage =
|
|
545
|
-
const loading =
|
|
546
|
-
const error =
|
|
547
|
-
const subscriptionBundles =
|
|
748
|
+
const usage = ref11(null);
|
|
749
|
+
const loading = ref11(false);
|
|
750
|
+
const error = ref11(null);
|
|
751
|
+
const subscriptionBundles = ref11([]);
|
|
548
752
|
function authHeaders() {
|
|
549
753
|
const headers = {};
|
|
550
754
|
const token = options.getAuthToken?.();
|
|
@@ -678,7 +882,7 @@ function useTenantBilling(options = {}) {
|
|
|
678
882
|
}
|
|
679
883
|
|
|
680
884
|
// src/vue/use-subscription-draft.ts
|
|
681
|
-
import { computed as
|
|
885
|
+
import { computed as computed4, ref as ref12 } from "vue";
|
|
682
886
|
import {
|
|
683
887
|
selectChargeableBundles
|
|
684
888
|
} from "@saasicat/types";
|
|
@@ -697,27 +901,27 @@ function priceForCycle(monthlyNet, yearlyNet, cycle, yearlyFactor) {
|
|
|
697
901
|
}
|
|
698
902
|
function useSubscriptionDraft(options) {
|
|
699
903
|
const yearlyFactor = options.yearlyFactor ?? DEFAULT_YEARLY_FACTOR;
|
|
700
|
-
const plansRef =
|
|
701
|
-
const subscriptionBundlesRef =
|
|
904
|
+
const plansRef = computed4(() => unwrap(options.plans) ?? []);
|
|
905
|
+
const subscriptionBundlesRef = computed4(
|
|
702
906
|
() => unwrap(options.subscriptionBundles ?? null) ?? []
|
|
703
907
|
);
|
|
704
|
-
const plan =
|
|
705
|
-
const cycle =
|
|
706
|
-
const selectedBundleVersionIds =
|
|
908
|
+
const plan = ref12(options.initialPlan ?? null);
|
|
909
|
+
const cycle = ref12(options.initialCycle ?? "MONTHLY");
|
|
910
|
+
const selectedBundleVersionIds = ref12(
|
|
707
911
|
new Set(options.initialBundleVersionIds ?? [])
|
|
708
912
|
);
|
|
709
|
-
const promoCode =
|
|
710
|
-
const promoState =
|
|
711
|
-
const selectedPlan =
|
|
913
|
+
const promoCode = ref12("");
|
|
914
|
+
const promoState = ref12({ status: "idle", preview: null, message: "" });
|
|
915
|
+
const selectedPlan = computed4(() => {
|
|
712
916
|
if (!plan.value) return null;
|
|
713
917
|
return plansRef.value.find((p) => p.id === plan.value) ?? null;
|
|
714
918
|
});
|
|
715
|
-
const selectedBundles =
|
|
919
|
+
const selectedBundles = computed4(
|
|
716
920
|
() => subscriptionBundlesRef.value.filter(
|
|
717
921
|
(b) => selectedBundleVersionIds.value.has(b.bundleVersionId)
|
|
718
922
|
)
|
|
719
923
|
);
|
|
720
|
-
const chargeableBundles =
|
|
924
|
+
const chargeableBundles = computed4(() => {
|
|
721
925
|
const planFeatures = selectedPlan.value?.features ?? [];
|
|
722
926
|
const selected = selectedBundles.value;
|
|
723
927
|
const keptIds = new Set(
|
|
@@ -725,7 +929,7 @@ function useSubscriptionDraft(options) {
|
|
|
725
929
|
);
|
|
726
930
|
return selected.filter((b) => keptIds.has(b.bundleVersionId));
|
|
727
931
|
});
|
|
728
|
-
const activeFeatures =
|
|
932
|
+
const activeFeatures = computed4(() => {
|
|
729
933
|
const result = /* @__PURE__ */ new Set();
|
|
730
934
|
const planObj = selectedPlan.value;
|
|
731
935
|
if (planObj) {
|
|
@@ -736,7 +940,7 @@ function useSubscriptionDraft(options) {
|
|
|
736
940
|
}
|
|
737
941
|
return result;
|
|
738
942
|
});
|
|
739
|
-
const pricing =
|
|
943
|
+
const pricing = computed4(() => {
|
|
740
944
|
const cyc = cycle.value;
|
|
741
945
|
const planObj = selectedPlan.value;
|
|
742
946
|
const planNet = planObj ? priceForCycle(planObj.monthlyNet ?? 0, planObj.yearlyNet, cyc, yearlyFactor) : 0;
|
|
@@ -796,7 +1000,7 @@ function useSubscriptionDraft(options) {
|
|
|
796
1000
|
}
|
|
797
1001
|
};
|
|
798
1002
|
});
|
|
799
|
-
const isDirty =
|
|
1003
|
+
const isDirty = computed4(() => {
|
|
800
1004
|
return selectedBundleVersionIds.value.size > 0 || promoState.value.status === "valid";
|
|
801
1005
|
});
|
|
802
1006
|
function setPlan(planId) {
|
|
@@ -872,7 +1076,7 @@ function useSubscriptionDraft(options) {
|
|
|
872
1076
|
}
|
|
873
1077
|
|
|
874
1078
|
// src/vue/use-bulk-publish.ts
|
|
875
|
-
import { computed as
|
|
1079
|
+
import { computed as computed5, ref as ref13 } from "vue";
|
|
876
1080
|
function useBulkPublish(options) {
|
|
877
1081
|
const msg = useSaMessages("planVersions");
|
|
878
1082
|
if (!options?.endpoints) {
|
|
@@ -882,15 +1086,15 @@ function useBulkPublish(options) {
|
|
|
882
1086
|
}
|
|
883
1087
|
const http = options.http ?? defaultHttpClient();
|
|
884
1088
|
const endpoints = options.endpoints;
|
|
885
|
-
const items =
|
|
886
|
-
const successCount =
|
|
887
|
-
const failureCount =
|
|
888
|
-
const progress =
|
|
1089
|
+
const items = ref13([]);
|
|
1090
|
+
const successCount = computed5(() => items.value.filter((i) => i.status === "published").length);
|
|
1091
|
+
const failureCount = computed5(() => items.value.filter((i) => i.status === "failed").length);
|
|
1092
|
+
const progress = computed5(() => {
|
|
889
1093
|
if (items.value.length === 0) return 0;
|
|
890
1094
|
const done2 = successCount.value + failureCount.value;
|
|
891
1095
|
return done2 / items.value.length;
|
|
892
1096
|
});
|
|
893
|
-
const done =
|
|
1097
|
+
const done = computed5(
|
|
894
1098
|
() => items.value.length > 0 && items.value.every((i) => i.status === "published" || i.status === "failed")
|
|
895
1099
|
);
|
|
896
1100
|
function setItems(next) {
|
|
@@ -948,7 +1152,7 @@ function useBulkPublish(options) {
|
|
|
948
1152
|
}
|
|
949
1153
|
|
|
950
1154
|
// src/vue/use-plan-editor.ts
|
|
951
|
-
import { computed as
|
|
1155
|
+
import { computed as computed6, ref as ref14 } from "vue";
|
|
952
1156
|
var PlannedOnlyFeatureError = class extends Error {
|
|
953
1157
|
constructor(violations) {
|
|
954
1158
|
super(
|
|
@@ -968,10 +1172,10 @@ function tierWeight(tier) {
|
|
|
968
1172
|
function usePlanEditor(manifest, options = {}) {
|
|
969
1173
|
const baseSet = new Set(options.baseFeatures ?? []);
|
|
970
1174
|
const nonRegressive = options.nonRegressive ?? true;
|
|
971
|
-
const selectedFeatures =
|
|
1175
|
+
const selectedFeatures = ref14(new Set(options.initialFeatures ?? []));
|
|
972
1176
|
const catalogFeatures = manifest.planCatalogSnapshot.features ?? [];
|
|
973
1177
|
const plannedOnlySet = new Set(catalogFeatures.filter((f) => f.plannedOnly).map((f) => f.key));
|
|
974
|
-
const availableFeatures =
|
|
1178
|
+
const availableFeatures = computed6(() => {
|
|
975
1179
|
return catalogFeatures.map((def) => {
|
|
976
1180
|
const isSelected = selectedFeatures.value.has(def.key);
|
|
977
1181
|
const isPlannedOnly = !!def.plannedOnly;
|
|
@@ -980,7 +1184,7 @@ function usePlanEditor(manifest, options = {}) {
|
|
|
980
1184
|
return { def, isSelected, isPlannedOnly, isInherited, canToggle };
|
|
981
1185
|
});
|
|
982
1186
|
});
|
|
983
|
-
const featuresByTier =
|
|
1187
|
+
const featuresByTier = computed6(() => {
|
|
984
1188
|
const groups = /* @__PURE__ */ new Map();
|
|
985
1189
|
for (const row of availableFeatures.value) {
|
|
986
1190
|
const tier = row.def.tier ?? "OTHER";
|
|
@@ -1025,12 +1229,12 @@ function usePlanEditor(manifest, options = {}) {
|
|
|
1025
1229
|
}
|
|
1026
1230
|
|
|
1027
1231
|
// src/vue/use-public-boot.ts
|
|
1028
|
-
import { ref as
|
|
1232
|
+
import { ref as ref15 } from "vue";
|
|
1029
1233
|
function usePublicBoot(options) {
|
|
1030
1234
|
const loader = new BootLoader(options);
|
|
1031
|
-
const boot =
|
|
1032
|
-
const loading =
|
|
1033
|
-
const error =
|
|
1235
|
+
const boot = ref15(null);
|
|
1236
|
+
const loading = ref15(false);
|
|
1237
|
+
const error = ref15(null);
|
|
1034
1238
|
async function load() {
|
|
1035
1239
|
loading.value = true;
|
|
1036
1240
|
error.value = null;
|
|
@@ -1047,27 +1251,27 @@ function usePublicBoot(options) {
|
|
|
1047
1251
|
}
|
|
1048
1252
|
|
|
1049
1253
|
// src/vue/use-discovery.ts
|
|
1050
|
-
import { ref as
|
|
1254
|
+
import { ref as ref16 } from "vue";
|
|
1051
1255
|
var DiscoveryLoadError = class extends Error {
|
|
1052
1256
|
constructor(status, message) {
|
|
1053
1257
|
super(message);
|
|
1054
1258
|
this.status = status;
|
|
1055
1259
|
this.name = "DiscoveryLoadError";
|
|
1260
|
+
markPlatformError(this);
|
|
1056
1261
|
}
|
|
1057
1262
|
status;
|
|
1058
1263
|
};
|
|
1059
1264
|
function useDiscovery(options) {
|
|
1060
|
-
const msg = useSaMessages("discovery");
|
|
1061
1265
|
if (!options?.endpoint) {
|
|
1062
1266
|
throw new Error(
|
|
1063
1267
|
'useDiscovery: `endpoint` is required (e.g. "/api/admin/discovery" or "/api/v1/admin/discovery"). The platform has no default because apps use different globalPrefix conventions.'
|
|
1064
1268
|
);
|
|
1065
1269
|
}
|
|
1066
1270
|
const http = options.http ?? defaultHttpClient();
|
|
1067
|
-
const snapshot =
|
|
1068
|
-
const etag =
|
|
1069
|
-
const loading =
|
|
1070
|
-
const error =
|
|
1271
|
+
const snapshot = ref16(null);
|
|
1272
|
+
const etag = ref16(null);
|
|
1273
|
+
const loading = ref16(false);
|
|
1274
|
+
const error = ref16(null);
|
|
1071
1275
|
async function fetchSnapshot(includeEtag) {
|
|
1072
1276
|
loading.value = true;
|
|
1073
1277
|
error.value = null;
|
|
@@ -1079,13 +1283,19 @@ function useDiscovery(options) {
|
|
|
1079
1283
|
headers["If-None-Match"] = etag.value;
|
|
1080
1284
|
}
|
|
1081
1285
|
const res = await http(options.endpoint, { method: "GET", headers });
|
|
1286
|
+
requireServerAnswer(
|
|
1287
|
+
res.status,
|
|
1288
|
+
"GET",
|
|
1289
|
+
options.endpoint,
|
|
1290
|
+
(diagnostic) => new DiscoveryLoadError(res.status, diagnostic)
|
|
1291
|
+
);
|
|
1082
1292
|
if (res.status === 304) {
|
|
1083
1293
|
return;
|
|
1084
1294
|
}
|
|
1085
1295
|
if (res.status !== 200) {
|
|
1086
1296
|
throw new DiscoveryLoadError(
|
|
1087
1297
|
res.status,
|
|
1088
|
-
|
|
1298
|
+
`Discovery endpoint responded with HTTP ${res.status}`
|
|
1089
1299
|
);
|
|
1090
1300
|
}
|
|
1091
1301
|
const body = await res.json();
|
|
@@ -1111,11 +1321,18 @@ function useDiscovery(options) {
|
|
|
1111
1321
|
const headers = { "content-type": "application/json" };
|
|
1112
1322
|
const token = options.getAuthToken?.();
|
|
1113
1323
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1114
|
-
const
|
|
1324
|
+
const rescanUrl = `${options.endpoint}/rescan`;
|
|
1325
|
+
const res = await http(rescanUrl, { method: "POST", headers });
|
|
1326
|
+
requireServerAnswer(
|
|
1327
|
+
res.status,
|
|
1328
|
+
"POST",
|
|
1329
|
+
rescanUrl,
|
|
1330
|
+
(diagnostic) => new DiscoveryLoadError(res.status, diagnostic)
|
|
1331
|
+
);
|
|
1115
1332
|
if (res.status !== 200 && res.status !== 201) {
|
|
1116
1333
|
throw new DiscoveryLoadError(
|
|
1117
1334
|
res.status,
|
|
1118
|
-
|
|
1335
|
+
`Discovery rescan responded with HTTP ${res.status}`
|
|
1119
1336
|
);
|
|
1120
1337
|
}
|
|
1121
1338
|
const body = await res.json();
|
|
@@ -1134,13 +1351,14 @@ function useDiscovery(options) {
|
|
|
1134
1351
|
}
|
|
1135
1352
|
|
|
1136
1353
|
// src/vue/use-catalog-entries.ts
|
|
1137
|
-
import { ref as
|
|
1354
|
+
import { ref as ref17 } from "vue";
|
|
1138
1355
|
var CatalogEntriesApiError = class extends Error {
|
|
1139
1356
|
constructor(status, body, message) {
|
|
1140
1357
|
super(message);
|
|
1141
1358
|
this.status = status;
|
|
1142
1359
|
this.body = body;
|
|
1143
1360
|
this.name = "CatalogEntriesApiError";
|
|
1361
|
+
markPlatformError(this);
|
|
1144
1362
|
}
|
|
1145
1363
|
status;
|
|
1146
1364
|
body;
|
|
@@ -1152,13 +1370,12 @@ function useCatalogEntries(options) {
|
|
|
1152
1370
|
if (!options?.projectKey) {
|
|
1153
1371
|
throw new Error("useCatalogEntries: `projectKey` is required.");
|
|
1154
1372
|
}
|
|
1155
|
-
const msg = useSaMessages("discovery");
|
|
1156
1373
|
const http = options.http ?? defaultHttpClient();
|
|
1157
|
-
const capabilities =
|
|
1158
|
-
const features =
|
|
1159
|
-
const quotas =
|
|
1160
|
-
const loading =
|
|
1161
|
-
const error =
|
|
1374
|
+
const capabilities = ref17([]);
|
|
1375
|
+
const features = ref17([]);
|
|
1376
|
+
const quotas = ref17([]);
|
|
1377
|
+
const loading = ref17(false);
|
|
1378
|
+
const error = ref17(null);
|
|
1162
1379
|
const base = `${options.adminEndpoint}/catalog`;
|
|
1163
1380
|
const pk = encodeURIComponent(options.projectKey);
|
|
1164
1381
|
function authHeaders() {
|
|
@@ -1166,18 +1383,25 @@ function useCatalogEntries(options) {
|
|
|
1166
1383
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1167
1384
|
}
|
|
1168
1385
|
async function fetchJson(url, init) {
|
|
1386
|
+
const method = init?.method ?? "GET";
|
|
1169
1387
|
const res = await http(url, {
|
|
1170
|
-
method
|
|
1388
|
+
method,
|
|
1171
1389
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1172
1390
|
body: init?.body
|
|
1173
1391
|
});
|
|
1392
|
+
requireServerAnswer(
|
|
1393
|
+
res.status,
|
|
1394
|
+
method,
|
|
1395
|
+
url,
|
|
1396
|
+
(diagnostic) => new CatalogEntriesApiError(res.status, null, diagnostic)
|
|
1397
|
+
);
|
|
1174
1398
|
if (res.status === 204) return null;
|
|
1175
1399
|
const body = await res.json().catch(() => null);
|
|
1176
1400
|
if (res.status >= 400) {
|
|
1177
1401
|
throw new CatalogEntriesApiError(
|
|
1178
1402
|
res.status,
|
|
1179
1403
|
body,
|
|
1180
|
-
|
|
1404
|
+
`Catalog entries API responded with HTTP ${res.status}`
|
|
1181
1405
|
);
|
|
1182
1406
|
}
|
|
1183
1407
|
return body;
|
|
@@ -1205,7 +1429,8 @@ function useCatalogEntries(options) {
|
|
|
1205
1429
|
`${base}/features/${encodeURIComponent(featureKey)}/review?projectKey=${pk}`,
|
|
1206
1430
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1207
1431
|
);
|
|
1208
|
-
if (!updated)
|
|
1432
|
+
if (!updated)
|
|
1433
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "Review returned no body"));
|
|
1209
1434
|
features.value = features.value.map((f) => f.featureKey === featureKey ? updated : f);
|
|
1210
1435
|
return updated;
|
|
1211
1436
|
}
|
|
@@ -1214,7 +1439,8 @@ function useCatalogEntries(options) {
|
|
|
1214
1439
|
`${base}/quotas/${encodeURIComponent(quotaKey)}/review?projectKey=${pk}`,
|
|
1215
1440
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1216
1441
|
);
|
|
1217
|
-
if (!updated)
|
|
1442
|
+
if (!updated)
|
|
1443
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "Review returned no body"));
|
|
1218
1444
|
quotas.value = quotas.value.map((q) => q.quotaKey === quotaKey ? updated : q);
|
|
1219
1445
|
return updated;
|
|
1220
1446
|
}
|
|
@@ -1223,7 +1449,8 @@ function useCatalogEntries(options) {
|
|
|
1223
1449
|
`${base}/features/${encodeURIComponent(featureKey)}/i18n?projectKey=${pk}`,
|
|
1224
1450
|
{ method: "PATCH", body: JSON.stringify({ i18n }) }
|
|
1225
1451
|
);
|
|
1226
|
-
if (!updated)
|
|
1452
|
+
if (!updated)
|
|
1453
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "i18n returned no body"));
|
|
1227
1454
|
features.value = features.value.map((f) => f.featureKey === featureKey ? updated : f);
|
|
1228
1455
|
return updated;
|
|
1229
1456
|
}
|
|
@@ -1232,7 +1459,8 @@ function useCatalogEntries(options) {
|
|
|
1232
1459
|
`${base}/quotas/${encodeURIComponent(quotaKey)}/i18n?projectKey=${pk}`,
|
|
1233
1460
|
{ method: "PATCH", body: JSON.stringify({ i18n }) }
|
|
1234
1461
|
);
|
|
1235
|
-
if (!updated)
|
|
1462
|
+
if (!updated)
|
|
1463
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "i18n returned no body"));
|
|
1236
1464
|
quotas.value = quotas.value.map((q) => q.quotaKey === quotaKey ? updated : q);
|
|
1237
1465
|
return updated;
|
|
1238
1466
|
}
|
|
@@ -1241,7 +1469,8 @@ function useCatalogEntries(options) {
|
|
|
1241
1469
|
`${base}/features/${encodeURIComponent(featureKey)}?projectKey=${pk}`,
|
|
1242
1470
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1243
1471
|
);
|
|
1244
|
-
if (!updated)
|
|
1472
|
+
if (!updated)
|
|
1473
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "Base returned no body"));
|
|
1245
1474
|
features.value = features.value.map((f) => f.featureKey === featureKey ? updated : f);
|
|
1246
1475
|
return updated;
|
|
1247
1476
|
}
|
|
@@ -1250,7 +1479,8 @@ function useCatalogEntries(options) {
|
|
|
1250
1479
|
`${base}/quotas/${encodeURIComponent(quotaKey)}?projectKey=${pk}`,
|
|
1251
1480
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1252
1481
|
);
|
|
1253
|
-
if (!updated)
|
|
1482
|
+
if (!updated)
|
|
1483
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "Base returned no body"));
|
|
1254
1484
|
quotas.value = quotas.value.map((q) => q.quotaKey === quotaKey ? updated : q);
|
|
1255
1485
|
return updated;
|
|
1256
1486
|
}
|
|
@@ -1259,7 +1489,8 @@ function useCatalogEntries(options) {
|
|
|
1259
1489
|
method: "POST",
|
|
1260
1490
|
body: JSON.stringify({ snapshot })
|
|
1261
1491
|
});
|
|
1262
|
-
if (!result)
|
|
1492
|
+
if (!result)
|
|
1493
|
+
throw markEmptyResponse(new CatalogEntriesApiError(0, null, "Sync returned no body"));
|
|
1263
1494
|
await load();
|
|
1264
1495
|
return result;
|
|
1265
1496
|
}
|
|
@@ -1284,13 +1515,14 @@ function useCatalogEntries(options) {
|
|
|
1284
1515
|
}
|
|
1285
1516
|
|
|
1286
1517
|
// src/vue/use-bundles.ts
|
|
1287
|
-
import { ref as
|
|
1518
|
+
import { ref as ref18 } from "vue";
|
|
1288
1519
|
var BundlesApiError = class extends Error {
|
|
1289
1520
|
constructor(status, body, message) {
|
|
1290
1521
|
super(message);
|
|
1291
1522
|
this.status = status;
|
|
1292
1523
|
this.body = body;
|
|
1293
1524
|
this.name = "BundlesApiError";
|
|
1525
|
+
markPlatformError(this);
|
|
1294
1526
|
}
|
|
1295
1527
|
status;
|
|
1296
1528
|
body;
|
|
@@ -1305,20 +1537,27 @@ function useBundles(options) {
|
|
|
1305
1537
|
throw new Error("useBundles: `projectKey` is required.");
|
|
1306
1538
|
}
|
|
1307
1539
|
const http = options.http ?? defaultHttpClient();
|
|
1308
|
-
const bundles =
|
|
1309
|
-
const loading =
|
|
1310
|
-
const error =
|
|
1540
|
+
const bundles = ref18([]);
|
|
1541
|
+
const loading = ref18(false);
|
|
1542
|
+
const error = ref18(null);
|
|
1311
1543
|
const baseUrl = `${options.adminEndpoint}/catalog/bundles`;
|
|
1312
1544
|
function authHeaders() {
|
|
1313
1545
|
const token = options.getAuthToken?.();
|
|
1314
1546
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1315
1547
|
}
|
|
1316
1548
|
async function fetchJson(url, init) {
|
|
1549
|
+
const method = init?.method ?? "GET";
|
|
1317
1550
|
const res = await http(url, {
|
|
1318
|
-
method
|
|
1551
|
+
method,
|
|
1319
1552
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1320
1553
|
body: init?.body
|
|
1321
1554
|
});
|
|
1555
|
+
requireServerAnswer(
|
|
1556
|
+
res.status,
|
|
1557
|
+
method,
|
|
1558
|
+
url,
|
|
1559
|
+
(diagnostic) => new BundlesApiError(res.status, null, diagnostic)
|
|
1560
|
+
);
|
|
1322
1561
|
if (res.status === 204) return null;
|
|
1323
1562
|
const body = await res.json().catch(() => null);
|
|
1324
1563
|
if (res.status >= 400) {
|
|
@@ -1349,7 +1588,8 @@ function useBundles(options) {
|
|
|
1349
1588
|
method: "POST",
|
|
1350
1589
|
body: JSON.stringify(data)
|
|
1351
1590
|
});
|
|
1352
|
-
if (!created)
|
|
1591
|
+
if (!created)
|
|
1592
|
+
throw markEmptyResponse(new BundlesApiError(0, null, "Create returned no body"));
|
|
1353
1593
|
bundles.value = [...bundles.value, created];
|
|
1354
1594
|
return created;
|
|
1355
1595
|
}
|
|
@@ -1358,7 +1598,8 @@ function useBundles(options) {
|
|
|
1358
1598
|
method: "PATCH",
|
|
1359
1599
|
body: JSON.stringify(data)
|
|
1360
1600
|
});
|
|
1361
|
-
if (!updated)
|
|
1601
|
+
if (!updated)
|
|
1602
|
+
throw markEmptyResponse(new BundlesApiError(0, null, "Update returned no body"));
|
|
1362
1603
|
bundles.value = bundles.value.map((b) => b.id === bundleId ? updated : b);
|
|
1363
1604
|
return updated;
|
|
1364
1605
|
}
|
|
@@ -1379,9 +1620,9 @@ function useBundleVersions(options) {
|
|
|
1379
1620
|
throw new Error("useBundleVersions: `bundleId` is required.");
|
|
1380
1621
|
}
|
|
1381
1622
|
const http = options.http ?? defaultHttpClient();
|
|
1382
|
-
const versions =
|
|
1383
|
-
const loading =
|
|
1384
|
-
const error =
|
|
1623
|
+
const versions = ref18([]);
|
|
1624
|
+
const loading = ref18(false);
|
|
1625
|
+
const error = ref18(null);
|
|
1385
1626
|
const bundleVersionsUrl = `${options.adminEndpoint}/catalog/bundles/${options.bundleId}/versions`;
|
|
1386
1627
|
const versionUrlBase = `${options.adminEndpoint}/catalog/bundle-versions`;
|
|
1387
1628
|
function authHeaders() {
|
|
@@ -1389,11 +1630,18 @@ function useBundleVersions(options) {
|
|
|
1389
1630
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1390
1631
|
}
|
|
1391
1632
|
async function fetchJson(url, init) {
|
|
1633
|
+
const method = init?.method ?? "GET";
|
|
1392
1634
|
const res = await http(url, {
|
|
1393
|
-
method
|
|
1635
|
+
method,
|
|
1394
1636
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1395
1637
|
body: init?.body
|
|
1396
1638
|
});
|
|
1639
|
+
requireServerAnswer(
|
|
1640
|
+
res.status,
|
|
1641
|
+
method,
|
|
1642
|
+
url,
|
|
1643
|
+
(diagnostic) => new BundlesApiError(res.status, null, diagnostic)
|
|
1644
|
+
);
|
|
1397
1645
|
if (res.status === 204) return null;
|
|
1398
1646
|
const body = await res.json().catch(() => null);
|
|
1399
1647
|
if (res.status >= 400) {
|
|
@@ -1422,7 +1670,8 @@ function useBundleVersions(options) {
|
|
|
1422
1670
|
method: "POST",
|
|
1423
1671
|
body: JSON.stringify(data)
|
|
1424
1672
|
});
|
|
1425
|
-
if (!result)
|
|
1673
|
+
if (!result)
|
|
1674
|
+
throw markEmptyResponse(new BundlesApiError(0, null, "CreateDraft returned no body"));
|
|
1426
1675
|
versions.value = [...versions.value, result.bundleVersion];
|
|
1427
1676
|
return result;
|
|
1428
1677
|
}
|
|
@@ -1431,7 +1680,8 @@ function useBundleVersions(options) {
|
|
|
1431
1680
|
`${versionUrlBase}/${versionId}`,
|
|
1432
1681
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1433
1682
|
);
|
|
1434
|
-
if (!result)
|
|
1683
|
+
if (!result)
|
|
1684
|
+
throw markEmptyResponse(new BundlesApiError(0, null, "UpdateDraft returned no body"));
|
|
1435
1685
|
versions.value = versions.value.map((v) => v.id === versionId ? result.bundleVersion : v);
|
|
1436
1686
|
return result;
|
|
1437
1687
|
}
|
|
@@ -1440,7 +1690,8 @@ function useBundleVersions(options) {
|
|
|
1440
1690
|
`${versionUrlBase}/${versionId}/publish`,
|
|
1441
1691
|
{ method: "POST", body: JSON.stringify(opts) }
|
|
1442
1692
|
);
|
|
1443
|
-
if (!result)
|
|
1693
|
+
if (!result)
|
|
1694
|
+
throw markEmptyResponse(new BundlesApiError(0, null, "Publish returned no body"));
|
|
1444
1695
|
await load();
|
|
1445
1696
|
return result;
|
|
1446
1697
|
}
|
|
@@ -1455,7 +1706,7 @@ function useBundleVersions(options) {
|
|
|
1455
1706
|
}
|
|
1456
1707
|
|
|
1457
1708
|
// src/vue/use-bundle-versions-map.ts
|
|
1458
|
-
import { ref as
|
|
1709
|
+
import { ref as ref19, watch as watch5 } from "vue";
|
|
1459
1710
|
function useBundleVersionsMap(options) {
|
|
1460
1711
|
if (!options?.adminEndpoint) {
|
|
1461
1712
|
throw new Error("useBundleVersionsMap: `adminEndpoint` is required.");
|
|
@@ -1464,9 +1715,9 @@ function useBundleVersionsMap(options) {
|
|
|
1464
1715
|
throw new Error("useBundleVersionsMap: `bundles` is required.");
|
|
1465
1716
|
}
|
|
1466
1717
|
const http = options.http ?? defaultHttpClient();
|
|
1467
|
-
const versionsByBundle =
|
|
1468
|
-
const loading =
|
|
1469
|
-
const error =
|
|
1718
|
+
const versionsByBundle = ref19({});
|
|
1719
|
+
const loading = ref19(false);
|
|
1720
|
+
const error = ref19(null);
|
|
1470
1721
|
function authHeaders() {
|
|
1471
1722
|
const token = options.getAuthToken?.();
|
|
1472
1723
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
@@ -1516,7 +1767,7 @@ function useBundleVersionsMap(options) {
|
|
|
1516
1767
|
console.warn(`useBundleVersionsMap: refreshOne('${bundleId}') failed`, err);
|
|
1517
1768
|
}
|
|
1518
1769
|
}
|
|
1519
|
-
|
|
1770
|
+
watch5(
|
|
1520
1771
|
() => options.bundles.value.map((b) => b.id).join(","),
|
|
1521
1772
|
() => {
|
|
1522
1773
|
if (options.bundles.value.length > 0) void refresh();
|
|
@@ -1528,13 +1779,14 @@ function useBundleVersionsMap(options) {
|
|
|
1528
1779
|
}
|
|
1529
1780
|
|
|
1530
1781
|
// src/vue/use-tenant-subscription-bundles.ts
|
|
1531
|
-
import { ref as
|
|
1782
|
+
import { ref as ref20 } from "vue";
|
|
1532
1783
|
var TenantSubscriptionBundlesApiError = class extends Error {
|
|
1533
1784
|
constructor(status, body, message) {
|
|
1534
1785
|
super(message);
|
|
1535
1786
|
this.status = status;
|
|
1536
1787
|
this.body = body;
|
|
1537
1788
|
this.name = "TenantSubscriptionBundlesApiError";
|
|
1789
|
+
markPlatformError(this);
|
|
1538
1790
|
}
|
|
1539
1791
|
status;
|
|
1540
1792
|
body;
|
|
@@ -1547,19 +1799,26 @@ function useTenantSubscriptionBundles(options) {
|
|
|
1547
1799
|
}
|
|
1548
1800
|
const http = options.http ?? defaultHttpClient();
|
|
1549
1801
|
const baseUrl = `${options.billingEndpoint}/billing/subscription-bundles`;
|
|
1550
|
-
const bundles =
|
|
1551
|
-
const loading =
|
|
1552
|
-
const error =
|
|
1802
|
+
const bundles = ref20([]);
|
|
1803
|
+
const loading = ref20(false);
|
|
1804
|
+
const error = ref20(null);
|
|
1553
1805
|
function authHeaders() {
|
|
1554
1806
|
const token = options.getAuthToken?.();
|
|
1555
1807
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1556
1808
|
}
|
|
1557
1809
|
async function fetchJson(url, init) {
|
|
1810
|
+
const method = init?.method ?? "GET";
|
|
1558
1811
|
const res = await http(url, {
|
|
1559
|
-
method
|
|
1812
|
+
method,
|
|
1560
1813
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1561
1814
|
body: init?.body
|
|
1562
1815
|
});
|
|
1816
|
+
requireServerAnswer(
|
|
1817
|
+
res.status,
|
|
1818
|
+
method,
|
|
1819
|
+
url,
|
|
1820
|
+
(diagnostic) => new TenantSubscriptionBundlesApiError(res.status, null, diagnostic)
|
|
1821
|
+
);
|
|
1563
1822
|
if (res.status === 204) return null;
|
|
1564
1823
|
const body = await res.json().catch(() => null);
|
|
1565
1824
|
if (res.status >= 400) {
|
|
@@ -1589,7 +1848,9 @@ function useTenantSubscriptionBundles(options) {
|
|
|
1589
1848
|
body: JSON.stringify(data)
|
|
1590
1849
|
});
|
|
1591
1850
|
if (!result) {
|
|
1592
|
-
throw
|
|
1851
|
+
throw markEmptyResponse(
|
|
1852
|
+
new TenantSubscriptionBundlesApiError(0, null, "add returned no body")
|
|
1853
|
+
);
|
|
1593
1854
|
}
|
|
1594
1855
|
const hydrated = rehydrateDates(result);
|
|
1595
1856
|
bundles.value = [hydrated, ...bundles.value];
|
|
@@ -1601,7 +1862,9 @@ function useTenantSubscriptionBundles(options) {
|
|
|
1601
1862
|
{ method: "DELETE", body: JSON.stringify(opts) }
|
|
1602
1863
|
);
|
|
1603
1864
|
if (!result) {
|
|
1604
|
-
throw
|
|
1865
|
+
throw markEmptyResponse(
|
|
1866
|
+
new TenantSubscriptionBundlesApiError(0, null, "cancel returned no body")
|
|
1867
|
+
);
|
|
1605
1868
|
}
|
|
1606
1869
|
const hydrated = rehydrateDates(result);
|
|
1607
1870
|
bundles.value = bundles.value.map((b) => b.id === subscriptionBundleId ? hydrated : b);
|
|
@@ -1623,13 +1886,14 @@ function rehydrateDates(raw) {
|
|
|
1623
1886
|
}
|
|
1624
1887
|
|
|
1625
1888
|
// src/vue/use-marketing-projections.ts
|
|
1626
|
-
import { ref as
|
|
1889
|
+
import { ref as ref21 } from "vue";
|
|
1627
1890
|
var MarketingProjectionsApiError = class extends Error {
|
|
1628
1891
|
constructor(status, body, message) {
|
|
1629
1892
|
super(message);
|
|
1630
1893
|
this.status = status;
|
|
1631
1894
|
this.body = body;
|
|
1632
1895
|
this.name = "MarketingProjectionsApiError";
|
|
1896
|
+
markPlatformError(this);
|
|
1633
1897
|
}
|
|
1634
1898
|
status;
|
|
1635
1899
|
body;
|
|
@@ -1641,12 +1905,11 @@ function useMarketingProjections(options) {
|
|
|
1641
1905
|
if (!options?.filter?.projectKey) {
|
|
1642
1906
|
throw new Error("useMarketingProjections: `filter.projectKey` is required.");
|
|
1643
1907
|
}
|
|
1644
|
-
const msg = useSaMessages("marketing");
|
|
1645
1908
|
const http = options.http ?? defaultHttpClient();
|
|
1646
|
-
const projections =
|
|
1647
|
-
const filter =
|
|
1648
|
-
const loading =
|
|
1649
|
-
const error =
|
|
1909
|
+
const projections = ref21([]);
|
|
1910
|
+
const filter = ref21({ ...options.filter });
|
|
1911
|
+
const loading = ref21(false);
|
|
1912
|
+
const error = ref21(null);
|
|
1650
1913
|
const baseUrl = `${options.adminEndpoint}/catalog/marketing-projections`;
|
|
1651
1914
|
function authHeaders() {
|
|
1652
1915
|
const token = options.getAuthToken?.();
|
|
@@ -1662,18 +1925,25 @@ function useMarketingProjections(options) {
|
|
|
1662
1925
|
return `${baseUrl}?${params.toString()}`;
|
|
1663
1926
|
}
|
|
1664
1927
|
async function fetchJson(url, init) {
|
|
1928
|
+
const method = init?.method ?? "GET";
|
|
1665
1929
|
const res = await http(url, {
|
|
1666
|
-
method
|
|
1930
|
+
method,
|
|
1667
1931
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1668
1932
|
body: init?.body
|
|
1669
1933
|
});
|
|
1934
|
+
requireServerAnswer(
|
|
1935
|
+
res.status,
|
|
1936
|
+
method,
|
|
1937
|
+
url,
|
|
1938
|
+
(diagnostic) => new MarketingProjectionsApiError(res.status, null, diagnostic)
|
|
1939
|
+
);
|
|
1670
1940
|
if (res.status === 204) return null;
|
|
1671
1941
|
const body = await res.json().catch(() => null);
|
|
1672
1942
|
if (res.status >= 400) {
|
|
1673
1943
|
throw new MarketingProjectionsApiError(
|
|
1674
1944
|
res.status,
|
|
1675
1945
|
body,
|
|
1676
|
-
|
|
1946
|
+
`Marketing projections API responded with HTTP ${res.status}`
|
|
1677
1947
|
);
|
|
1678
1948
|
}
|
|
1679
1949
|
return body;
|
|
@@ -1700,7 +1970,9 @@ function useMarketingProjections(options) {
|
|
|
1700
1970
|
body: JSON.stringify(data)
|
|
1701
1971
|
});
|
|
1702
1972
|
if (!created) {
|
|
1703
|
-
throw
|
|
1973
|
+
throw markEmptyResponse(
|
|
1974
|
+
new MarketingProjectionsApiError(0, null, "Create returned no body")
|
|
1975
|
+
);
|
|
1704
1976
|
}
|
|
1705
1977
|
await load();
|
|
1706
1978
|
return created;
|
|
@@ -1711,7 +1983,9 @@ function useMarketingProjections(options) {
|
|
|
1711
1983
|
body: JSON.stringify(data)
|
|
1712
1984
|
});
|
|
1713
1985
|
if (!updated) {
|
|
1714
|
-
throw
|
|
1986
|
+
throw markEmptyResponse(
|
|
1987
|
+
new MarketingProjectionsApiError(0, null, "Update returned no body")
|
|
1988
|
+
);
|
|
1715
1989
|
}
|
|
1716
1990
|
projections.value = projections.value.map((p) => p.id === id ? updated : p);
|
|
1717
1991
|
return updated;
|
|
@@ -1727,13 +2001,14 @@ function useMarketingProjections(options) {
|
|
|
1727
2001
|
}
|
|
1728
2002
|
|
|
1729
2003
|
// src/vue/use-promotions.ts
|
|
1730
|
-
import { ref as
|
|
2004
|
+
import { ref as ref22 } from "vue";
|
|
1731
2005
|
var PromotionsApiError = class extends Error {
|
|
1732
2006
|
constructor(status, body, message) {
|
|
1733
2007
|
super(message);
|
|
1734
2008
|
this.status = status;
|
|
1735
2009
|
this.body = body;
|
|
1736
2010
|
this.name = "PromotionsApiError";
|
|
2011
|
+
markPlatformError(this);
|
|
1737
2012
|
}
|
|
1738
2013
|
status;
|
|
1739
2014
|
body;
|
|
@@ -1745,11 +2020,10 @@ function usePromotions(options) {
|
|
|
1745
2020
|
if (!options?.projectKey) {
|
|
1746
2021
|
throw new Error("usePromotions: `projectKey` is required.");
|
|
1747
2022
|
}
|
|
1748
|
-
const msg = useSaMessages("promos");
|
|
1749
2023
|
const http = options.http ?? defaultHttpClient();
|
|
1750
|
-
const promotions =
|
|
1751
|
-
const loading =
|
|
1752
|
-
const error =
|
|
2024
|
+
const promotions = ref22([]);
|
|
2025
|
+
const loading = ref22(false);
|
|
2026
|
+
const error = ref22(null);
|
|
1753
2027
|
const baseUrl = `${options.adminEndpoint}/catalog/promotions`;
|
|
1754
2028
|
const pk = encodeURIComponent(options.projectKey);
|
|
1755
2029
|
function authHeaders() {
|
|
@@ -1757,18 +2031,25 @@ function usePromotions(options) {
|
|
|
1757
2031
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1758
2032
|
}
|
|
1759
2033
|
async function fetchJson(url, init) {
|
|
2034
|
+
const method = init?.method ?? "GET";
|
|
1760
2035
|
const res = await http(url, {
|
|
1761
|
-
method
|
|
2036
|
+
method,
|
|
1762
2037
|
headers: { "content-type": "application/json", ...authHeaders(), ...init?.headers },
|
|
1763
2038
|
body: init?.body
|
|
1764
2039
|
});
|
|
2040
|
+
requireServerAnswer(
|
|
2041
|
+
res.status,
|
|
2042
|
+
method,
|
|
2043
|
+
url,
|
|
2044
|
+
(diagnostic) => new PromotionsApiError(res.status, null, diagnostic)
|
|
2045
|
+
);
|
|
1765
2046
|
if (res.status === 204) return null;
|
|
1766
2047
|
const body = await res.json().catch(() => null);
|
|
1767
2048
|
if (res.status >= 400) {
|
|
1768
2049
|
throw new PromotionsApiError(
|
|
1769
2050
|
res.status,
|
|
1770
2051
|
body,
|
|
1771
|
-
|
|
2052
|
+
`Promotions API responded with HTTP ${res.status}`
|
|
1772
2053
|
);
|
|
1773
2054
|
}
|
|
1774
2055
|
return body;
|
|
@@ -1790,7 +2071,8 @@ function usePromotions(options) {
|
|
|
1790
2071
|
method: "POST",
|
|
1791
2072
|
body: JSON.stringify(data)
|
|
1792
2073
|
});
|
|
1793
|
-
if (!created)
|
|
2074
|
+
if (!created)
|
|
2075
|
+
throw markEmptyResponse(new PromotionsApiError(0, null, "Create returned no body"));
|
|
1794
2076
|
promotions.value = [...promotions.value, created];
|
|
1795
2077
|
return created;
|
|
1796
2078
|
}
|
|
@@ -1799,7 +2081,8 @@ function usePromotions(options) {
|
|
|
1799
2081
|
method: "PATCH",
|
|
1800
2082
|
body: JSON.stringify(data)
|
|
1801
2083
|
});
|
|
1802
|
-
if (!updated)
|
|
2084
|
+
if (!updated)
|
|
2085
|
+
throw markEmptyResponse(new PromotionsApiError(0, null, "Update returned no body"));
|
|
1803
2086
|
promotions.value = promotions.value.map((p) => p.id === id ? updated : p);
|
|
1804
2087
|
return updated;
|
|
1805
2088
|
}
|
|
@@ -1814,13 +2097,14 @@ function usePromotions(options) {
|
|
|
1814
2097
|
}
|
|
1815
2098
|
|
|
1816
2099
|
// src/vue/use-plans.ts
|
|
1817
|
-
import { ref as
|
|
2100
|
+
import { ref as ref23 } from "vue";
|
|
1818
2101
|
var PlansApiError = class extends Error {
|
|
1819
2102
|
constructor(status, body, message) {
|
|
1820
2103
|
super(message);
|
|
1821
2104
|
this.status = status;
|
|
1822
2105
|
this.body = body;
|
|
1823
2106
|
this.name = "PlansApiError";
|
|
2107
|
+
markPlatformError(this);
|
|
1824
2108
|
}
|
|
1825
2109
|
status;
|
|
1826
2110
|
body;
|
|
@@ -1835,18 +2119,19 @@ function usePlans(options) {
|
|
|
1835
2119
|
throw new Error("usePlans: `projectKey` is required.");
|
|
1836
2120
|
}
|
|
1837
2121
|
const http = options.http ?? defaultHttpClient();
|
|
1838
|
-
const plans =
|
|
1839
|
-
const loading =
|
|
1840
|
-
const error =
|
|
1841
|
-
const tenantCountsByPlanKey =
|
|
2122
|
+
const plans = ref23([]);
|
|
2123
|
+
const loading = ref23(false);
|
|
2124
|
+
const error = ref23(null);
|
|
2125
|
+
const tenantCountsByPlanKey = ref23({});
|
|
1842
2126
|
const baseUrl = `${options.adminEndpoint}/catalog/plans`;
|
|
1843
2127
|
function authHeaders() {
|
|
1844
2128
|
const token = options.getAuthToken?.();
|
|
1845
2129
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1846
2130
|
}
|
|
1847
2131
|
async function fetchJson(url, init) {
|
|
2132
|
+
const method = init?.method ?? "GET";
|
|
1848
2133
|
const res = await http(url, {
|
|
1849
|
-
method
|
|
2134
|
+
method,
|
|
1850
2135
|
headers: {
|
|
1851
2136
|
"content-type": "application/json",
|
|
1852
2137
|
...authHeaders(),
|
|
@@ -1854,6 +2139,12 @@ function usePlans(options) {
|
|
|
1854
2139
|
},
|
|
1855
2140
|
body: init?.body
|
|
1856
2141
|
});
|
|
2142
|
+
requireServerAnswer(
|
|
2143
|
+
res.status,
|
|
2144
|
+
method,
|
|
2145
|
+
url,
|
|
2146
|
+
(diagnostic) => new PlansApiError(res.status, null, diagnostic)
|
|
2147
|
+
);
|
|
1857
2148
|
if (res.status === 204) return null;
|
|
1858
2149
|
const body = await res.json().catch(() => null);
|
|
1859
2150
|
if (res.status >= 400) {
|
|
@@ -1894,7 +2185,8 @@ function usePlans(options) {
|
|
|
1894
2185
|
method: "POST",
|
|
1895
2186
|
body: JSON.stringify(data)
|
|
1896
2187
|
});
|
|
1897
|
-
if (!created)
|
|
2188
|
+
if (!created)
|
|
2189
|
+
throw markEmptyResponse(new PlansApiError(0, null, "Create returned no body"));
|
|
1898
2190
|
plans.value = [...plans.value, created];
|
|
1899
2191
|
return created;
|
|
1900
2192
|
}
|
|
@@ -1903,7 +2195,8 @@ function usePlans(options) {
|
|
|
1903
2195
|
method: "PATCH",
|
|
1904
2196
|
body: JSON.stringify(data)
|
|
1905
2197
|
});
|
|
1906
|
-
if (!updated)
|
|
2198
|
+
if (!updated)
|
|
2199
|
+
throw markEmptyResponse(new PlansApiError(0, null, "Update returned no body"));
|
|
1907
2200
|
plans.value = plans.value.map((p) => p.id === planId ? updated : p);
|
|
1908
2201
|
return updated;
|
|
1909
2202
|
}
|
|
@@ -1939,9 +2232,9 @@ function usePlanVersions(options) {
|
|
|
1939
2232
|
throw new Error("usePlanVersions: `planId` is required.");
|
|
1940
2233
|
}
|
|
1941
2234
|
const http = options.http ?? defaultHttpClient();
|
|
1942
|
-
const versions =
|
|
1943
|
-
const loading =
|
|
1944
|
-
const error =
|
|
2235
|
+
const versions = ref23([]);
|
|
2236
|
+
const loading = ref23(false);
|
|
2237
|
+
const error = ref23(null);
|
|
1945
2238
|
const planVersionsUrl = `${options.adminEndpoint}/catalog/plans/${options.planId}/versions`;
|
|
1946
2239
|
const versionUrlBase = `${options.adminEndpoint}/catalog/plan-versions`;
|
|
1947
2240
|
function authHeaders() {
|
|
@@ -1949,8 +2242,9 @@ function usePlanVersions(options) {
|
|
|
1949
2242
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
1950
2243
|
}
|
|
1951
2244
|
async function fetchJson(url, init) {
|
|
2245
|
+
const method = init?.method ?? "GET";
|
|
1952
2246
|
const res = await http(url, {
|
|
1953
|
-
method
|
|
2247
|
+
method,
|
|
1954
2248
|
headers: {
|
|
1955
2249
|
"content-type": "application/json",
|
|
1956
2250
|
...authHeaders(),
|
|
@@ -1958,6 +2252,12 @@ function usePlanVersions(options) {
|
|
|
1958
2252
|
},
|
|
1959
2253
|
body: init?.body
|
|
1960
2254
|
});
|
|
2255
|
+
requireServerAnswer(
|
|
2256
|
+
res.status,
|
|
2257
|
+
method,
|
|
2258
|
+
url,
|
|
2259
|
+
(diagnostic) => new PlansApiError(res.status, null, diagnostic)
|
|
2260
|
+
);
|
|
1961
2261
|
if (res.status === 204) return null;
|
|
1962
2262
|
const body = await res.json().catch(() => null);
|
|
1963
2263
|
if (res.status >= 400) {
|
|
@@ -1986,7 +2286,8 @@ function usePlanVersions(options) {
|
|
|
1986
2286
|
method: "POST",
|
|
1987
2287
|
body: JSON.stringify(data)
|
|
1988
2288
|
});
|
|
1989
|
-
if (!result)
|
|
2289
|
+
if (!result)
|
|
2290
|
+
throw markEmptyResponse(new PlansApiError(0, null, "CreateDraft returned no body"));
|
|
1990
2291
|
versions.value = [...versions.value, result.planVersion];
|
|
1991
2292
|
return result;
|
|
1992
2293
|
}
|
|
@@ -1995,7 +2296,8 @@ function usePlanVersions(options) {
|
|
|
1995
2296
|
`${versionUrlBase}/${versionId}`,
|
|
1996
2297
|
{ method: "PATCH", body: JSON.stringify(data) }
|
|
1997
2298
|
);
|
|
1998
|
-
if (!result)
|
|
2299
|
+
if (!result)
|
|
2300
|
+
throw markEmptyResponse(new PlansApiError(0, null, "UpdateDraft returned no body"));
|
|
1999
2301
|
versions.value = versions.value.map((v) => v.id === versionId ? result.planVersion : v);
|
|
2000
2302
|
return result;
|
|
2001
2303
|
}
|
|
@@ -2004,7 +2306,8 @@ function usePlanVersions(options) {
|
|
|
2004
2306
|
`${versionUrlBase}/${versionId}/publish`,
|
|
2005
2307
|
{ method: "POST", body: JSON.stringify(opts) }
|
|
2006
2308
|
);
|
|
2007
|
-
if (!result)
|
|
2309
|
+
if (!result)
|
|
2310
|
+
throw markEmptyResponse(new PlansApiError(0, null, "Publish returned no body"));
|
|
2008
2311
|
versions.value = versions.value.map((v) => v.id === versionId ? result.planVersion : v);
|
|
2009
2312
|
return result;
|
|
2010
2313
|
}
|
|
@@ -2017,7 +2320,8 @@ function usePlanVersions(options) {
|
|
|
2017
2320
|
`${versionUrlBase}/${versionId}/terminate`,
|
|
2018
2321
|
{ method: "POST", body: JSON.stringify({ endsAt }) }
|
|
2019
2322
|
);
|
|
2020
|
-
if (!updated)
|
|
2323
|
+
if (!updated)
|
|
2324
|
+
throw markEmptyResponse(new PlansApiError(0, null, "Terminate returned no body"));
|
|
2021
2325
|
versions.value = versions.value.map((v) => v.id === versionId ? updated : v);
|
|
2022
2326
|
return updated;
|
|
2023
2327
|
}
|
|
@@ -2038,7 +2342,7 @@ function usePlanVersions(options) {
|
|
|
2038
2342
|
}
|
|
2039
2343
|
|
|
2040
2344
|
// src/vue/use-live-plan-versions.ts
|
|
2041
|
-
import { ref as
|
|
2345
|
+
import { ref as ref24, watch as watch6 } from "vue";
|
|
2042
2346
|
function useLivePlanVersions(options) {
|
|
2043
2347
|
if (!options?.adminEndpoint) {
|
|
2044
2348
|
throw new Error("useLivePlanVersions: `adminEndpoint` is required.");
|
|
@@ -2047,9 +2351,9 @@ function useLivePlanVersions(options) {
|
|
|
2047
2351
|
throw new Error("useLivePlanVersions: `plans` is required.");
|
|
2048
2352
|
}
|
|
2049
2353
|
const http = options.http ?? defaultHttpClient();
|
|
2050
|
-
const livePlanVersions =
|
|
2051
|
-
const loading =
|
|
2052
|
-
const error =
|
|
2354
|
+
const livePlanVersions = ref24({});
|
|
2355
|
+
const loading = ref24(false);
|
|
2356
|
+
const error = ref24(null);
|
|
2053
2357
|
function authHeaders() {
|
|
2054
2358
|
const token = options.getAuthToken?.();
|
|
2055
2359
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
@@ -2091,7 +2395,7 @@ function useLivePlanVersions(options) {
|
|
|
2091
2395
|
loading.value = false;
|
|
2092
2396
|
}
|
|
2093
2397
|
}
|
|
2094
|
-
|
|
2398
|
+
watch6(
|
|
2095
2399
|
() => options.plans.value.map((p) => p.id).join(","),
|
|
2096
2400
|
() => {
|
|
2097
2401
|
if (options.plans.value.length > 0) void refresh();
|
|
@@ -2113,12 +2417,12 @@ function findLatestLive(versions) {
|
|
|
2113
2417
|
}
|
|
2114
2418
|
|
|
2115
2419
|
// src/vue/use-manifest.ts
|
|
2116
|
-
import { ref as
|
|
2420
|
+
import { ref as ref25 } from "vue";
|
|
2117
2421
|
function useManifest(options) {
|
|
2118
2422
|
const loader = new ManifestLoader(options);
|
|
2119
|
-
const manifest =
|
|
2120
|
-
const loading =
|
|
2121
|
-
const error =
|
|
2423
|
+
const manifest = ref25(null);
|
|
2424
|
+
const loading = ref25(false);
|
|
2425
|
+
const error = ref25(null);
|
|
2122
2426
|
async function load() {
|
|
2123
2427
|
loading.value = true;
|
|
2124
2428
|
error.value = null;
|
|
@@ -2144,24 +2448,24 @@ function useManifest(options) {
|
|
|
2144
2448
|
}
|
|
2145
2449
|
|
|
2146
2450
|
// src/vue/use-nav.ts
|
|
2147
|
-
import { computed as
|
|
2451
|
+
import { computed as computed7 } from "vue";
|
|
2148
2452
|
function useNav(manifest, options = {}) {
|
|
2149
2453
|
const { locale } = useSuperAdminI18n();
|
|
2150
|
-
const activeLocale =
|
|
2151
|
-
const routes =
|
|
2454
|
+
const activeLocale = computed7(() => options.locale ?? locale.value);
|
|
2455
|
+
const routes = computed7(() => {
|
|
2152
2456
|
if (!manifest.value) return [];
|
|
2153
2457
|
return buildRoutes(manifest.value, { ...options, locale: activeLocale.value });
|
|
2154
2458
|
});
|
|
2155
|
-
const sidebar =
|
|
2459
|
+
const sidebar = computed7(
|
|
2156
2460
|
() => buildSidebar(routes.value, defaultSectionOrder(activeLocale.value))
|
|
2157
2461
|
);
|
|
2158
2462
|
return { routes, sidebar };
|
|
2159
2463
|
}
|
|
2160
2464
|
|
|
2161
2465
|
// src/vue/use-actions.ts
|
|
2162
|
-
import { computed as
|
|
2466
|
+
import { computed as computed8 } from "vue";
|
|
2163
2467
|
function useActions(manifest, actions) {
|
|
2164
|
-
const registry =
|
|
2468
|
+
const registry = computed8(() => {
|
|
2165
2469
|
if (!manifest.value) return null;
|
|
2166
2470
|
return new ActionRegistry(manifest.value, actions);
|
|
2167
2471
|
});
|
|
@@ -2169,18 +2473,18 @@ function useActions(manifest, actions) {
|
|
|
2169
2473
|
}
|
|
2170
2474
|
|
|
2171
2475
|
// src/vue/use-tenant-action-flow.ts
|
|
2172
|
-
import { computed as
|
|
2476
|
+
import { computed as computed9 } from "vue";
|
|
2173
2477
|
function useTenantActionFlow(manifest, providers = {}) {
|
|
2174
2478
|
const handlers = useSuperAdminActions();
|
|
2175
2479
|
const msg = useSaMessages("tenants");
|
|
2176
|
-
const registry =
|
|
2480
|
+
const registry = computed9(() => {
|
|
2177
2481
|
if (!manifest.value) return null;
|
|
2178
2482
|
return new ActionRegistry(manifest.value, handlers);
|
|
2179
2483
|
});
|
|
2180
|
-
const orphanedDefs =
|
|
2484
|
+
const orphanedDefs = computed9(
|
|
2181
2485
|
() => registry.value ? registry.value.listOrphanedDefs() : []
|
|
2182
2486
|
);
|
|
2183
|
-
const availableActions =
|
|
2487
|
+
const availableActions = computed9(() => {
|
|
2184
2488
|
const m = manifest.value;
|
|
2185
2489
|
const reg = registry.value;
|
|
2186
2490
|
if (!m || !reg) return [];
|
|
@@ -2253,7 +2557,7 @@ async function runFlow(def, row, registry, providers, successTemplate) {
|
|
|
2253
2557
|
}
|
|
2254
2558
|
|
|
2255
2559
|
// src/vue/use-platform-tenant-actions.ts
|
|
2256
|
-
import { computed as
|
|
2560
|
+
import { computed as computed10, ref as ref26 } from "vue";
|
|
2257
2561
|
var DEFAULT_VISIBLE_FOR_ROW = (def, row) => {
|
|
2258
2562
|
if (def.actionKey === "tenants.suspend") return row.isActive;
|
|
2259
2563
|
if (def.actionKey === "tenants.reactivate") return !row.isActive;
|
|
@@ -2289,7 +2593,7 @@ function usePlatformTenantActions(options) {
|
|
|
2289
2593
|
const iconForActionKey = options.iconForActionKey ?? DEFAULT_ICON_FOR_ACTION_KEY;
|
|
2290
2594
|
const toneForActionKey = options.toneForActionKey ?? DEFAULT_TONE_FOR_ACTION_KEY;
|
|
2291
2595
|
const visibleForRow = options.visibleForRow ?? DEFAULT_VISIBLE_FOR_ROW;
|
|
2292
|
-
const mfa =
|
|
2596
|
+
const mfa = ref26({ show: false, description: "", error: "" });
|
|
2293
2597
|
let pendingMfaResolve = null;
|
|
2294
2598
|
function showMfaDialog(def, ctx) {
|
|
2295
2599
|
return new Promise((resolve) => {
|
|
@@ -2314,7 +2618,7 @@ function usePlatformTenantActions(options) {
|
|
|
2314
2618
|
pendingMfaResolve(null);
|
|
2315
2619
|
}
|
|
2316
2620
|
}
|
|
2317
|
-
const confirmDialog =
|
|
2621
|
+
const confirmDialog = ref26({
|
|
2318
2622
|
show: false,
|
|
2319
2623
|
def: null,
|
|
2320
2624
|
row: null
|
|
@@ -2356,7 +2660,7 @@ function usePlatformTenantActions(options) {
|
|
|
2356
2660
|
},
|
|
2357
2661
|
visibleForRow
|
|
2358
2662
|
});
|
|
2359
|
-
const manifestActions =
|
|
2663
|
+
const manifestActions = computed10(
|
|
2360
2664
|
() => flow.availableActions.value.map((def) => ({
|
|
2361
2665
|
id: def.id,
|
|
2362
2666
|
label: def.label,
|
|
@@ -2370,7 +2674,7 @@ function usePlatformTenantActions(options) {
|
|
|
2370
2674
|
}
|
|
2371
2675
|
}))
|
|
2372
2676
|
);
|
|
2373
|
-
const realOrphans =
|
|
2677
|
+
const realOrphans = computed10(() => {
|
|
2374
2678
|
const caps = options.manifest.value?.capabilities ?? {};
|
|
2375
2679
|
const defs = options.manifest.value?.tenants?.actions ?? [];
|
|
2376
2680
|
const defByActionKey = new Map(defs.map((d) => [d.actionKey, d]));
|
|
@@ -2395,12 +2699,12 @@ function usePlatformTenantActions(options) {
|
|
|
2395
2699
|
}
|
|
2396
2700
|
|
|
2397
2701
|
// src/vue/use-batch-columns.ts
|
|
2398
|
-
import { ref as
|
|
2702
|
+
import { ref as ref27, watch as watch7 } from "vue";
|
|
2399
2703
|
function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
2400
2704
|
const fetcher = new BatchColumnFetcher(options);
|
|
2401
|
-
const data =
|
|
2402
|
-
const loading =
|
|
2403
|
-
const error =
|
|
2705
|
+
const data = ref27({});
|
|
2706
|
+
const loading = ref27(false);
|
|
2707
|
+
const error = ref27(null);
|
|
2404
2708
|
async function load() {
|
|
2405
2709
|
if (!manifest.value || tenantIds.value.length === 0) {
|
|
2406
2710
|
data.value = {};
|
|
@@ -2417,45 +2721,21 @@ function useBatchColumns(manifest, tenantIds, options = {}) {
|
|
|
2417
2721
|
loading.value = false;
|
|
2418
2722
|
}
|
|
2419
2723
|
}
|
|
2420
|
-
|
|
2724
|
+
watch7([manifest, tenantIds], () => {
|
|
2421
2725
|
void load();
|
|
2422
2726
|
});
|
|
2423
2727
|
return { data, loading, error, reload: load };
|
|
2424
2728
|
}
|
|
2425
2729
|
|
|
2426
|
-
// src/vue/platform-loaders.ts
|
|
2427
|
-
function resolveEndpoints(endpoints) {
|
|
2428
|
-
return {
|
|
2429
|
-
apiBase: endpoints.apiBase,
|
|
2430
|
-
publicBootEndpoint: endpoints.publicBootEndpoint ?? `${endpoints.apiBase}/boot`,
|
|
2431
|
-
manifestEndpoint: endpoints.manifestEndpoint ?? `${endpoints.apiBase}/manifest`
|
|
2432
|
-
};
|
|
2433
|
-
}
|
|
2434
|
-
function createPlatformLoaders(options) {
|
|
2435
|
-
const resolved = resolveEndpoints(options.endpoints);
|
|
2436
|
-
const bootLoader = new BootLoader({
|
|
2437
|
-
endpoint: resolved.publicBootEndpoint,
|
|
2438
|
-
http: options.http
|
|
2439
|
-
});
|
|
2440
|
-
const manifestLoader = new ManifestLoader({
|
|
2441
|
-
endpoint: resolved.manifestEndpoint,
|
|
2442
|
-
http: options.http,
|
|
2443
|
-
storage: options.storage,
|
|
2444
|
-
storageKeyPrefix: options.storageKeyPrefix,
|
|
2445
|
-
getAuthToken: options.getAuthToken
|
|
2446
|
-
});
|
|
2447
|
-
return { bootLoader, manifestLoader };
|
|
2448
|
-
}
|
|
2449
|
-
|
|
2450
2730
|
// src/vue/manifest-store-factory.ts
|
|
2451
2731
|
import { defineStore } from "pinia";
|
|
2452
|
-
import { ref as
|
|
2732
|
+
import { ref as ref28 } from "vue";
|
|
2453
2733
|
function createManifestStore(options) {
|
|
2454
2734
|
return defineStore(options.id ?? "admin-manifest", () => {
|
|
2455
|
-
const manifest =
|
|
2456
|
-
const loading =
|
|
2457
|
-
const error =
|
|
2458
|
-
const loaded =
|
|
2735
|
+
const manifest = ref28(null);
|
|
2736
|
+
const loading = ref28(false);
|
|
2737
|
+
const error = ref28(null);
|
|
2738
|
+
const loaded = ref28(false);
|
|
2459
2739
|
let inflight = null;
|
|
2460
2740
|
async function load() {
|
|
2461
2741
|
loading.value = true;
|
|
@@ -2887,6 +3167,7 @@ export {
|
|
|
2887
3167
|
ALL_ROWS,
|
|
2888
3168
|
ActionDefNotInManifestError,
|
|
2889
3169
|
ActionRegistry,
|
|
3170
|
+
AdminError,
|
|
2890
3171
|
BatchColumnDriftError,
|
|
2891
3172
|
BatchColumnFetcher,
|
|
2892
3173
|
BootLoadError,
|
|
@@ -2907,6 +3188,10 @@ export {
|
|
|
2907
3188
|
IDENTITY_ACCENT_VALUES,
|
|
2908
3189
|
IDENTITY_NEUTRAL,
|
|
2909
3190
|
IDENTITY_NEUTRAL_VALUE,
|
|
3191
|
+
LIST_FIRST_PAGE,
|
|
3192
|
+
LIST_PAGE_SIZE_DEFAULT,
|
|
3193
|
+
LIST_PAGE_SIZE_MAX,
|
|
3194
|
+
LIST_PAGINATION_PARAMS,
|
|
2910
3195
|
ManifestLoadError,
|
|
2911
3196
|
ManifestLoader,
|
|
2912
3197
|
MarketingProjectionsApiError,
|
|
@@ -2916,15 +3201,18 @@ export {
|
|
|
2916
3201
|
PlansApiError,
|
|
2917
3202
|
ProjectPageHost,
|
|
2918
3203
|
PromotionsApiError,
|
|
3204
|
+
SA_COLOR_SCHEMES,
|
|
2919
3205
|
SA_INTL_LOCALES,
|
|
2920
3206
|
SA_LOCALES,
|
|
2921
3207
|
SA_LOCALE_LABELS,
|
|
2922
3208
|
SA_LOCALE_STORAGE_KEY,
|
|
2923
3209
|
SA_MESSAGES,
|
|
2924
3210
|
SA_THEME_KEY,
|
|
3211
|
+
SA_THEME_STORAGE_KEY,
|
|
2925
3212
|
SERVER_PAGE_SIZE_OPTIONS,
|
|
2926
3213
|
SUPER_ADMIN_ACTIONS_KEY,
|
|
2927
3214
|
SUPER_ADMIN_BRAND_KEY,
|
|
3215
|
+
SUPER_ADMIN_CONFIRM_KEY,
|
|
2928
3216
|
SUPER_ADMIN_ENDPOINTS_KEY,
|
|
2929
3217
|
SUPER_ADMIN_EXTENSIONS_KEY,
|
|
2930
3218
|
SUPER_ADMIN_HTTP_KEY,
|
|
@@ -2933,19 +3221,28 @@ export {
|
|
|
2933
3221
|
SUPER_ADMIN_MANIFEST_CLEAR_CACHE_KEY,
|
|
2934
3222
|
SUPER_ADMIN_MANIFEST_KEY,
|
|
2935
3223
|
SUPER_ADMIN_NOTIFY_KEY,
|
|
3224
|
+
SUPER_ADMIN_RESOURCES_KEY,
|
|
2936
3225
|
TenantSubscriptionBundlesApiError,
|
|
3226
|
+
adminErrorMessage,
|
|
3227
|
+
auditResource,
|
|
3228
|
+
bindResource,
|
|
2937
3229
|
buildFeatureRegistry,
|
|
2938
3230
|
buildFeatureRouterGuard,
|
|
2939
3231
|
buildNavigationGuard,
|
|
2940
3232
|
buildQuotaRegistry,
|
|
2941
3233
|
buildRoutes,
|
|
2942
3234
|
buildSidebar,
|
|
3235
|
+
clampListPage,
|
|
3236
|
+
clampListPageSize,
|
|
2943
3237
|
countPlans,
|
|
2944
3238
|
createAdminResourceClient,
|
|
2945
3239
|
createAdminRoutes,
|
|
3240
|
+
createAxiosHttpClient,
|
|
3241
|
+
createFetchHttpClient,
|
|
2946
3242
|
createManifestStore,
|
|
2947
3243
|
createPlatformLoaders,
|
|
2948
3244
|
createProjectPageHostRoute,
|
|
3245
|
+
createResourceRegistry,
|
|
2949
3246
|
createSaCatalog,
|
|
2950
3247
|
createSaTheme,
|
|
2951
3248
|
createSuperAdminI18n,
|
|
@@ -2955,30 +3252,57 @@ export {
|
|
|
2955
3252
|
defaultSectionOrder,
|
|
2956
3253
|
defaultTenantPlanSectionI18n,
|
|
2957
3254
|
defaultToneForActionKey,
|
|
3255
|
+
defineListOp,
|
|
2958
3256
|
defineMessages,
|
|
3257
|
+
defineResource,
|
|
3258
|
+
filterQueryString,
|
|
2959
3259
|
formatCurrency,
|
|
2960
3260
|
formatMessage,
|
|
2961
3261
|
getJson,
|
|
2962
3262
|
identityAccentAt,
|
|
2963
3263
|
identityAccentFor,
|
|
2964
3264
|
identityChipStyle,
|
|
3265
|
+
isAdminError,
|
|
3266
|
+
isAxiosNoResponseError,
|
|
2965
3267
|
isCurrentlyValid,
|
|
3268
|
+
isEmptyResponse,
|
|
2966
3269
|
isExpired,
|
|
2967
3270
|
isFutureScheduled,
|
|
3271
|
+
isPlatformError,
|
|
2968
3272
|
isProductionBoot,
|
|
2969
3273
|
isSaBuiltinLocale,
|
|
3274
|
+
isSentInQuery,
|
|
3275
|
+
isTransportFailure,
|
|
3276
|
+
listUrl,
|
|
3277
|
+
markEmptyResponse,
|
|
3278
|
+
markPlatformError,
|
|
3279
|
+
markTransportFailure,
|
|
2970
3280
|
mergeMessages,
|
|
2971
3281
|
planChangeWizardI18n,
|
|
3282
|
+
planVersionsResource,
|
|
3283
|
+
plansResource,
|
|
3284
|
+
platformResources,
|
|
2972
3285
|
postJson,
|
|
2973
3286
|
provideEntitlement,
|
|
3287
|
+
readErrorCode,
|
|
3288
|
+
readErrorDetail,
|
|
3289
|
+
readListPage,
|
|
3290
|
+
requestJson,
|
|
3291
|
+
requestJsonBody,
|
|
3292
|
+
requireServerAnswer,
|
|
2974
3293
|
resolveExtension,
|
|
2975
3294
|
resolveLoginBranding,
|
|
2976
3295
|
resolveMessages,
|
|
2977
3296
|
resolvePlans,
|
|
3297
|
+
resolveSuperAdminEndpoints,
|
|
3298
|
+
tenantsResource,
|
|
3299
|
+
toAdminError,
|
|
2978
3300
|
todayIsoDate,
|
|
2979
3301
|
trimTrailingSlashes,
|
|
2980
3302
|
useActions,
|
|
2981
3303
|
useApiList,
|
|
3304
|
+
useAsyncAction,
|
|
3305
|
+
useAsyncData,
|
|
2982
3306
|
useAuditEntries,
|
|
2983
3307
|
useBatchColumns,
|
|
2984
3308
|
useBulkPublish,
|
|
@@ -3000,6 +3324,8 @@ export {
|
|
|
3000
3324
|
usePlatformTenantActions,
|
|
3001
3325
|
usePromotions,
|
|
3002
3326
|
usePublicBoot,
|
|
3327
|
+
useResource,
|
|
3328
|
+
useResourceList,
|
|
3003
3329
|
useSaMessages,
|
|
3004
3330
|
useSaTheme,
|
|
3005
3331
|
useSubscriptionDraft,
|