@betterportal/config-manager 10.1.61 → 10.1.63
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/lib/.bsb/clients/service-betterportal-config-manager.d.ts +1 -1
- package/lib/.bsb/clients/service-betterportal-config-manager.js +1 -1
- package/lib/bp-contracts/org.betterportal.config-manager.json +4137 -2714
- package/lib/plugins/service-betterportal-config-manager/.bp-generated/registry.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/.bp-generated/registry.js +32 -89
- package/lib/plugins/service-betterportal-config-manager/.bp-generated/registry.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.d.ts +100 -14
- package/lib/plugins/service-betterportal-config-manager/adminApi.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.js +111 -86
- package/lib/plugins/service-betterportal-config-manager/adminApi.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bootstrapEndpoint.js +12 -12
- package/lib/plugins/service-betterportal-config-manager/bootstrapEndpoint.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/GET.d.ts +3 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/GET.js +3 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_renderer.bootstrap5/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_renderer.bootstrap5/GET.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_renderer.bootstrap5/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/route.impl.d.ts +18 -12
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/route.impl.js +21 -18
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/GET.d.ts +3 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/GET.js +3 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/route.impl.js +5 -5
- package/lib/plugins/service-betterportal-config-manager/bp-routes/config/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/route.impl.js +2 -2
- package/lib/plugins/service-betterportal-config-manager/bp-routes/fragments/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/route.impl.js +4 -4
- package/lib/plugins/service-betterportal-config-manager/bp-routes/menu/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/route.impl.js +4 -4
- package/lib/plugins/service-betterportal-config-manager/bp-routes/preview/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.js +45 -33
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.d.ts +10 -4
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.js +11 -8
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/route.impl.js +7 -7
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/GET.js +2 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/route.impl.js +9 -9
- package/lib/plugins/service-betterportal-config-manager/bp-routes/settings/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/DELETE.d.ts +6 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/DELETE.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/DELETE.js +8 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/DELETE.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/GET.d.ts +6 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/GET.js +8 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/POST.d.ts +6 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/POST.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/POST.js +8 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/POST.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/PUT.d.ts +6 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/PUT.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/PUT.js +8 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/PUT.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/index.d.ts +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/index.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.d.ts +5 -6
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.js +29 -38
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/cpBootstrap.d.ts +2 -1
- package/lib/plugins/service-betterportal-config-manager/cpBootstrap.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/cpBootstrap.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.js +30 -22
- package/lib/plugins/service-betterportal-config-manager/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/menuEditor.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/menuEditor.js +3 -2
- package/lib/plugins/service-betterportal-config-manager/menuEditor.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/setupTokens.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/setupTokens.js +9 -2
- package/lib/plugins/service-betterportal-config-manager/setupTokens.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/core.d.ts +17 -0
- package/lib/plugins/service-betterportal-config-manager/storage/core.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/core.js +96 -0
- package/lib/plugins/service-betterportal-config-manager/storage/core.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/file.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/file.js +2 -2
- package/lib/plugins/service-betterportal-config-manager/storage/file.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/index.js +2 -2
- package/lib/plugins/service-betterportal-config-manager/storage/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/postgres.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/postgres.js +2 -2
- package/lib/plugins/service-betterportal-config-manager/storage/postgres.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.d.ts +22 -14
- package/lib/plugins/service-betterportal-config-manager/syncApi.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.js +167 -90
- package/lib/plugins/service-betterportal-config-manager/syncApi.js.map +1 -1
- package/lib/schemas/service-betterportal-config-manager.json +1 -1
- package/lib/schemas/service-betterportal-config-manager.plugin.json +1 -1
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as av from "anyvali";
|
|
2
|
-
import { AppAuthRoleSchema, eventHeaders, htmlResponse, jsonResponse, resolveEmbeddedRequestContext, signServiceConfigTicket, uuidv7, BetterPortalThemeConfigSchema } from "@betterportal/framework";
|
|
2
|
+
import { AppAuthRoleSchema, eventHeaders, htmlResponse, jsonResponse, resolveEmbeddedRequestContext, signServiceConfigTicket, uuidv7, BetterPortalMenuItemSchema, BetterPortalThemeConfigSchema } from "@betterportal/framework";
|
|
3
3
|
import { generateApiKey, hashApiKey } from "./storage/index.js";
|
|
4
4
|
import { getManifestCache } from "./syncApi.js";
|
|
5
5
|
import { apiRoutePath, appRoutePatternKey, isApiRoute, pageRoutePath } from "./routeMounts.js";
|
|
@@ -90,6 +90,19 @@ function requiredRouteString(body, key, label) {
|
|
|
90
90
|
return { error: `${label} is required.` };
|
|
91
91
|
return { value };
|
|
92
92
|
}
|
|
93
|
+
function normalizeMenuItem(raw) {
|
|
94
|
+
const item = raw && typeof raw === "object" ? raw : {};
|
|
95
|
+
return BetterPortalMenuItemSchema.parse({
|
|
96
|
+
id: typeof item.id === "string" ? item.id : uuidv7(),
|
|
97
|
+
type: item.type === "group" ? "group" : "link",
|
|
98
|
+
title: typeof item.title === "string" ? item.title : undefined,
|
|
99
|
+
icon: typeof item.icon === "string" ? item.icon : undefined,
|
|
100
|
+
routeId: typeof item.routeId === "string" ? item.routeId : undefined,
|
|
101
|
+
href: typeof item.href === "string" ? item.href : undefined,
|
|
102
|
+
enabled: item.enabled !== false,
|
|
103
|
+
children: Array.isArray(item.children) ? item.children.map(normalizeMenuItem) : []
|
|
104
|
+
});
|
|
105
|
+
}
|
|
93
106
|
function routesReloadPath(appId, apiServiceId) {
|
|
94
107
|
return `/routes?appId=${encodeURIComponent(appId)}${apiServiceId ? `&apiServiceId=${encodeURIComponent(apiServiceId)}` : ""}`;
|
|
95
108
|
}
|
|
@@ -163,15 +176,13 @@ function validateRouteParamMapping(appPath, servicePath, fixedParams, paramsSche
|
|
|
163
176
|
}
|
|
164
177
|
return undefined;
|
|
165
178
|
}
|
|
166
|
-
function routeMethodsFromManifest(methods) {
|
|
167
|
-
const normalized = (methods ?? []).filter((method) => method === "GET" || method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE" || method === "OPTIONS");
|
|
168
|
-
return normalized.length ? normalized : ["GET"];
|
|
169
|
-
}
|
|
170
179
|
function hasPageRenderer(view) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
180
|
+
return (view.operations ?? []).some((operation) => {
|
|
181
|
+
if (operation.method !== "GET" || operation.renderable === false)
|
|
182
|
+
return false;
|
|
183
|
+
const renderers = operation.html?.renderers;
|
|
184
|
+
return renderers && Object.values(renderers).some((renderer) => Array.isArray(renderer.renderModes) && renderer.renderModes.includes("page"));
|
|
185
|
+
});
|
|
175
186
|
}
|
|
176
187
|
function appMatchesTenantUrl(app, tenantUrl) {
|
|
177
188
|
let host = "";
|
|
@@ -279,21 +290,22 @@ function automationServiceCatalog(config, appDef) {
|
|
|
279
290
|
...resource,
|
|
280
291
|
url: `${service.url.replace(/\/+$/, "")}/.well-known/bp/resources/${encodeURIComponent(resource.id)}`
|
|
281
292
|
})),
|
|
282
|
-
actions: Object.values(manifest?.viewIndex ?? {}).
|
|
293
|
+
actions: Object.values(manifest?.viewIndex ?? {}).flatMap((view) => view.operations.map((operation) => ({
|
|
283
294
|
viewId: view.viewId,
|
|
295
|
+
operationId: operation.operationId,
|
|
284
296
|
path: view.path,
|
|
285
|
-
|
|
286
|
-
title:
|
|
287
|
-
renderable:
|
|
288
|
-
permissions:
|
|
289
|
-
role:
|
|
290
|
-
chrome:
|
|
291
|
-
dependencies:
|
|
292
|
-
schemas:
|
|
293
|
-
raw:
|
|
294
|
-
apiContracts:
|
|
295
|
-
demoScenarios:
|
|
296
|
-
}))
|
|
297
|
+
method: operation.method,
|
|
298
|
+
title: operation.title,
|
|
299
|
+
renderable: operation.renderable,
|
|
300
|
+
permissions: operation.permissions,
|
|
301
|
+
role: operation.role,
|
|
302
|
+
chrome: operation.chrome,
|
|
303
|
+
dependencies: operation.dependencies,
|
|
304
|
+
schemas: operation.schemas,
|
|
305
|
+
raw: operation.raw === true,
|
|
306
|
+
apiContracts: operation.apiContracts,
|
|
307
|
+
demoScenarios: operation.demoScenarios
|
|
308
|
+
})))
|
|
297
309
|
};
|
|
298
310
|
})
|
|
299
311
|
};
|
|
@@ -320,7 +332,7 @@ export function renderAutomationLlmsApi(catalog) {
|
|
|
320
332
|
if (service.actions.length === 0)
|
|
321
333
|
lines.push("No synced actions.", "");
|
|
322
334
|
for (const action of service.actions) {
|
|
323
|
-
lines.push(`#### ${action.title}`, "", `- View ID: \`${action.viewId}\``, `-
|
|
335
|
+
lines.push(`#### ${action.title}`, "", `- View ID: \`${action.viewId}\``, `- Operation ID: \`${action.operationId}\``, `- Method: \`${action.method}\``, `- URL: ${base}${action.path}`, `- Renderable: ${action.renderable ? "yes" : "no"}`, `- Required permissions: \`${JSON.stringify(action.permissions)}\``, "");
|
|
324
336
|
if (action.schemas)
|
|
325
337
|
lines.push("```json", JSON.stringify(action.schemas, null, 2), "```", "");
|
|
326
338
|
if (action.demoScenarios.length)
|
|
@@ -336,8 +348,14 @@ function parseRouteCreateBody(body) {
|
|
|
336
348
|
const viewId = requiredRouteString(body, "viewId", "View");
|
|
337
349
|
if (viewId.error)
|
|
338
350
|
return { error: viewId.error };
|
|
351
|
+
const operationId = requiredRouteString(body, "operationId", "Operation");
|
|
352
|
+
if (operationId.error)
|
|
353
|
+
return { error: operationId.error };
|
|
339
354
|
const manifestView = getManifestCache().get(serviceId.value)?.viewIndex[viewId.value];
|
|
340
|
-
const
|
|
355
|
+
const manifestOperation = manifestView?.operations.find((operation) => operation.operationId === operationId.value);
|
|
356
|
+
if (manifestView && !manifestOperation)
|
|
357
|
+
return { error: "Selected operation is not available for this view." };
|
|
358
|
+
const renderable = manifestOperation?.method === "GET" && manifestOperation.renderable === true;
|
|
341
359
|
const manifest = getManifestCache().get(serviceId.value);
|
|
342
360
|
const servicePathVariant = trimmedString(body, "servicePathVariant") ?? manifestView?.path ?? `/${viewId.value}`;
|
|
343
361
|
if (manifestView && ![manifestView.path, ...manifestView.pathVariants].includes(servicePathVariant)) {
|
|
@@ -357,7 +375,7 @@ function parseRouteCreateBody(body) {
|
|
|
357
375
|
const mappingError = validateRouteParamMapping(path.value, serviceRoutePath, fixedParams, manifestView?.paramsSchema);
|
|
358
376
|
if (mappingError)
|
|
359
377
|
return { error: mappingError };
|
|
360
|
-
const title = renderable ? requiredRouteString(body, "title", "Display title") : { value:
|
|
378
|
+
const title = renderable ? requiredRouteString(body, "title", "Display title") : { value: manifestOperation?.title ?? operationId.value };
|
|
361
379
|
if (title.error)
|
|
362
380
|
return { error: title.error };
|
|
363
381
|
const route = {
|
|
@@ -369,7 +387,7 @@ function parseRouteCreateBody(body) {
|
|
|
369
387
|
...(Object.keys(fixedParams).length > 0 ? { fixedParams } : {}),
|
|
370
388
|
title: title.value,
|
|
371
389
|
enabled: true,
|
|
372
|
-
|
|
390
|
+
operations: [operationId.value]
|
|
373
391
|
};
|
|
374
392
|
if (manifestView?.path)
|
|
375
393
|
route.targetPath = serviceRoutePath;
|
|
@@ -383,7 +401,7 @@ function serviceRouteTargetKey(route) {
|
|
|
383
401
|
?? route.targetPath
|
|
384
402
|
?? getManifestCache().get(route.serviceId)?.viewIndex[route.viewId]?.path;
|
|
385
403
|
return servicePath
|
|
386
|
-
? `${route.serviceId}\u0000${route.viewId}\u0000${appRoutePatternKey(servicePath)}`
|
|
404
|
+
? `${route.serviceId}\u0000${route.viewId}\u0000${[...route.operations].sort().join(",")}\u0000${appRoutePatternKey(servicePath)}`
|
|
387
405
|
: undefined;
|
|
388
406
|
}
|
|
389
407
|
function hasDuplicateServiceRouteTarget(appDef, route, excludeRouteId) {
|
|
@@ -453,22 +471,26 @@ function addRouteDependencies(appDef, route) {
|
|
|
453
471
|
const view = manifest?.viewIndex[route.viewId];
|
|
454
472
|
if (!manifest || !view)
|
|
455
473
|
return;
|
|
456
|
-
|
|
457
|
-
|
|
474
|
+
const operations = new Map(Object.values(manifest.viewIndex).flatMap((candidateView) => candidateView.operations.map((operation) => [operation.operationId, { view: candidateView, operation }])));
|
|
475
|
+
const dependencies = view.operations
|
|
476
|
+
.filter((operation) => route.operations.includes(operation.operationId))
|
|
477
|
+
.flatMap((operation) => operation.dependencies);
|
|
478
|
+
for (const dependencyOperationId of dependencies) {
|
|
479
|
+
const dependency = operations.get(dependencyOperationId);
|
|
458
480
|
if (!dependency)
|
|
459
481
|
continue;
|
|
460
|
-
if (appDef.routes.some((candidate) => candidate.serviceId === route.serviceId && candidate.
|
|
482
|
+
if (appDef.routes.some((candidate) => candidate.serviceId === route.serviceId && candidate.operations.includes(dependencyOperationId)))
|
|
461
483
|
continue;
|
|
462
484
|
appDef.routes.push({
|
|
463
485
|
id: uuidv7(),
|
|
464
486
|
kind: "api",
|
|
465
|
-
path: apiRoutePath(manifest.serviceId, dependency.path),
|
|
487
|
+
path: apiRoutePath(manifest.serviceId, dependency.view.path),
|
|
466
488
|
serviceId: route.serviceId,
|
|
467
|
-
viewId:
|
|
468
|
-
targetPath: dependency.path,
|
|
469
|
-
title: dependency.
|
|
489
|
+
viewId: dependency.view.viewId,
|
|
490
|
+
targetPath: dependency.view.path,
|
|
491
|
+
title: dependency.operation.title,
|
|
470
492
|
enabled: true,
|
|
471
|
-
|
|
493
|
+
operations: [dependencyOperationId]
|
|
472
494
|
});
|
|
473
495
|
}
|
|
474
496
|
}
|
|
@@ -1527,16 +1549,16 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1527
1549
|
type: av.literal("auth"),
|
|
1528
1550
|
mutation: av.object({
|
|
1529
1551
|
roles: av.array(AppAuthRoleSchema)
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1552
|
+
})
|
|
1553
|
+
}),
|
|
1532
1554
|
av.object({
|
|
1533
1555
|
tenantId: av.string().minLength(1),
|
|
1534
1556
|
appId: av.string().minLength(1),
|
|
1535
1557
|
type: av.literal("theme"),
|
|
1536
1558
|
mutation: av.object({
|
|
1537
1559
|
themeConfig: BetterPortalThemeConfigSchema
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1560
|
+
})
|
|
1561
|
+
})
|
|
1540
1562
|
]);
|
|
1541
1563
|
const getAppOr404 = async (appId) => {
|
|
1542
1564
|
const config = await store.loadConfig();
|
|
@@ -1979,10 +2001,19 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1979
2001
|
return validationError(event, "View is required.");
|
|
1980
2002
|
route.viewId = viewId;
|
|
1981
2003
|
}
|
|
2004
|
+
if (body.operationId !== undefined) {
|
|
2005
|
+
const operationId = trimmedString(body, "operationId");
|
|
2006
|
+
if (!operationId)
|
|
2007
|
+
return validationError(event, "Operation is required.");
|
|
2008
|
+
route.operations = [operationId];
|
|
2009
|
+
}
|
|
1982
2010
|
const manifest = getManifestCache().get(route.serviceId);
|
|
1983
2011
|
const manifestView = manifest?.viewIndex[route.viewId];
|
|
1984
2012
|
if (manifestView) {
|
|
1985
|
-
const
|
|
2013
|
+
const manifestOperation = manifestView.operations.find((operation) => route.operations.includes(operation.operationId));
|
|
2014
|
+
if (!manifestOperation)
|
|
2015
|
+
return validationError(event, "Selected operation is not available for this view.");
|
|
2016
|
+
const routeIdentityChanged = body.serviceId !== undefined || body.viewId !== undefined || body.operationId !== undefined;
|
|
1986
2017
|
const requestedServicePath = trimmedString(body, "servicePathVariant")
|
|
1987
2018
|
?? (routeIdentityChanged ? undefined : route.servicePathVariant)
|
|
1988
2019
|
?? manifestView.path;
|
|
@@ -1993,7 +2024,8 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1993
2024
|
if (servicePathError)
|
|
1994
2025
|
return validationError(event, servicePathError);
|
|
1995
2026
|
const submittedFixed = fixedParamsFromBody(body);
|
|
1996
|
-
const
|
|
2027
|
+
const pageRenderable = manifestOperation.method === "GET" && manifestOperation.renderable;
|
|
2028
|
+
const mappedAppPath = !pageRenderable
|
|
1997
2029
|
? apiRoutePath(manifest?.serviceId ?? route.serviceId, requestedServicePath)
|
|
1998
2030
|
: route.path;
|
|
1999
2031
|
const appParams = new Set(routeParamNames(mappedAppPath));
|
|
@@ -2009,12 +2041,11 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2009
2041
|
route.fixedParams = fixedParams;
|
|
2010
2042
|
else
|
|
2011
2043
|
delete route.fixedParams;
|
|
2012
|
-
route.methods = routeMethodsFromManifest(manifestView.methods);
|
|
2013
2044
|
route.targetPath = requestedServicePath;
|
|
2014
|
-
if (
|
|
2045
|
+
if (!pageRenderable) {
|
|
2015
2046
|
route.kind = "api";
|
|
2016
2047
|
route.path = apiRoutePath(manifest?.serviceId ?? route.serviceId, requestedServicePath);
|
|
2017
|
-
route.title =
|
|
2048
|
+
route.title = manifestOperation.title;
|
|
2018
2049
|
delete route.query;
|
|
2019
2050
|
}
|
|
2020
2051
|
else {
|
|
@@ -2030,7 +2061,8 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2030
2061
|
}
|
|
2031
2062
|
if (body.query !== undefined) {
|
|
2032
2063
|
const query = trimmedString(body, "query");
|
|
2033
|
-
|
|
2064
|
+
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && operation.method === "GET" && operation.renderable);
|
|
2065
|
+
if (isApiRoute(route, renderable))
|
|
2034
2066
|
delete route.query;
|
|
2035
2067
|
else if (query)
|
|
2036
2068
|
route.query = query.replace(/^\?+/, "");
|
|
@@ -2041,7 +2073,8 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2041
2073
|
const title = trimmedString(body, "title");
|
|
2042
2074
|
if (!title)
|
|
2043
2075
|
return validationError(event, "Display title is required.");
|
|
2044
|
-
|
|
2076
|
+
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && operation.method === "GET" && operation.renderable);
|
|
2077
|
+
if (!isApiRoute(route, renderable))
|
|
2045
2078
|
route.title = title;
|
|
2046
2079
|
}
|
|
2047
2080
|
if (body.enabled !== undefined)
|
|
@@ -2111,19 +2144,7 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2111
2144
|
const appDef = config.apps.find((a) => a.id === appId);
|
|
2112
2145
|
if (!appDef)
|
|
2113
2146
|
return jsonResponse({ error: "App not found" }, 404);
|
|
2114
|
-
appDef.menu = items.map(
|
|
2115
|
-
const item = raw && typeof raw === "object" ? raw : {};
|
|
2116
|
-
return {
|
|
2117
|
-
id: typeof item.id === "string" ? item.id : uuidv7(),
|
|
2118
|
-
type: item.type === "group" ? "group" : "link",
|
|
2119
|
-
title: typeof item.title === "string" ? item.title : undefined,
|
|
2120
|
-
icon: typeof item.icon === "string" ? item.icon : undefined,
|
|
2121
|
-
routeId: typeof item.routeId === "string" ? item.routeId : undefined,
|
|
2122
|
-
href: typeof item.href === "string" ? item.href : undefined,
|
|
2123
|
-
enabled: item.enabled !== false,
|
|
2124
|
-
children: Array.isArray(item.children) ? item.children : []
|
|
2125
|
-
};
|
|
2126
|
-
});
|
|
2147
|
+
appDef.menu = items.map(normalizeMenuItem);
|
|
2127
2148
|
await store.saveConfig(config);
|
|
2128
2149
|
return jsonResponse({ ok: true });
|
|
2129
2150
|
});
|
|
@@ -2196,27 +2217,27 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2196
2217
|
let serviceId;
|
|
2197
2218
|
let capabilities = [];
|
|
2198
2219
|
let serviceRoutes = [];
|
|
2199
|
-
let
|
|
2200
|
-
let dependencyViewIds = new Set();
|
|
2220
|
+
let dependencyOperationIds = new Set();
|
|
2201
2221
|
const schemaText = typeof body.schema === "string" ? body.schema : "";
|
|
2202
2222
|
if (schemaText) {
|
|
2203
2223
|
try {
|
|
2204
2224
|
const schema = JSON.parse(schemaText);
|
|
2205
2225
|
serviceId = schema.manifest?.pluginId;
|
|
2206
2226
|
capabilities = Array.isArray(schema.manifest?.capabilities) ? schema.manifest.capabilities.filter((value) => typeof value === "string") : [];
|
|
2207
|
-
serviceRoutes = schema.routes ?? [];
|
|
2208
2227
|
const manifestViews = schema.manifest?.views ?? [];
|
|
2209
|
-
|
|
2210
|
-
?
|
|
2228
|
+
dependencyOperationIds = new Set(manifestViews.flatMap((view) => (view.operations ?? []).flatMap((operation) => Array.isArray(operation.dependencies)
|
|
2229
|
+
? operation.dependencies.filter((value) => typeof value === "string")
|
|
2230
|
+
: [])));
|
|
2231
|
+
serviceRoutes = manifestViews.flatMap((view) => (view.operations ?? []).flatMap((operation) => typeof operation.operationId === "string"
|
|
2232
|
+
? [{
|
|
2233
|
+
viewId: view.viewId,
|
|
2234
|
+
path: view.path ?? `/${view.viewId}`,
|
|
2235
|
+
operationId: operation.operationId,
|
|
2236
|
+
title: typeof operation.title === "string" ? operation.title : view.title,
|
|
2237
|
+
renderable: operation.renderable === true,
|
|
2238
|
+
pageRenderable: operation.method === "GET" && hasPageRenderer({ ...view, operations: [operation] })
|
|
2239
|
+
}]
|
|
2211
2240
|
: []));
|
|
2212
|
-
viewMeta = new Map(manifestViews.map((v) => [v.viewId, {
|
|
2213
|
-
title: v.title,
|
|
2214
|
-
renderable: v.renderable !== false,
|
|
2215
|
-
pageRenderable: hasPageRenderer(v),
|
|
2216
|
-
methods: Array.isArray(v.methods)
|
|
2217
|
-
? v.methods.filter((value) => typeof value === "string")
|
|
2218
|
-
: []
|
|
2219
|
-
}]));
|
|
2220
2241
|
}
|
|
2221
2242
|
catch { /* malformed schema - register without routes */ }
|
|
2222
2243
|
}
|
|
@@ -2246,47 +2267,51 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
2246
2267
|
const existingPaths = new Set(appDef.routes.map((r) => r.path));
|
|
2247
2268
|
for (const r of serviceRoutes) {
|
|
2248
2269
|
const routeServiceId = serviceId ?? newServiceId;
|
|
2249
|
-
const
|
|
2250
|
-
const renderable = meta?.renderable ?? r.renderable !== false;
|
|
2251
|
-
const mountPath = renderable
|
|
2270
|
+
const mountPath = r.pageRenderable
|
|
2252
2271
|
? pageRoutePath(routeServiceId, r.path)
|
|
2253
2272
|
: apiRoutePath(routeServiceId, r.path);
|
|
2254
|
-
if (existingPaths.has(mountPath))
|
|
2273
|
+
if (r.pageRenderable && existingPaths.has(mountPath))
|
|
2274
|
+
continue;
|
|
2275
|
+
if (appDef.routes.some((route) => route.serviceId === newServiceId && route.operations.includes(r.operationId)))
|
|
2255
2276
|
continue;
|
|
2256
2277
|
const routeId = uuidv7();
|
|
2257
|
-
const routeTitle =
|
|
2278
|
+
const routeTitle = r.title;
|
|
2258
2279
|
appDef.routes.push({
|
|
2259
2280
|
id: routeId,
|
|
2260
|
-
kind:
|
|
2281
|
+
kind: r.pageRenderable ? "page" : "api",
|
|
2261
2282
|
path: mountPath,
|
|
2262
2283
|
serviceId: newServiceId,
|
|
2263
2284
|
viewId: r.viewId,
|
|
2264
2285
|
targetPath: r.path,
|
|
2265
2286
|
title: routeTitle,
|
|
2266
|
-
enabled:
|
|
2267
|
-
|
|
2287
|
+
enabled: r.pageRenderable || dependencyOperationIds.has(r.operationId),
|
|
2288
|
+
operations: [r.operationId]
|
|
2268
2289
|
});
|
|
2269
|
-
|
|
2270
|
-
|
|
2290
|
+
if (r.pageRenderable)
|
|
2291
|
+
existingPaths.add(mountPath);
|
|
2292
|
+
if (r.pageRenderable && !isApiRoute({ kind: "page", path: mountPath }, true)) {
|
|
2271
2293
|
groupChildren.push({
|
|
2272
2294
|
id: uuidv7(),
|
|
2273
2295
|
type: "link",
|
|
2274
2296
|
title: routeTitle,
|
|
2275
2297
|
routeId,
|
|
2276
|
-
enabled: true
|
|
2298
|
+
enabled: true,
|
|
2299
|
+
serviceStatus: "show",
|
|
2300
|
+
authStatus: "show",
|
|
2301
|
+
children: []
|
|
2277
2302
|
});
|
|
2278
2303
|
}
|
|
2279
2304
|
}
|
|
2280
2305
|
if (groupChildren.length > 0) {
|
|
2281
|
-
|
|
2282
|
-
menu.push({
|
|
2306
|
+
appDef.menu.push({
|
|
2283
2307
|
id: groupId,
|
|
2284
2308
|
type: "group",
|
|
2285
2309
|
title,
|
|
2286
2310
|
enabled: true,
|
|
2311
|
+
serviceStatus: "show",
|
|
2312
|
+
authStatus: "show",
|
|
2287
2313
|
children: groupChildren
|
|
2288
2314
|
});
|
|
2289
|
-
appDef.menu = menu;
|
|
2290
2315
|
}
|
|
2291
2316
|
}
|
|
2292
2317
|
}
|