@acorex-platform/module-platform-dev-tools-client 0.0.38 → 0.0.48
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/fesm2022/acorex-platform-module-platform-dev-tools-client-contracts.mjs +21 -1
- package/fesm2022/acorex-platform-module-platform-dev-tools-client-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-module-platform-dev-tools-client.mjs +2387 -698
- package/fesm2022/acorex-platform-module-platform-dev-tools-client.mjs.map +1 -1
- package/package.json +2 -1
- package/types/acorex-platform-module-platform-dev-tools-client-contracts.d.ts +9 -1
- package/types/acorex-platform-module-platform-dev-tools-client.d.ts +353 -101
|
@@ -1,45 +1,42 @@
|
|
|
1
|
-
import { AXPModuleManifestRegistry,
|
|
1
|
+
import { AXPModuleManifestRegistry, AXPDeviceService, provideLazyProvider } from '@acorex-platform/framework-client/core';
|
|
2
2
|
import { AXP_SETTING_DEFINITION_PROVIDER, AXP_MENU_PROVIDER } from '@acorex-platform/framework-client/common';
|
|
3
|
-
import {
|
|
3
|
+
import { AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
|
|
4
4
|
import { AXPRootLayoutComponent } from '@acorex-platform/framework-client/themes/default';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
6
|
-
import { Injectable, inject, input, ChangeDetectionStrategy, ViewEncapsulation, Component,
|
|
7
|
-
import { ROUTES } from '@angular/router';
|
|
8
|
-
import { RootConfig, AXPApplicationsPlatformPermissionKeys, AXPPlatformDevToolsSettings, AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION } from '@acorex-platform/module-platform-dev-tools-client/contracts';
|
|
6
|
+
import { Injectable, inject, signal, input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, DestroyRef, linkedSignal, effect, viewChild, NgModule } from '@angular/core';
|
|
7
|
+
import { ActivatedRoute, ROUTES } from '@angular/router';
|
|
9
8
|
import { AXPCommonPermissionGroupKeys } from '@acorex-platform/module-common-client/contracts';
|
|
10
|
-
import {
|
|
11
|
-
|
|
9
|
+
import { AXPApplicationsPlatformPermissionKeys, AXPPlatformDevToolsSettings, AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION } from '@acorex-platform/module-platform-dev-tools-client/contracts';
|
|
10
|
+
export { PlatformDevToolsManifest } from '@acorex-platform/module-platform-dev-tools-client/contracts';
|
|
11
|
+
import { AXPWidgetsList, runtimeQueryPayloadData, AXP_MODULE_TYPE, resolveModuleType, resolveModuleDomain } from '@acorex-platform/framework-shared/core';
|
|
12
|
+
import { AXPQueryService } from '@acorex-platform/framework-client/runtime';
|
|
13
|
+
import { AXMPlatformExplorerQueryKeys } from '@acorex-platform/module-platform-management-client/contracts';
|
|
12
14
|
import * as i1 from '@angular/common';
|
|
13
|
-
import { CommonModule } from '@angular/common';
|
|
15
|
+
import { CommonModule, NgTemplateOutlet } from '@angular/common';
|
|
16
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
17
|
+
import { AXResizableDirective } from '@acorex/cdk/resizable';
|
|
14
18
|
import { AXTreeViewComponent } from '@acorex/components/tree-view';
|
|
15
|
-
import
|
|
16
|
-
import
|
|
19
|
+
import * as i4 from '@acorex/components/decorators';
|
|
20
|
+
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
21
|
+
import * as i2$1 from '@acorex/components/loading';
|
|
22
|
+
import { AXLoadingModule } from '@acorex/components/loading';
|
|
23
|
+
import * as i3$1 from '@acorex/components/search-box';
|
|
24
|
+
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
|
25
|
+
import * as i5$1 from '@acorex/components/tabs';
|
|
26
|
+
import { AXTabsModule } from '@acorex/components/tabs';
|
|
27
|
+
import * as i3 from '@acorex/core/translation';
|
|
17
28
|
import { AXTranslationModule } from '@acorex/core/translation';
|
|
18
|
-
import {
|
|
29
|
+
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex-platform/framework-client/layout/views';
|
|
30
|
+
import { AXPStateMessageComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutBlockComponent } from '@acorex-platform/framework-client/layout/components';
|
|
31
|
+
import * as i2 from '@acorex/components/badge';
|
|
32
|
+
import { AXBadgeModule } from '@acorex/components/badge';
|
|
33
|
+
import * as i5 from '@acorex/components/drawer';
|
|
34
|
+
import { AXDrawerModule } from '@acorex/components/drawer';
|
|
35
|
+
import { arrangeWorkflowDiagram, AXPWorkflowDesignerComponent } from '@acorex-platform/module-platform-management-client';
|
|
19
36
|
import { AXDataSource } from '@acorex/cdk/common';
|
|
20
37
|
import * as i1$1 from '@acorex/components/data-table';
|
|
21
38
|
import { AXDataTableModule } from '@acorex/components/data-table';
|
|
22
39
|
|
|
23
|
-
//#region ---- Imports ----
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region ---- Manifest Definition ----
|
|
26
|
-
/**
|
|
27
|
-
* Platform Dev Tools Module Manifest.
|
|
28
|
-
* Development-only module for exploring platform structure (modules, entities, permissions, features).
|
|
29
|
-
*/
|
|
30
|
-
const PlatformDevToolsManifest = {
|
|
31
|
-
name: RootConfig.module.name,
|
|
32
|
-
version: '1.0.0',
|
|
33
|
-
title: RootConfig.module.title,
|
|
34
|
-
icon: RootConfig.module.icon,
|
|
35
|
-
i18n: RootConfig.config.i18n,
|
|
36
|
-
type: 'platform',
|
|
37
|
-
domain: 'platform',
|
|
38
|
-
description: '@platform-dev-tools:module.description',
|
|
39
|
-
required: false,
|
|
40
|
-
};
|
|
41
|
-
//#endregion
|
|
42
|
-
|
|
43
40
|
//#endregion
|
|
44
41
|
//#region ---- Permission Definition Provider ----
|
|
45
42
|
/**
|
|
@@ -100,147 +97,353 @@ class AXPPlatformDevToolsSettingProvider {
|
|
|
100
97
|
}
|
|
101
98
|
//#endregion
|
|
102
99
|
|
|
103
|
-
//#region
|
|
100
|
+
//#region ----- Tree node types -----
|
|
104
101
|
//#endregion
|
|
105
102
|
|
|
106
|
-
//#region ---- Imports ----
|
|
107
103
|
//#endregion
|
|
108
|
-
//#region
|
|
104
|
+
//#region ----- Constants -----
|
|
105
|
+
const EXPLORER_QUERY_MODULE = 'module';
|
|
106
|
+
const EXPLORER_QUERY_KIND = 'kind';
|
|
107
|
+
const EXPLORER_QUERY_NAME = 'name';
|
|
108
|
+
const EXPLORER_QUERY_SEARCH = 'q';
|
|
109
|
+
const FOLDER_KINDS = new Set(['entities', 'commands', 'queries', 'plugins', 'widgets']);
|
|
110
|
+
const PAGE_KINDS = new Set([
|
|
111
|
+
'module',
|
|
112
|
+
'diagram',
|
|
113
|
+
'entity',
|
|
114
|
+
'command',
|
|
115
|
+
'query',
|
|
116
|
+
'plugin',
|
|
117
|
+
'widget',
|
|
118
|
+
]);
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region ----- Kind helpers -----
|
|
121
|
+
function isExplorerFolderKind(kind) {
|
|
122
|
+
return !!kind && FOLDER_KINDS.has(kind);
|
|
123
|
+
}
|
|
124
|
+
function isExplorerPageKind(kind) {
|
|
125
|
+
return !!kind && PAGE_KINDS.has(kind);
|
|
126
|
+
}
|
|
127
|
+
function catalogFolderKind(kind) {
|
|
128
|
+
switch (kind) {
|
|
129
|
+
case 'entity':
|
|
130
|
+
return 'entities';
|
|
131
|
+
case 'command':
|
|
132
|
+
return 'commands';
|
|
133
|
+
case 'query':
|
|
134
|
+
return 'queries';
|
|
135
|
+
case 'plugin':
|
|
136
|
+
return 'plugins';
|
|
137
|
+
case 'widget':
|
|
138
|
+
return 'widgets';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region ----- Query params -----
|
|
143
|
+
function param(map, key) {
|
|
144
|
+
const value = map.get(key)?.trim();
|
|
145
|
+
return value || undefined;
|
|
146
|
+
}
|
|
147
|
+
function explorerStateFromQuery(map) {
|
|
148
|
+
const module = param(map, EXPLORER_QUERY_MODULE);
|
|
149
|
+
const rawKind = param(map, EXPLORER_QUERY_KIND);
|
|
150
|
+
const kind = rawKind === 'entities' ? 'diagram' : rawKind;
|
|
151
|
+
return {
|
|
152
|
+
...(module ? { module } : {}),
|
|
153
|
+
...(isExplorerPageKind(kind) ? { kind } : {}),
|
|
154
|
+
...(param(map, EXPLORER_QUERY_NAME) ? { name: param(map, EXPLORER_QUERY_NAME) } : {}),
|
|
155
|
+
...(param(map, EXPLORER_QUERY_SEARCH) ? { search: param(map, EXPLORER_QUERY_SEARCH) } : {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function queryParamsFromExplorer(node, search) {
|
|
159
|
+
const q = search.trim();
|
|
160
|
+
const params = {
|
|
161
|
+
[EXPLORER_QUERY_MODULE]: null,
|
|
162
|
+
[EXPLORER_QUERY_KIND]: null,
|
|
163
|
+
[EXPLORER_QUERY_NAME]: null,
|
|
164
|
+
[EXPLORER_QUERY_SEARCH]: q || null,
|
|
165
|
+
};
|
|
166
|
+
if (!node || node.kind === 'type-group' || isExplorerFolderKind(node.kind)) {
|
|
167
|
+
return params;
|
|
168
|
+
}
|
|
169
|
+
if (node.moduleName) {
|
|
170
|
+
params[EXPLORER_QUERY_MODULE] = node.moduleName;
|
|
171
|
+
}
|
|
172
|
+
if (node.kind === 'module') {
|
|
173
|
+
return params;
|
|
174
|
+
}
|
|
175
|
+
if (node.kind === 'diagram') {
|
|
176
|
+
params[EXPLORER_QUERY_KIND] = 'diagram';
|
|
177
|
+
return params;
|
|
178
|
+
}
|
|
179
|
+
if (node.kind === 'entity' ||
|
|
180
|
+
node.kind === 'command' ||
|
|
181
|
+
node.kind === 'query' ||
|
|
182
|
+
node.kind === 'plugin' ||
|
|
183
|
+
node.kind === 'widget') {
|
|
184
|
+
params[EXPLORER_QUERY_KIND] = node.kind;
|
|
185
|
+
const payload = node.payload;
|
|
186
|
+
const name = String(payload?.name ?? '').trim() ||
|
|
187
|
+
String(payload?.fullName ?? '').trim() ||
|
|
188
|
+
node.label;
|
|
189
|
+
params[EXPLORER_QUERY_NAME] = name;
|
|
190
|
+
}
|
|
191
|
+
return params;
|
|
192
|
+
}
|
|
193
|
+
function explorerNodeId(moduleName, kind, name) {
|
|
194
|
+
if (kind === 'module') {
|
|
195
|
+
return `module-${moduleName}`;
|
|
196
|
+
}
|
|
197
|
+
if (kind === 'diagram') {
|
|
198
|
+
return `module-${moduleName}-diagram`;
|
|
199
|
+
}
|
|
200
|
+
return `${kind}-${name ?? ''}`;
|
|
201
|
+
}
|
|
202
|
+
function explorerRevealIds(node) {
|
|
203
|
+
const moduleName = node.moduleName;
|
|
204
|
+
if (!moduleName) {
|
|
205
|
+
return [node.id];
|
|
206
|
+
}
|
|
207
|
+
const ids = [`module-${moduleName}`];
|
|
208
|
+
if (node.kind === 'entity' ||
|
|
209
|
+
node.kind === 'command' ||
|
|
210
|
+
node.kind === 'query' ||
|
|
211
|
+
node.kind === 'plugin' ||
|
|
212
|
+
node.kind === 'widget') {
|
|
213
|
+
ids.push(`module-${moduleName}-${catalogFolderKind(node.kind)}`);
|
|
214
|
+
}
|
|
215
|
+
if (node.kind !== 'module') {
|
|
216
|
+
ids.push(node.id);
|
|
217
|
+
}
|
|
218
|
+
return ids;
|
|
219
|
+
}
|
|
220
|
+
function sameExplorerNode(left, right) {
|
|
221
|
+
return left?.id === right?.id;
|
|
222
|
+
}
|
|
223
|
+
//#endregion
|
|
224
|
+
|
|
225
|
+
//#region ----- Imports -----
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region ----- Service -----
|
|
109
228
|
class PlatformExplorerDataService {
|
|
110
229
|
constructor() {
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
113
|
-
this.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const children = await this.getModuleChildren(modNode.id);
|
|
147
|
-
if (children.length > 0) {
|
|
148
|
-
filtered.push({
|
|
149
|
-
...modNode,
|
|
150
|
-
itemCount: children.length,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
230
|
+
this.queryService = inject(AXPQueryService);
|
|
231
|
+
this.manifestRegistry = inject(AXPModuleManifestRegistry, { optional: true });
|
|
232
|
+
this.moduleCache = new Map();
|
|
233
|
+
this.entityTabs = signal([], /* @ts-ignore */
|
|
234
|
+
...(ngDevMode ? [{ debugName: "entityTabs" }] : /* istanbul ignore next */ []));
|
|
235
|
+
this.activeEntitySection = signal('properties', /* @ts-ignore */
|
|
236
|
+
...(ngDevMode ? [{ debugName: "activeEntitySection" }] : /* istanbul ignore next */ []));
|
|
237
|
+
}
|
|
238
|
+
clearCache() {
|
|
239
|
+
this.moduleCache.clear();
|
|
240
|
+
}
|
|
241
|
+
setEntityTabs(tabs) {
|
|
242
|
+
this.entityTabs.set(tabs);
|
|
243
|
+
}
|
|
244
|
+
selectEntitySection(section) {
|
|
245
|
+
this.activeEntitySection.set(section);
|
|
246
|
+
}
|
|
247
|
+
clearEntityTabs() {
|
|
248
|
+
this.entityTabs.set([]);
|
|
249
|
+
this.activeEntitySection.set('properties');
|
|
250
|
+
}
|
|
251
|
+
async listModules(search) {
|
|
252
|
+
const result = await this.queryService.fetch(AXMPlatformExplorerQueryKeys.ListModules, { search: search?.trim() || undefined });
|
|
253
|
+
return runtimeQueryPayloadData(result)?.items ?? [];
|
|
254
|
+
}
|
|
255
|
+
async getModule(moduleName) {
|
|
256
|
+
const name = moduleName.trim();
|
|
257
|
+
const cached = this.moduleCache.get(name);
|
|
258
|
+
if (cached) {
|
|
259
|
+
return cached;
|
|
260
|
+
}
|
|
261
|
+
const result = await this.queryService.fetch(AXMPlatformExplorerQueryKeys.GetModule, { module: name });
|
|
262
|
+
const catalog = runtimeQueryPayloadData(result) ?? null;
|
|
263
|
+
if (catalog) {
|
|
264
|
+
this.moduleCache.set(name, catalog);
|
|
153
265
|
}
|
|
154
|
-
return
|
|
266
|
+
return catalog;
|
|
155
267
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
async
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
268
|
+
async getEntity(moduleName, entityName) {
|
|
269
|
+
const result = await this.queryService.fetch(AXMPlatformExplorerQueryKeys.GetEntity, { module: moduleName, entity: entityName });
|
|
270
|
+
return runtimeQueryPayloadData(result) ?? null;
|
|
271
|
+
}
|
|
272
|
+
async getCatalogItem(kind, name) {
|
|
273
|
+
const result = await this.queryService.fetch(AXMPlatformExplorerQueryKeys.GetCatalogItem, { kind, name });
|
|
274
|
+
return runtimeQueryPayloadData(result) ?? null;
|
|
275
|
+
}
|
|
276
|
+
getManifest(moduleName) {
|
|
277
|
+
return this.manifestRegistry?.get(moduleName);
|
|
278
|
+
}
|
|
279
|
+
moduleTitle(moduleName) {
|
|
280
|
+
return this.getManifest(moduleName)?.title ?? moduleName;
|
|
281
|
+
}
|
|
282
|
+
moduleIcon(moduleName) {
|
|
283
|
+
return this.getManifest(moduleName)?.icon || 'fa-light fa-cube';
|
|
284
|
+
}
|
|
285
|
+
async resolveExplorerSelection(state, moduleNodes) {
|
|
286
|
+
const moduleName = state.module?.trim();
|
|
287
|
+
if (!moduleName) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
const moduleNode = moduleNodes.find((node) => node.kind === 'module' && node.moduleName === moduleName);
|
|
291
|
+
if (!moduleNode) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const kind = state.kind;
|
|
295
|
+
if (!kind || kind === 'module') {
|
|
296
|
+
return moduleNode;
|
|
297
|
+
}
|
|
298
|
+
const title = this.moduleTitle(moduleName);
|
|
299
|
+
if (kind === 'diagram') {
|
|
300
|
+
const catalog = await this.getModule(moduleName);
|
|
301
|
+
if (!catalog?.entities.length) {
|
|
302
|
+
return moduleNode;
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
id: `module-${moduleName}-diagram`,
|
|
306
|
+
kind: 'diagram',
|
|
307
|
+
label: '@platform-dev-tools:module.terms.diagram',
|
|
180
308
|
moduleName,
|
|
181
|
-
moduleTitle,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
309
|
+
moduleTitle: title,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
const name = state.name?.trim();
|
|
313
|
+
if (!name) {
|
|
314
|
+
return moduleNode;
|
|
315
|
+
}
|
|
316
|
+
const children = await this.getCategoryChildren(moduleName, catalogFolderKind(kind));
|
|
317
|
+
return (children.find((node) => {
|
|
318
|
+
const payload = node.payload;
|
|
319
|
+
return (node.id === `${kind}-${name}` ||
|
|
320
|
+
String(payload?.name ?? '') === name ||
|
|
321
|
+
String(payload?.fullName ?? '') === name);
|
|
322
|
+
}) ?? moduleNode);
|
|
323
|
+
}
|
|
324
|
+
toModuleTreeNodes(modules) {
|
|
325
|
+
const buckets = new Map();
|
|
326
|
+
for (const type of Object.values(AXP_MODULE_TYPE)) {
|
|
327
|
+
buckets.set(type, []);
|
|
328
|
+
}
|
|
329
|
+
for (const mod of modules) {
|
|
330
|
+
const manifest = this.getManifest(mod.name);
|
|
331
|
+
const type = resolveModuleType({
|
|
332
|
+
name: mod.name,
|
|
333
|
+
type: manifest?.type,
|
|
334
|
+
required: manifest?.required,
|
|
191
335
|
});
|
|
336
|
+
const list = buckets.get(type) ?? [];
|
|
337
|
+
list.push(mod);
|
|
338
|
+
buckets.set(type, list);
|
|
192
339
|
}
|
|
193
|
-
|
|
340
|
+
const nodes = [];
|
|
341
|
+
let firstGroup = true;
|
|
342
|
+
for (const type of Object.values(AXP_MODULE_TYPE)) {
|
|
343
|
+
const list = [...(buckets.get(type) ?? [])].sort((a, b) => this.moduleTitle(a.name).localeCompare(this.moduleTitle(b.name), undefined, { sensitivity: 'base' }));
|
|
344
|
+
if (list.length === 0) {
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
194
347
|
nodes.push({
|
|
195
|
-
id: `
|
|
196
|
-
kind: '
|
|
197
|
-
label:
|
|
198
|
-
|
|
199
|
-
moduleTitle,
|
|
200
|
-
itemCount: permissionsCount,
|
|
348
|
+
id: `type-group-${type}`,
|
|
349
|
+
kind: 'type-group',
|
|
350
|
+
label: `@application-management:editions.modules-editor.types.${type}`,
|
|
351
|
+
divided: !firstGroup,
|
|
201
352
|
});
|
|
353
|
+
firstGroup = false;
|
|
354
|
+
for (const mod of list) {
|
|
355
|
+
nodes.push(this.toModuleNode(mod));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return nodes;
|
|
359
|
+
}
|
|
360
|
+
toModuleNode(mod) {
|
|
361
|
+
return {
|
|
362
|
+
id: `module-${mod.name}`,
|
|
363
|
+
kind: 'module',
|
|
364
|
+
label: this.moduleTitle(mod.name),
|
|
365
|
+
moduleName: mod.name,
|
|
366
|
+
moduleTitle: this.moduleTitle(mod.name),
|
|
367
|
+
icon: this.moduleIcon(mod.name),
|
|
368
|
+
itemCount: mod.categoryCount + (mod.entityCount > 0 ? 1 : 0),
|
|
369
|
+
payload: mod,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
async getModuleChildren(moduleName) {
|
|
373
|
+
const catalog = await this.getModule(moduleName);
|
|
374
|
+
if (!catalog) {
|
|
375
|
+
return [];
|
|
202
376
|
}
|
|
203
|
-
|
|
377
|
+
const title = this.moduleTitle(moduleName);
|
|
378
|
+
const nodes = [];
|
|
379
|
+
if (catalog.entities.length > 0) {
|
|
204
380
|
nodes.push({
|
|
205
|
-
id: `module-${moduleName}-
|
|
206
|
-
kind: '
|
|
207
|
-
label: '@platform-dev-tools:module.terms.
|
|
381
|
+
id: `module-${moduleName}-diagram`,
|
|
382
|
+
kind: 'diagram',
|
|
383
|
+
label: '@platform-dev-tools:module.terms.diagram',
|
|
208
384
|
moduleName,
|
|
209
|
-
moduleTitle,
|
|
210
|
-
itemCount: featuresCount,
|
|
385
|
+
moduleTitle: title,
|
|
211
386
|
});
|
|
212
387
|
}
|
|
388
|
+
this.pushCategory(nodes, moduleName, title, 'entities', catalog.entities.length);
|
|
389
|
+
this.pushCategory(nodes, moduleName, title, 'commands', catalog.commands.length);
|
|
390
|
+
this.pushCategory(nodes, moduleName, title, 'queries', catalog.queries.length);
|
|
391
|
+
this.pushCategory(nodes, moduleName, title, 'plugins', catalog.plugins.length);
|
|
392
|
+
this.pushCategory(nodes, moduleName, title, 'widgets', catalog.widgets.length);
|
|
213
393
|
return nodes;
|
|
214
394
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
395
|
+
async getCategoryChildren(moduleName, kind) {
|
|
396
|
+
const catalog = await this.getModule(moduleName);
|
|
397
|
+
if (!catalog) {
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
const title = this.moduleTitle(moduleName);
|
|
401
|
+
switch (kind) {
|
|
402
|
+
case 'entities':
|
|
403
|
+
return catalog.entities.map((item) => ({
|
|
404
|
+
id: `entity-${item.fullName}`,
|
|
405
|
+
kind: 'entity',
|
|
406
|
+
label: item.name,
|
|
407
|
+
moduleName,
|
|
408
|
+
moduleTitle: title,
|
|
409
|
+
icon: item.icon,
|
|
410
|
+
payload: item,
|
|
411
|
+
}));
|
|
412
|
+
case 'commands':
|
|
413
|
+
return catalog.commands.map((item) => this.namedNode('command', item.name, item.title ?? item.name, moduleName, title, item, item.icon));
|
|
414
|
+
case 'queries':
|
|
415
|
+
return catalog.queries.map((item) => this.namedNode('query', item.name, item.title ?? item.name, moduleName, title, item, item.icon));
|
|
416
|
+
case 'plugins':
|
|
417
|
+
return catalog.plugins.map((item) => this.namedNode('plugin', item.name, item.title ?? item.name, moduleName, title, item, item.icon));
|
|
418
|
+
case 'widgets':
|
|
419
|
+
return catalog.widgets.map((item) => this.namedNode('widget', item.name, item.title ?? item.name, moduleName, title, item, item.icon));
|
|
420
|
+
default:
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
pushCategory(nodes, moduleName, moduleTitle, kind, count) {
|
|
425
|
+
if (count <= 0) {
|
|
426
|
+
return;
|
|
242
427
|
}
|
|
243
|
-
|
|
428
|
+
nodes.push({
|
|
429
|
+
id: `module-${moduleName}-${kind}`,
|
|
430
|
+
kind,
|
|
431
|
+
label: `@platform-dev-tools:module.terms.${kind}`,
|
|
432
|
+
moduleName,
|
|
433
|
+
moduleTitle,
|
|
434
|
+
itemCount: count,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
namedNode(kind, name, label, moduleName, moduleTitle, payload, icon) {
|
|
438
|
+
return {
|
|
439
|
+
id: `${kind}-${name}`,
|
|
440
|
+
kind,
|
|
441
|
+
label,
|
|
442
|
+
moduleName,
|
|
443
|
+
moduleTitle,
|
|
444
|
+
icon,
|
|
445
|
+
payload,
|
|
446
|
+
};
|
|
244
447
|
}
|
|
245
448
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PlatformExplorerDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
246
449
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PlatformExplorerDataService }); }
|
|
@@ -249,540 +452,1883 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
249
452
|
type: Injectable
|
|
250
453
|
}] });
|
|
251
454
|
|
|
252
|
-
//#region
|
|
455
|
+
//#region ----- Imports -----
|
|
253
456
|
//#endregion
|
|
457
|
+
//#region ----- Constants -----
|
|
458
|
+
const TYPE_I18N = '@application-management:editions.modules-editor.types';
|
|
459
|
+
const DOMAIN_I18N = '@application-management:editions.modules-editor.domains';
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region ----- Component -----
|
|
254
462
|
class AXPlatformExplorerModuleDetailComponent {
|
|
255
463
|
constructor() {
|
|
256
464
|
this.payload = input(/* @ts-ignore */
|
|
257
465
|
...(ngDevMode ? [undefined, { debugName: "payload" }] : /* istanbul ignore next */ []));
|
|
466
|
+
this.dataService = inject(PlatformExplorerDataService);
|
|
467
|
+
this.view = computed(() => {
|
|
468
|
+
const summary = this.payload();
|
|
469
|
+
if (!summary) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const manifest = this.dataService.getManifest(summary.name);
|
|
473
|
+
if (!manifest) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
return this.toView(summary.name, manifest);
|
|
477
|
+
}, /* @ts-ignore */
|
|
478
|
+
...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
258
479
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
</dt>
|
|
280
|
-
<dd>{{ payload()!.title }}</dd>
|
|
281
|
-
|
|
282
|
-
@if (payload()!.description) {
|
|
283
|
-
<dt>
|
|
284
|
-
{{ '@platform-dev-tools:module.terms.description' | translate | async }}
|
|
285
|
-
</dt>
|
|
286
|
-
<dd>{{ payload()!.description }}</dd>
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
@if (payload()!.i18n) {
|
|
290
|
-
<dt>i18n</dt>
|
|
291
|
-
<dd>{{ payload()!.i18n }}</dd>
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
@if (payload()!.required !== undefined) {
|
|
295
|
-
<dt>
|
|
296
|
-
{{ '@platform-dev-tools:module.terms.required' | translate | async }}
|
|
297
|
-
</dt>
|
|
298
|
-
<dd>{{ payload()!.required }}</dd>
|
|
299
|
-
}
|
|
300
|
-
</dl>
|
|
301
|
-
</section>
|
|
480
|
+
toView(name, manifest) {
|
|
481
|
+
const type = resolveModuleType(manifest);
|
|
482
|
+
const domain = resolveModuleDomain(manifest);
|
|
483
|
+
return {
|
|
484
|
+
name,
|
|
485
|
+
title: manifest.title || name,
|
|
486
|
+
description: manifest.description,
|
|
487
|
+
icon: manifest.icon || 'fa-light fa-cube',
|
|
488
|
+
version: manifest.version,
|
|
489
|
+
type,
|
|
490
|
+
typeKey: `${TYPE_I18N}.${type}`,
|
|
491
|
+
domain,
|
|
492
|
+
domainKey: `${DOMAIN_I18N}.${domain}`,
|
|
493
|
+
i18n: manifest.i18n,
|
|
494
|
+
required: !!manifest.required,
|
|
495
|
+
dependencies: (manifest.dependencies ?? []).map((dep) => ({
|
|
496
|
+
name: dep,
|
|
497
|
+
title: dep.includes('.') ? dep : this.dataService.moduleTitle(dep),
|
|
498
|
+
})),
|
|
499
|
+
};
|
|
302
500
|
}
|
|
303
|
-
|
|
501
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerModuleDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
502
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerModuleDetailComponent, isStandalone: true, selector: "axp-platform-explorer-module-detail", inputs: { payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col flex-1 min-h-0" }, ngImport: i0, template: "<div class=\"flex flex-col flex-1 min-h-0 overflow-auto\">\n <!-- ----- Module identity from client manifest ----- -->\n @if (payload(); as mod) {\n <section class=\"flex flex-col gap-5 p-4\">\n <!--->\n <!-- ----- Manifest header when the module is registered on the client ----- -->\n @if (view(); as info) {\n <div class=\"flex items-start gap-3\">\n <i class=\"text-2xl text-primary shrink-0 mt-0.5\" [ngClass]=\"info.icon\" aria-hidden=\"true\"></i>\n <div class=\"flex flex-col gap-1 min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h2 class=\"m-0 text-lg font-semibold\">{{ info.title | translate | async }}</h2>\n <ax-badge color=\"secondary\" [text]=\"info.version\"></ax-badge>\n <ax-badge color=\"primary\" [text]=\"(info.typeKey | translate | async) ?? info.type\"></ax-badge>\n <ax-badge [text]=\"(info.domainKey | translate | async) ?? info.domain\"></ax-badge>\n <!--->\n <!-- ----- Required modules cannot be disabled in editions ----- -->\n @if (info.required) {\n <ax-badge\n color=\"success\"\n [text]=\"('@platform-dev-tools:module.terms.required' | translate | async) ?? ''\"\n ></ax-badge>\n }\n </div>\n <!--->\n <!-- ----- Optional manifest description ----- -->\n @if (info.description) {\n <p class=\"m-0 text-sm text-muted\">{{ info.description | translate | async }}</p>\n }\n </div>\n </div>\n\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ info.name }}</code></dd>\n <!--->\n <!-- ----- i18n scope from the module manifest ----- -->\n @if (info.i18n) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.i18n' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ info.i18n }}</code></dd>\n }\n </dl>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.dependencies' | translate | async }}</div>\n <!--->\n <!-- ----- Empty dependency list ----- -->\n @if (info.dependencies.length === 0) {\n <p class=\"m-0 text-sm text-muted\">{{ '@platform-dev-tools:module.messages.no-dependencies' | translate | async }}</p>\n }\n <!-- ----- Manifest dependency chips ----- -->\n @else {\n <div class=\"flex flex-wrap gap-2\">\n @for (dep of info.dependencies; track dep.name) {\n <ax-badge [text]=\"(dep.title | translate | async) ?? dep.name\"></ax-badge>\n }\n </div>\n }\n </div>\n }\n <!-- ----- Catalog-only module with no client manifest ----- -->\n @else {\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\">{{ mod.name }}</dd>\n </dl>\n <p class=\"m-0 text-sm text-muted\">{{ '@platform-dev-tools:module.messages.no-manifest' | translate | async }}</p>\n }\n\n <div class=\"flex flex-wrap gap-2\">\n <ax-badge\n color=\"primary\"\n [text]=\"('@platform-dev-tools:module.badges.entities' | translate: { params: { count: mod.entityCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"success\"\n [text]=\"('@platform-dev-tools:module.badges.commands' | translate: { params: { count: mod.commandCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"primary\"\n [text]=\"('@platform-dev-tools:module.badges.queries' | translate: { params: { count: mod.queryCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"warning\"\n [text]=\"('@platform-dev-tools:module.badges.plugins' | translate: { params: { count: mod.pluginCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n [text]=\"('@platform-dev-tools:module.badges.widgets' | translate: { params: { count: mod.widgetCount } } | async) ?? ''\"\n ></ax-badge>\n </div>\n </section>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
304
503
|
}
|
|
305
504
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerModuleDetailComponent, decorators: [{
|
|
306
505
|
type: Component,
|
|
307
|
-
args: [{ selector: 'axp-platform-explorer-module-detail', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXTranslationModule], template:
|
|
308
|
-
|
|
309
|
-
<section class="axp-module-detail">
|
|
310
|
-
<h3 class="axp-module-detail__section-title">
|
|
311
|
-
{{ '@platform-dev-tools:module.terms.module-info' | translate | async }}
|
|
312
|
-
</h3>
|
|
313
|
-
<dl class="axp-detail-dl">
|
|
314
|
-
<dt>
|
|
315
|
-
{{ '@platform-dev-tools:module.terms.name' | translate | async }}
|
|
316
|
-
</dt>
|
|
317
|
-
<dd>{{ payload()!.name }}</dd>
|
|
318
|
-
|
|
319
|
-
<dt>
|
|
320
|
-
{{ '@platform-dev-tools:module.terms.version' | translate | async }}
|
|
321
|
-
</dt>
|
|
322
|
-
<dd>{{ payload()!.version }}</dd>
|
|
323
|
-
|
|
324
|
-
<dt>
|
|
325
|
-
{{ '@platform-dev-tools:module.terms.title' | translate | async }}
|
|
326
|
-
</dt>
|
|
327
|
-
<dd>{{ payload()!.title }}</dd>
|
|
506
|
+
args: [{ selector: 'axp-platform-explorer-module-detail', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'flex flex-col flex-1 min-h-0' }, imports: [CommonModule, AXTranslationModule, AXBadgeModule], template: "<div class=\"flex flex-col flex-1 min-h-0 overflow-auto\">\n <!-- ----- Module identity from client manifest ----- -->\n @if (payload(); as mod) {\n <section class=\"flex flex-col gap-5 p-4\">\n <!--->\n <!-- ----- Manifest header when the module is registered on the client ----- -->\n @if (view(); as info) {\n <div class=\"flex items-start gap-3\">\n <i class=\"text-2xl text-primary shrink-0 mt-0.5\" [ngClass]=\"info.icon\" aria-hidden=\"true\"></i>\n <div class=\"flex flex-col gap-1 min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h2 class=\"m-0 text-lg font-semibold\">{{ info.title | translate | async }}</h2>\n <ax-badge color=\"secondary\" [text]=\"info.version\"></ax-badge>\n <ax-badge color=\"primary\" [text]=\"(info.typeKey | translate | async) ?? info.type\"></ax-badge>\n <ax-badge [text]=\"(info.domainKey | translate | async) ?? info.domain\"></ax-badge>\n <!--->\n <!-- ----- Required modules cannot be disabled in editions ----- -->\n @if (info.required) {\n <ax-badge\n color=\"success\"\n [text]=\"('@platform-dev-tools:module.terms.required' | translate | async) ?? ''\"\n ></ax-badge>\n }\n </div>\n <!--->\n <!-- ----- Optional manifest description ----- -->\n @if (info.description) {\n <p class=\"m-0 text-sm text-muted\">{{ info.description | translate | async }}</p>\n }\n </div>\n </div>\n\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ info.name }}</code></dd>\n <!--->\n <!-- ----- i18n scope from the module manifest ----- -->\n @if (info.i18n) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.i18n' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ info.i18n }}</code></dd>\n }\n </dl>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.dependencies' | translate | async }}</div>\n <!--->\n <!-- ----- Empty dependency list ----- -->\n @if (info.dependencies.length === 0) {\n <p class=\"m-0 text-sm text-muted\">{{ '@platform-dev-tools:module.messages.no-dependencies' | translate | async }}</p>\n }\n <!-- ----- Manifest dependency chips ----- -->\n @else {\n <div class=\"flex flex-wrap gap-2\">\n @for (dep of info.dependencies; track dep.name) {\n <ax-badge [text]=\"(dep.title | translate | async) ?? dep.name\"></ax-badge>\n }\n </div>\n }\n </div>\n }\n <!-- ----- Catalog-only module with no client manifest ----- -->\n @else {\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\">{{ mod.name }}</dd>\n </dl>\n <p class=\"m-0 text-sm text-muted\">{{ '@platform-dev-tools:module.messages.no-manifest' | translate | async }}</p>\n }\n\n <div class=\"flex flex-wrap gap-2\">\n <ax-badge\n color=\"primary\"\n [text]=\"('@platform-dev-tools:module.badges.entities' | translate: { params: { count: mod.entityCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"success\"\n [text]=\"('@platform-dev-tools:module.badges.commands' | translate: { params: { count: mod.commandCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"primary\"\n [text]=\"('@platform-dev-tools:module.badges.queries' | translate: { params: { count: mod.queryCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n color=\"warning\"\n [text]=\"('@platform-dev-tools:module.badges.plugins' | translate: { params: { count: mod.pluginCount } } | async) ?? ''\"\n ></ax-badge>\n <ax-badge\n [text]=\"('@platform-dev-tools:module.badges.widgets' | translate: { params: { count: mod.widgetCount } } | async) ?? ''\"\n ></ax-badge>\n </div>\n </section>\n }\n</div>\n" }]
|
|
507
|
+
}], propDecorators: { payload: [{ type: i0.Input, args: [{ isSignal: true, alias: "payload", required: false }] }] } });
|
|
328
508
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region ----- Plugin contribution field names -----
|
|
511
|
+
function isPlaceholderName(name) {
|
|
512
|
+
const trimmed = name.trim();
|
|
513
|
+
return trimmed.startsWith('(from ') || trimmed.includes('options.fields[]');
|
|
514
|
+
}
|
|
515
|
+
function parseContributions(json) {
|
|
516
|
+
if (json == null) {
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
let parsed = json;
|
|
520
|
+
if (typeof json === 'string') {
|
|
521
|
+
const trimmed = json.trim();
|
|
522
|
+
if (!trimmed) {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
parsed = JSON.parse(trimmed);
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (parsed == null || typeof parsed !== 'object') {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
return parsed;
|
|
536
|
+
}
|
|
537
|
+
function optionString(options, key) {
|
|
538
|
+
if (!key || options == null || typeof options !== 'object') {
|
|
539
|
+
return '';
|
|
540
|
+
}
|
|
541
|
+
const value = options[key];
|
|
542
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
543
|
+
}
|
|
544
|
+
function contributedNames(plugin) {
|
|
545
|
+
const contributions = parseContributions(plugin.contributionsJson);
|
|
546
|
+
const names = new Set();
|
|
547
|
+
const add = (name, nameFromOption) => {
|
|
548
|
+
const fromOption = optionString(plugin.options, nameFromOption);
|
|
549
|
+
const fieldName = fromOption || name?.trim() || '';
|
|
550
|
+
if (fieldName && !isPlaceholderName(fieldName)) {
|
|
551
|
+
names.add(fieldName);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
for (const property of contributions?.properties ?? []) {
|
|
555
|
+
add(property.name, property.nameFromOption);
|
|
556
|
+
}
|
|
557
|
+
for (const column of contributions?.columns ?? []) {
|
|
558
|
+
add(column.name, column.nameFromOption);
|
|
559
|
+
}
|
|
560
|
+
return [...names];
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Maps host property/column names to the plugin that contributed them.
|
|
564
|
+
* First matching plugin wins when two plugins claim the same name.
|
|
565
|
+
*/
|
|
566
|
+
function pluginSourceByFieldName(plugins) {
|
|
567
|
+
const map = new Map();
|
|
568
|
+
for (const plugin of plugins) {
|
|
569
|
+
const source = {
|
|
570
|
+
name: plugin.name,
|
|
571
|
+
title: plugin.title || plugin.name,
|
|
572
|
+
};
|
|
573
|
+
for (const fieldName of contributedNames(plugin)) {
|
|
574
|
+
if (!map.has(fieldName)) {
|
|
575
|
+
map.set(fieldName, source);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return map;
|
|
580
|
+
}
|
|
581
|
+
//#endregion
|
|
335
582
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
583
|
+
//#region ----- Types -----
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region ----- Flatten -----
|
|
586
|
+
function formatLeaf(value) {
|
|
587
|
+
if (value === null) {
|
|
588
|
+
return 'null';
|
|
589
|
+
}
|
|
590
|
+
if (typeof value === 'string') {
|
|
591
|
+
return value;
|
|
592
|
+
}
|
|
593
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
594
|
+
return String(value);
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
return JSON.stringify(value);
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
return String(value);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function joinPath(prefix, key) {
|
|
604
|
+
return prefix ? `${prefix}.${key}` : key;
|
|
605
|
+
}
|
|
606
|
+
function flattenToPairs(value, prefix = '') {
|
|
607
|
+
if (value === undefined || typeof value === 'function') {
|
|
608
|
+
return [];
|
|
609
|
+
}
|
|
610
|
+
if (value !== null && typeof value === 'object') {
|
|
611
|
+
if (Array.isArray(value)) {
|
|
612
|
+
if (value.length === 0) {
|
|
613
|
+
return prefix ? [{ path: prefix, value: '[]' }] : [];
|
|
614
|
+
}
|
|
615
|
+
return value.flatMap((item, index) => flattenToPairs(item, joinPath(prefix, String(index))));
|
|
616
|
+
}
|
|
617
|
+
const entries = Object.entries(value).filter(([, nested]) => nested !== undefined && typeof nested !== 'function');
|
|
618
|
+
if (entries.length === 0) {
|
|
619
|
+
return prefix ? [{ path: prefix, value: '{}' }] : [];
|
|
620
|
+
}
|
|
621
|
+
return entries.flatMap(([key, nested]) => flattenToPairs(nested, joinPath(prefix, key)));
|
|
622
|
+
}
|
|
623
|
+
return [{ path: prefix, value: formatLeaf(value) }];
|
|
624
|
+
}
|
|
625
|
+
function flattenJsonText(json) {
|
|
626
|
+
if (!json?.trim()) {
|
|
627
|
+
return [];
|
|
628
|
+
}
|
|
629
|
+
try {
|
|
630
|
+
return flattenToPairs(JSON.parse(json));
|
|
631
|
+
}
|
|
632
|
+
catch {
|
|
633
|
+
return [{ path: '', value: json }];
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
//#endregion
|
|
340
637
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
638
|
+
//#endregion
|
|
639
|
+
//#region ----- Constants -----
|
|
640
|
+
const SCOPE_ORDER = ['typeLevel', 'selected', 'individual', 'section'];
|
|
641
|
+
//#endregion
|
|
642
|
+
//#region ----- Serialize -----
|
|
643
|
+
function humanText(value) {
|
|
644
|
+
if (typeof value !== 'string') {
|
|
645
|
+
return undefined;
|
|
646
|
+
}
|
|
647
|
+
const trimmed = value.trim();
|
|
648
|
+
if (!trimmed || trimmed.includes('{{')) {
|
|
649
|
+
return undefined;
|
|
650
|
+
}
|
|
651
|
+
return trimmed;
|
|
652
|
+
}
|
|
653
|
+
function titleCaseType(type) {
|
|
654
|
+
return type
|
|
655
|
+
.split('-')
|
|
656
|
+
.filter(Boolean)
|
|
657
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
658
|
+
.join(' ');
|
|
659
|
+
}
|
|
660
|
+
function boolOrExpression(value) {
|
|
661
|
+
if (typeof value === 'boolean') {
|
|
662
|
+
return value ? 'yes' : 'no';
|
|
663
|
+
}
|
|
664
|
+
if (typeof value === 'string' && value.trim()) {
|
|
665
|
+
return value.trim();
|
|
666
|
+
}
|
|
667
|
+
return undefined;
|
|
668
|
+
}
|
|
669
|
+
function asActions(value) {
|
|
670
|
+
if (!Array.isArray(value)) {
|
|
671
|
+
return [];
|
|
672
|
+
}
|
|
673
|
+
return value.filter((item) => !!item && typeof item === 'object');
|
|
674
|
+
}
|
|
675
|
+
function layoutActions(layout) {
|
|
676
|
+
if (!layout || typeof layout !== 'object') {
|
|
677
|
+
return [];
|
|
678
|
+
}
|
|
679
|
+
return asActions(layout.actions);
|
|
680
|
+
}
|
|
681
|
+
function resolveCommand(command) {
|
|
682
|
+
if (typeof command === 'function') {
|
|
683
|
+
return { name: 'function', optionsPairs: [], metadataPairs: [] };
|
|
684
|
+
}
|
|
685
|
+
if (typeof command === 'string') {
|
|
686
|
+
return { name: command, optionsPairs: [], metadataPairs: [] };
|
|
687
|
+
}
|
|
688
|
+
if (command && typeof command === 'object') {
|
|
689
|
+
return {
|
|
690
|
+
name: typeof command.name === 'string' ? command.name : '',
|
|
691
|
+
optionsPairs: flattenToPairs(command.options),
|
|
692
|
+
metadataPairs: flattenToPairs(command.metadata),
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
return { name: '', optionsPairs: [], metadataPairs: [] };
|
|
696
|
+
}
|
|
697
|
+
function resolveItems(items) {
|
|
698
|
+
if (Array.isArray(items)) {
|
|
699
|
+
return { children: asActions(items) };
|
|
700
|
+
}
|
|
701
|
+
if (typeof items === 'string' && items.trim()) {
|
|
702
|
+
return { children: [], expression: items.trim() };
|
|
703
|
+
}
|
|
704
|
+
return { children: [] };
|
|
705
|
+
}
|
|
706
|
+
//#endregion
|
|
707
|
+
//#region ----- Actions -----
|
|
708
|
+
function toActionView(action, id, depth) {
|
|
709
|
+
const command = resolveCommand(action.command);
|
|
710
|
+
const items = resolveItems(action.items);
|
|
711
|
+
const hidden = boolOrExpression(action.hidden);
|
|
712
|
+
const disabled = boolOrExpression(action.disabled);
|
|
713
|
+
const type = typeof action.type === 'string' ? action.type : undefined;
|
|
714
|
+
const shortcuts = (action.shortcuts ?? []).filter((item) => typeof item === 'string' && item.trim());
|
|
715
|
+
const permissions = (action.permissions ?? []).filter((item) => typeof item === 'string' && item.trim());
|
|
716
|
+
return {
|
|
717
|
+
id,
|
|
718
|
+
name: typeof action.name === 'string' ? action.name : undefined,
|
|
719
|
+
title: typeof action.title === 'string' ? action.title : undefined,
|
|
720
|
+
commandName: command.name,
|
|
721
|
+
type,
|
|
722
|
+
typeLabel: type ? titleCaseType(type) : '',
|
|
723
|
+
scope: typeof action.scope === 'string' ? action.scope : 'individual',
|
|
724
|
+
priority: typeof action.priority === 'string' ? action.priority : 'secondary',
|
|
725
|
+
icon: typeof action.icon === 'string' ? action.icon : undefined,
|
|
726
|
+
color: typeof action.color === 'string' ? action.color : undefined,
|
|
727
|
+
shortcuts,
|
|
728
|
+
permissions,
|
|
729
|
+
hidden,
|
|
730
|
+
disabled,
|
|
731
|
+
isDefault: action.default === true,
|
|
732
|
+
separated: action.separated === true,
|
|
733
|
+
order: typeof action.order === 'number' ? action.order : undefined,
|
|
734
|
+
depth,
|
|
735
|
+
optionsPairs: command.optionsPairs,
|
|
736
|
+
metadataPairs: command.metadataPairs,
|
|
737
|
+
submenuExpression: items.expression,
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function flattenActions(actions, prefix, depth = 0) {
|
|
741
|
+
const rows = [];
|
|
742
|
+
actions.forEach((action, index) => {
|
|
743
|
+
const id = `${prefix}.${index}`;
|
|
744
|
+
rows.push(toActionView(action, id, depth));
|
|
745
|
+
const items = resolveItems(action.items);
|
|
746
|
+
if (items.children.length) {
|
|
747
|
+
rows.push(...flattenActions(items.children, id, depth + 1));
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
return rows;
|
|
751
|
+
}
|
|
752
|
+
function groupByScope(actions) {
|
|
753
|
+
const map = new Map();
|
|
754
|
+
for (const action of actions) {
|
|
755
|
+
const scope = action.scope || 'individual';
|
|
756
|
+
const list = map.get(scope) ?? [];
|
|
757
|
+
list.push(action);
|
|
758
|
+
map.set(scope, list);
|
|
759
|
+
}
|
|
760
|
+
const extra = [...map.keys()].filter((scope) => !SCOPE_ORDER.includes(scope));
|
|
761
|
+
return [...SCOPE_ORDER, ...extra]
|
|
762
|
+
.filter((scope) => (map.get(scope)?.length ?? 0) > 0)
|
|
763
|
+
.map((scope) => ({ scope, actions: map.get(scope) ?? [] }));
|
|
764
|
+
}
|
|
765
|
+
function toSection(id, kind, actions, extra, allowEmpty = false) {
|
|
766
|
+
const flat = flattenActions(actions, id);
|
|
767
|
+
if (!flat.length && !allowEmpty) {
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
return {
|
|
771
|
+
id,
|
|
772
|
+
kind,
|
|
773
|
+
views: extra?.views ?? [],
|
|
774
|
+
relatedTitle: extra?.relatedTitle,
|
|
775
|
+
relatedEntity: extra?.relatedEntity,
|
|
776
|
+
relatedLayoutType: extra?.relatedLayoutType,
|
|
777
|
+
layoutTitle: extra?.layoutTitle,
|
|
778
|
+
layoutDescription: extra?.layoutDescription,
|
|
779
|
+
groups: groupByScope(flat),
|
|
780
|
+
actionCount: flat.length,
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function queryViews(views) {
|
|
784
|
+
return (views ?? []).map((view) => ({
|
|
785
|
+
name: view.name,
|
|
786
|
+
title: humanText(view.title),
|
|
787
|
+
}));
|
|
788
|
+
}
|
|
789
|
+
function relatedLayoutType(related) {
|
|
790
|
+
const type = related.layout?.type;
|
|
791
|
+
return typeof type === 'string' ? type : undefined;
|
|
792
|
+
}
|
|
793
|
+
function buildLayoutSections(entity) {
|
|
794
|
+
const master = entity.interfaces?.master;
|
|
795
|
+
const sections = [];
|
|
796
|
+
const list = toSection('list', 'list', layoutActions(master?.list), {
|
|
797
|
+
layoutTitle: humanText(master?.list?.title),
|
|
798
|
+
layoutDescription: humanText(master?.list?.description),
|
|
799
|
+
views: queryViews(master?.list?.views),
|
|
800
|
+
}, true);
|
|
801
|
+
if (list) {
|
|
802
|
+
sections.push(list);
|
|
803
|
+
}
|
|
804
|
+
const record = toSection('record', 'record', layoutActions(master?.single), {
|
|
805
|
+
layoutTitle: humanText(master?.single?.title),
|
|
806
|
+
layoutDescription: humanText(master?.single?.description),
|
|
807
|
+
}, true);
|
|
808
|
+
if (record) {
|
|
809
|
+
sections.push(record);
|
|
810
|
+
}
|
|
811
|
+
const create = toSection('create', 'create', layoutActions(master?.create), {
|
|
812
|
+
layoutTitle: humanText(master?.create?.title),
|
|
813
|
+
}, true);
|
|
814
|
+
if (create) {
|
|
815
|
+
sections.push(create);
|
|
816
|
+
}
|
|
817
|
+
const update = toSection('update', 'update', layoutActions(master?.update), {
|
|
818
|
+
layoutTitle: humanText(master?.update?.title),
|
|
819
|
+
}, true);
|
|
820
|
+
if (update) {
|
|
821
|
+
sections.push(update);
|
|
822
|
+
}
|
|
823
|
+
const detailList = toSection('detail-list', 'detail-list', layoutActions(entity.interfaces?.detail?.list), {
|
|
824
|
+
layoutTitle: humanText(entity.interfaces?.detail?.list?.title),
|
|
825
|
+
layoutDescription: humanText(entity.interfaces?.detail?.list?.description),
|
|
826
|
+
});
|
|
827
|
+
if (detailList) {
|
|
828
|
+
sections.push(detailList);
|
|
829
|
+
}
|
|
830
|
+
(entity.relatedEntities ?? []).forEach((related, index) => {
|
|
831
|
+
const relatedActions = asActions(related.actions);
|
|
832
|
+
const section = toSection(`related:${index}`, 'related', relatedActions, {
|
|
833
|
+
relatedTitle: humanText(related.title),
|
|
834
|
+
relatedEntity: related.entity,
|
|
835
|
+
relatedLayoutType: relatedLayoutType(related),
|
|
836
|
+
});
|
|
837
|
+
if (section) {
|
|
838
|
+
sections.push(section);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
return sections;
|
|
842
|
+
}
|
|
843
|
+
//#endregion
|
|
352
844
|
|
|
845
|
+
const PROPERTY_SCHEMA_FLAG_KEYS = [
|
|
846
|
+
'nullable',
|
|
847
|
+
'unique',
|
|
848
|
+
'readonly',
|
|
849
|
+
'visible',
|
|
850
|
+
'searchable',
|
|
851
|
+
'full-text',
|
|
852
|
+
'filterable',
|
|
853
|
+
'auditable',
|
|
854
|
+
];
|
|
855
|
+
const PROPERTY_SCHEMA_PAIR_KEYS = ['data-type', 'group', 'default-value'];
|
|
856
|
+
const PROPERTY_PRESENTATION_FLAG_KEYS = [
|
|
857
|
+
'inline-filter',
|
|
858
|
+
'sortable',
|
|
859
|
+
'advanced-filter',
|
|
860
|
+
'preload-filter',
|
|
861
|
+
];
|
|
862
|
+
const PROPERTY_PRESENTATION_PAIR_KEYS = [
|
|
863
|
+
'editor',
|
|
864
|
+
'widget-path',
|
|
865
|
+
'widget-mode',
|
|
866
|
+
'widget-id',
|
|
867
|
+
'filter-widget',
|
|
868
|
+
];
|
|
869
|
+
const PROPERTY_SCHEMA_ORDER = [
|
|
870
|
+
'data-type',
|
|
871
|
+
'nullable',
|
|
872
|
+
'group',
|
|
873
|
+
'unique',
|
|
874
|
+
'readonly',
|
|
875
|
+
'visible',
|
|
876
|
+
'searchable',
|
|
877
|
+
'full-text',
|
|
878
|
+
'filterable',
|
|
879
|
+
'auditable',
|
|
880
|
+
'default-value',
|
|
881
|
+
];
|
|
882
|
+
const PROPERTY_PRESENTATION_ORDER = [
|
|
883
|
+
'editor',
|
|
884
|
+
'inline-filter',
|
|
885
|
+
'advanced-filter',
|
|
886
|
+
'sortable',
|
|
887
|
+
'widget-path',
|
|
888
|
+
'widget-mode',
|
|
889
|
+
'widget-id',
|
|
890
|
+
'filter-widget',
|
|
891
|
+
'preload-filter',
|
|
892
|
+
];
|
|
353
893
|
//#endregion
|
|
354
|
-
|
|
355
|
-
|
|
894
|
+
//#region ----- JSON / scalar -----
|
|
895
|
+
function formatScalar(value) {
|
|
896
|
+
if (value === undefined || typeof value === 'function') {
|
|
897
|
+
return undefined;
|
|
898
|
+
}
|
|
899
|
+
if (value === null) {
|
|
900
|
+
return 'null';
|
|
901
|
+
}
|
|
902
|
+
if (typeof value === 'string') {
|
|
903
|
+
const trimmed = value.trim();
|
|
904
|
+
return trimmed || undefined;
|
|
905
|
+
}
|
|
906
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
907
|
+
return String(value);
|
|
908
|
+
}
|
|
909
|
+
return undefined;
|
|
910
|
+
}
|
|
911
|
+
function resolvePropertyDataType(schemaDataType, normalizedDataType, editor, widgetDataTypes) {
|
|
912
|
+
const widgetName = typeof editor === 'string' ? editor.trim() : '';
|
|
913
|
+
const fromWidget = widgetName ? widgetDataTypes[widgetName] : undefined;
|
|
914
|
+
if (fromWidget) {
|
|
915
|
+
return fromWidget;
|
|
916
|
+
}
|
|
917
|
+
return formatScalar(schemaDataType) ?? formatScalar(normalizedDataType);
|
|
918
|
+
}
|
|
919
|
+
function pushFlag(flags, labelKey, value, always = false) {
|
|
920
|
+
if (typeof value !== 'boolean') {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (!always && !value) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (flags.some((flag) => flag.labelKey === labelKey)) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
flags.push({ labelKey, on: value });
|
|
930
|
+
}
|
|
931
|
+
function pushPair(pairs, labelKey, value) {
|
|
932
|
+
const text = formatScalar(value);
|
|
933
|
+
if (!text || pairs.some((pair) => pair.labelKey === labelKey)) {
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
pairs.push({ labelKey, value: text });
|
|
937
|
+
}
|
|
938
|
+
function pushJson(blocks, labelKey, value) {
|
|
939
|
+
const pairs = flattenToPairs(value);
|
|
940
|
+
if (!pairs.length || blocks.some((block) => block.labelKey === labelKey)) {
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
blocks.push({ labelKey, pairs });
|
|
944
|
+
}
|
|
945
|
+
function formatAction(action) {
|
|
946
|
+
if (Array.isArray(action)) {
|
|
947
|
+
return action.filter((item) => typeof item === 'string' && item.trim()).join(', ');
|
|
948
|
+
}
|
|
949
|
+
return typeof action === 'string' ? action.trim() : '';
|
|
950
|
+
}
|
|
951
|
+
//#endregion
|
|
952
|
+
//#region ----- Build details -----
|
|
953
|
+
function hasPropertyDetails(details) {
|
|
954
|
+
return (details.flags.length > 0 ||
|
|
955
|
+
details.pairs.length > 0 ||
|
|
956
|
+
details.triggers.length > 0 ||
|
|
957
|
+
details.validations.length > 0 ||
|
|
958
|
+
details.jsonBlocks.length > 0);
|
|
959
|
+
}
|
|
960
|
+
function propertyFlag(details, key) {
|
|
961
|
+
return details.flags.find((flag) => flag.labelKey === key)?.on;
|
|
962
|
+
}
|
|
963
|
+
function propertyFlagsNamed(details, keys) {
|
|
964
|
+
return keys
|
|
965
|
+
.map((key) => details.flags.find((flag) => flag.labelKey === key))
|
|
966
|
+
.filter((flag) => !!flag);
|
|
967
|
+
}
|
|
968
|
+
function propertyPairsNamed(details, keys) {
|
|
969
|
+
return keys
|
|
970
|
+
.map((key) => details.pairs.find((pair) => pair.labelKey === key))
|
|
971
|
+
.filter((pair) => !!pair);
|
|
972
|
+
}
|
|
973
|
+
function propertyEntries(details, pairKeys, flagKeys, order) {
|
|
974
|
+
const byKey = new Map();
|
|
975
|
+
for (const pair of propertyPairsNamed(details, pairKeys)) {
|
|
976
|
+
byKey.set(pair.labelKey, { kind: 'pair', labelKey: pair.labelKey, value: pair.value });
|
|
977
|
+
}
|
|
978
|
+
for (const flag of propertyFlagsNamed(details, flagKeys)) {
|
|
979
|
+
byKey.set(flag.labelKey, { kind: 'flag', labelKey: flag.labelKey, on: flag.on });
|
|
980
|
+
}
|
|
981
|
+
return order
|
|
982
|
+
.map((key) => byKey.get(key))
|
|
983
|
+
.filter((entry) => !!entry);
|
|
984
|
+
}
|
|
985
|
+
function buildPropertyDetails(layout, normalized, widgetDataTypes = {}) {
|
|
986
|
+
const flags = [];
|
|
987
|
+
const pairs = [];
|
|
988
|
+
const triggers = [];
|
|
989
|
+
const validations = [];
|
|
990
|
+
const jsonBlocks = [];
|
|
991
|
+
const schema = layout?.schema;
|
|
992
|
+
const widget = schema?.interface;
|
|
993
|
+
const features = normalized?.features;
|
|
994
|
+
const list = layout?.options;
|
|
995
|
+
pushFlag(flags, 'nullable', schema?.nullable ?? normalized?.fieldFeatures?.nullable, true);
|
|
996
|
+
pushFlag(flags, 'unique', schema?.unique?.enabled);
|
|
997
|
+
const readonly = schema?.readonly ?? normalized?.fieldFeatures?.readOnly;
|
|
998
|
+
if (typeof readonly === 'boolean') {
|
|
999
|
+
pushFlag(flags, 'readonly', readonly);
|
|
1000
|
+
}
|
|
1001
|
+
else {
|
|
1002
|
+
pushPair(pairs, 'readonly', readonly);
|
|
1003
|
+
}
|
|
1004
|
+
const visible = schema?.visible;
|
|
1005
|
+
if (typeof visible === 'boolean') {
|
|
1006
|
+
if (!visible) {
|
|
1007
|
+
pushFlag(flags, 'visible', false, true);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
pushPair(pairs, 'visible', visible);
|
|
1012
|
+
}
|
|
1013
|
+
pushFlag(flags, 'searchable', features?.searchable?.enabled);
|
|
1014
|
+
pushFlag(flags, 'full-text', features?.searchable?.fullText);
|
|
1015
|
+
pushFlag(flags, 'filterable', features?.filterable?.enabled);
|
|
1016
|
+
pushFlag(flags, 'inline-filter', features?.filterable?.inline ?? list?.filter?.inline?.enabled, true);
|
|
1017
|
+
pushFlag(flags, 'sortable', features?.sortable?.enabled ?? list?.sort?.enabled, true);
|
|
1018
|
+
pushFlag(flags, 'auditable', features?.auditable?.enabled);
|
|
1019
|
+
pushFlag(flags, 'advanced-filter', list?.filter?.advance?.enabled, true);
|
|
1020
|
+
pushFlag(flags, 'preload-filter', list?.filter?.preload?.enabled);
|
|
1021
|
+
pushPair(pairs, 'group', layout?.groupId);
|
|
1022
|
+
const editor = widget?.type ?? normalized?.interface?.name;
|
|
1023
|
+
pushPair(pairs, 'data-type', resolvePropertyDataType(schema?.dataType, normalized?.dataType, editor, widgetDataTypes));
|
|
1024
|
+
pushPair(pairs, 'editor', editor);
|
|
1025
|
+
pushPair(pairs, 'widget-path', widget?.path);
|
|
1026
|
+
pushPair(pairs, 'widget-mode', widget?.mode);
|
|
1027
|
+
pushPair(pairs, 'widget-id', widget?.id);
|
|
1028
|
+
pushPair(pairs, 'filter-widget', list?.filter?.advance?.widgetType);
|
|
1029
|
+
const defaultValue = schema?.defaultValue ?? normalized?.defaultValue;
|
|
1030
|
+
const defaultText = formatScalar(defaultValue);
|
|
1031
|
+
if (defaultText) {
|
|
1032
|
+
pushPair(pairs, 'default-value', defaultText);
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
pushJson(jsonBlocks, 'default-value', defaultValue);
|
|
1036
|
+
}
|
|
1037
|
+
for (const trigger of widget?.triggers ?? []) {
|
|
1038
|
+
const event = typeof trigger.event === 'string' ? trigger.event.trim() : '';
|
|
1039
|
+
const action = formatAction(trigger.action);
|
|
1040
|
+
if (!event && !action) {
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
triggers.push({
|
|
1044
|
+
event,
|
|
1045
|
+
action,
|
|
1046
|
+
disabled: !!trigger.disabled,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
const rules = layout?.validations ?? normalized?.validations ?? [];
|
|
1050
|
+
for (const rule of rules) {
|
|
1051
|
+
const name = typeof rule.rule === 'string' ? rule.rule.trim() : '';
|
|
1052
|
+
if (!name) {
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
validations.push({
|
|
1056
|
+
rule: name,
|
|
1057
|
+
message: typeof rule.message === 'string' ? rule.message.trim() || undefined : undefined,
|
|
1058
|
+
optionsPairs: flattenToPairs(rule.options),
|
|
1059
|
+
disabled: 'disabled' in rule && rule.disabled === true,
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
pushJson(jsonBlocks, 'widget-options', widget?.options ?? normalized?.interface?.options);
|
|
1063
|
+
pushJson(jsonBlocks, 'value-transforms', widget?.valueTransforms);
|
|
1064
|
+
pushJson(jsonBlocks, 'widget-children', widget?.children);
|
|
1065
|
+
return { flags, pairs, triggers, validations, jsonBlocks };
|
|
356
1066
|
}
|
|
1067
|
+
//#endregion
|
|
1068
|
+
|
|
1069
|
+
//#region ----- Imports -----
|
|
1070
|
+
//#endregion
|
|
1071
|
+
//#region ----- Constants -----
|
|
1072
|
+
const PRIMARY_ACTION_TABS = ['list', 'record', 'create', 'update'];
|
|
1073
|
+
const CODE_PAIR_KEYS = new Set([
|
|
1074
|
+
'editor',
|
|
1075
|
+
'widget-path',
|
|
1076
|
+
'widget-mode',
|
|
1077
|
+
'widget-id',
|
|
1078
|
+
'filter-widget',
|
|
1079
|
+
]);
|
|
1080
|
+
//#endregion
|
|
1081
|
+
//#region ----- Component -----
|
|
357
1082
|
class AXPlatformExplorerEntityDetailComponent {
|
|
1083
|
+
//#endregion
|
|
358
1084
|
constructor() {
|
|
359
1085
|
this.payload = input(/* @ts-ignore */
|
|
360
1086
|
...(ngDevMode ? [undefined, { debugName: "payload" }] : /* istanbul ignore next */ []));
|
|
361
|
-
|
|
362
|
-
|
|
1087
|
+
//#region ----- Services & Dependencies -----
|
|
1088
|
+
this.dataService = inject(PlatformExplorerDataService);
|
|
1089
|
+
this.destroyRef = inject(DestroyRef);
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region ----- State Signals -----
|
|
1092
|
+
this.detail = signal(null, /* @ts-ignore */
|
|
1093
|
+
...(ngDevMode ? [{ debugName: "detail" }] : /* istanbul ignore next */ []));
|
|
363
1094
|
this.loading = signal(false, /* @ts-ignore */
|
|
364
1095
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
365
|
-
this.
|
|
1096
|
+
this.loadError = signal(false, /* @ts-ignore */
|
|
1097
|
+
...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
1098
|
+
this.activeSection = this.dataService.activeEntitySection;
|
|
1099
|
+
this.selectedName = signal(null, /* @ts-ignore */
|
|
1100
|
+
...(ngDevMode ? [{ debugName: "selectedName" }] : /* istanbul ignore next */ []));
|
|
1101
|
+
this.selectedActionId = linkedSignal({ ...(ngDevMode ? { debugName: "selectedActionId" } : /* istanbul ignore next */ {}), source: () => this.activeSection(),
|
|
1102
|
+
computation: () => null });
|
|
1103
|
+
this.actionQuery = linkedSignal({ ...(ngDevMode ? { debugName: "actionQuery" } : /* istanbul ignore next */ {}), source: () => this.activeSection(),
|
|
1104
|
+
computation: () => '' });
|
|
1105
|
+
//#endregion
|
|
1106
|
+
//#region ----- Computed Properties -----
|
|
1107
|
+
this.properties = computed(() => this.mergeProperties(this.detail()), /* @ts-ignore */
|
|
1108
|
+
...(ngDevMode ? [{ debugName: "properties" }] : /* istanbul ignore next */ []));
|
|
1109
|
+
this.layoutSections = computed(() => {
|
|
1110
|
+
const detail = this.detail();
|
|
1111
|
+
return detail ? buildLayoutSections(detail.layout) : [];
|
|
1112
|
+
}, /* @ts-ignore */
|
|
1113
|
+
...(ngDevMode ? [{ debugName: "layoutSections" }] : /* istanbul ignore next */ []));
|
|
1114
|
+
this.selectedProperty = computed(() => {
|
|
1115
|
+
const name = this.selectedName();
|
|
1116
|
+
if (!name) {
|
|
1117
|
+
return null;
|
|
1118
|
+
}
|
|
1119
|
+
return this.properties().find((row) => row.name === name) ?? null;
|
|
1120
|
+
}, /* @ts-ignore */
|
|
1121
|
+
...(ngDevMode ? [{ debugName: "selectedProperty" }] : /* istanbul ignore next */ []));
|
|
1122
|
+
this.isFieldSection = computed(() => this.activeSection() === 'properties', /* @ts-ignore */
|
|
1123
|
+
...(ngDevMode ? [{ debugName: "isFieldSection" }] : /* istanbul ignore next */ []));
|
|
1124
|
+
this.inspectorOpen = computed(() => this.isFieldSection() ? this.selectedProperty() != null : this.selectedAction() != null, /* @ts-ignore */
|
|
1125
|
+
...(ngDevMode ? [{ debugName: "inspectorOpen" }] : /* istanbul ignore next */ []));
|
|
1126
|
+
this.inspectorAriaKey = computed(() => this.isFieldSection()
|
|
1127
|
+
? '@platform-dev-tools:module.property-details.field-definition'
|
|
1128
|
+
: '@platform-dev-tools:module.action-details.action-definition', /* @ts-ignore */
|
|
1129
|
+
...(ngDevMode ? [{ debugName: "inspectorAriaKey" }] : /* istanbul ignore next */ []));
|
|
1130
|
+
this.activeLayout = computed(() => {
|
|
1131
|
+
const section = this.activeSection();
|
|
1132
|
+
if (section === 'properties') {
|
|
1133
|
+
return null;
|
|
1134
|
+
}
|
|
1135
|
+
return this.layoutSections().find((item) => item.id === section || item.kind === section) ?? null;
|
|
1136
|
+
}, /* @ts-ignore */
|
|
1137
|
+
...(ngDevMode ? [{ debugName: "activeLayout" }] : /* istanbul ignore next */ []));
|
|
1138
|
+
this.activeActions = computed(() => {
|
|
1139
|
+
const layout = this.activeLayout();
|
|
1140
|
+
if (!layout) {
|
|
1141
|
+
return [];
|
|
1142
|
+
}
|
|
1143
|
+
return layout.groups.flatMap((group) => group.actions);
|
|
1144
|
+
}, /* @ts-ignore */
|
|
1145
|
+
...(ngDevMode ? [{ debugName: "activeActions" }] : /* istanbul ignore next */ []));
|
|
1146
|
+
this.filteredActions = computed(() => {
|
|
1147
|
+
const query = this.actionQuery().trim().toLowerCase();
|
|
1148
|
+
const rows = this.activeActions();
|
|
1149
|
+
if (!query) {
|
|
1150
|
+
return rows;
|
|
1151
|
+
}
|
|
1152
|
+
return rows.filter((row) => this.matchesActionQuery(row, query));
|
|
1153
|
+
}, /* @ts-ignore */
|
|
1154
|
+
...(ngDevMode ? [{ debugName: "filteredActions" }] : /* istanbul ignore next */ []));
|
|
1155
|
+
this.selectedAction = computed(() => {
|
|
1156
|
+
const id = this.selectedActionId();
|
|
1157
|
+
const rows = this.activeActions();
|
|
1158
|
+
if (id) {
|
|
1159
|
+
const match = rows.find((row) => row.id === id);
|
|
1160
|
+
if (match) {
|
|
1161
|
+
return match;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return rows[0] ?? null;
|
|
1165
|
+
}, /* @ts-ignore */
|
|
1166
|
+
...(ngDevMode ? [{ debugName: "selectedAction" }] : /* istanbul ignore next */ []));
|
|
1167
|
+
this.selectedSchemaEntries = computed(() => {
|
|
1168
|
+
const field = this.selectedProperty();
|
|
1169
|
+
return field ? this.schemaEntries(field.details) : [];
|
|
1170
|
+
}, /* @ts-ignore */
|
|
1171
|
+
...(ngDevMode ? [{ debugName: "selectedSchemaEntries" }] : /* istanbul ignore next */ []));
|
|
1172
|
+
this.selectedPresentationEntries = computed(() => {
|
|
1173
|
+
const field = this.selectedProperty();
|
|
1174
|
+
return field ? this.presentationEntries(field.details) : [];
|
|
1175
|
+
}, /* @ts-ignore */
|
|
1176
|
+
...(ngDevMode ? [{ debugName: "selectedPresentationEntries" }] : /* istanbul ignore next */ []));
|
|
1177
|
+
this.destroyRef.onDestroy(() => this.dataService.clearEntityTabs());
|
|
366
1178
|
effect(() => {
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
1179
|
+
const summary = this.payload();
|
|
1180
|
+
void this.loadDetail(summary);
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
//#region ----- Event Handlers -----
|
|
1184
|
+
selectProperty(name) {
|
|
1185
|
+
this.selectedName.set(name);
|
|
1186
|
+
}
|
|
1187
|
+
selectAction(id) {
|
|
1188
|
+
this.selectedActionId.set(id);
|
|
1189
|
+
}
|
|
1190
|
+
isSelected(name) {
|
|
1191
|
+
return this.selectedName() === name;
|
|
1192
|
+
}
|
|
1193
|
+
isActionSelected(id) {
|
|
1194
|
+
return this.selectedAction()?.id === id;
|
|
1195
|
+
}
|
|
1196
|
+
onActionSearchChanged(event) {
|
|
1197
|
+
this.actionQuery.set(event.value ?? '');
|
|
1198
|
+
}
|
|
1199
|
+
flagValue(details, key) {
|
|
1200
|
+
return propertyFlag(details, key);
|
|
1201
|
+
}
|
|
1202
|
+
isCodePair(key) {
|
|
1203
|
+
return CODE_PAIR_KEYS.has(key);
|
|
1204
|
+
}
|
|
1205
|
+
isTypePair(key) {
|
|
1206
|
+
return key === 'data-type';
|
|
1207
|
+
}
|
|
1208
|
+
hiddenFlag(action) {
|
|
1209
|
+
return this.yesNoFlag(action.hidden);
|
|
1210
|
+
}
|
|
1211
|
+
disabledFlag(action) {
|
|
1212
|
+
return this.yesNoFlag(action.disabled);
|
|
1213
|
+
}
|
|
1214
|
+
hiddenExpression(action) {
|
|
1215
|
+
return this.expressionValue(action.hidden);
|
|
1216
|
+
}
|
|
1217
|
+
disabledExpression(action) {
|
|
1218
|
+
return this.expressionValue(action.disabled);
|
|
1219
|
+
}
|
|
1220
|
+
//#endregion
|
|
1221
|
+
//#region ----- Property Details -----
|
|
1222
|
+
schemaEntries(details) {
|
|
1223
|
+
return propertyEntries(details, PROPERTY_SCHEMA_PAIR_KEYS, PROPERTY_SCHEMA_FLAG_KEYS, PROPERTY_SCHEMA_ORDER);
|
|
1224
|
+
}
|
|
1225
|
+
presentationEntries(details) {
|
|
1226
|
+
return propertyEntries(details, PROPERTY_PRESENTATION_PAIR_KEYS, PROPERTY_PRESENTATION_FLAG_KEYS, PROPERTY_PRESENTATION_ORDER);
|
|
1227
|
+
}
|
|
1228
|
+
//#endregion
|
|
1229
|
+
//#region ----- Data Loading -----
|
|
1230
|
+
async loadDetail(summary) {
|
|
1231
|
+
this.actionQuery.set('');
|
|
1232
|
+
this.selectedName.set(null);
|
|
1233
|
+
this.selectedActionId.set(null);
|
|
1234
|
+
if (!summary) {
|
|
1235
|
+
this.detail.set(null);
|
|
1236
|
+
this.loading.set(false);
|
|
1237
|
+
this.loadError.set(false);
|
|
1238
|
+
this.dataService.clearEntityTabs();
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
this.loading.set(true);
|
|
1242
|
+
this.loadError.set(false);
|
|
1243
|
+
this.detail.set(null);
|
|
1244
|
+
try {
|
|
1245
|
+
const detail = await this.dataService.getEntity(summary.module, summary.name);
|
|
1246
|
+
if (this.payload() === summary) {
|
|
1247
|
+
this.detail.set(detail);
|
|
1248
|
+
this.selectedName.set(this.mergeProperties(detail)[0]?.name ?? null);
|
|
1249
|
+
this.dataService.setEntityTabs(this.buildTabs(detail));
|
|
372
1250
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
this.
|
|
377
|
-
if (this.payload() === p) {
|
|
378
|
-
this.entity.set(e ?? null);
|
|
379
|
-
}
|
|
380
|
-
this.loading.set(false);
|
|
381
|
-
});
|
|
1251
|
+
}
|
|
1252
|
+
catch {
|
|
1253
|
+
if (this.payload() === summary) {
|
|
1254
|
+
this.loadError.set(true);
|
|
382
1255
|
}
|
|
383
|
-
|
|
384
|
-
|
|
1256
|
+
}
|
|
1257
|
+
finally {
|
|
1258
|
+
if (this.payload() === summary) {
|
|
385
1259
|
this.loading.set(false);
|
|
386
1260
|
}
|
|
387
|
-
}
|
|
1261
|
+
}
|
|
388
1262
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
@if (entity(); as e) {
|
|
393
|
-
<dl class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 mb-3 m-0">
|
|
394
|
-
<dt class="font-semibold text-muted">{{ '@platform-dev-tools:module.terms.module' | translate | async }}</dt><dd class="m-0">{{ e.module }}</dd>
|
|
395
|
-
<dt class="font-semibold text-muted">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt><dd class="m-0">{{ e.name }}</dd>
|
|
396
|
-
@if (e.title) {
|
|
397
|
-
<dt class="font-semibold text-muted">{{ '@platform-dev-tools:module.terms.title' | translate | async }}</dt><dd class="m-0">{{ e.title | translate | async}}</dd>
|
|
398
|
-
}
|
|
399
|
-
@if (e.formats.plural) {
|
|
400
|
-
<dt class="font-semibold text-muted">{{ '@platform-dev-tools:module.terms.plural' | translate | async }}</dt><dd class="m-0">{{ e.formats.plural | translate | async}}</dd>
|
|
401
|
-
}
|
|
402
|
-
</dl>
|
|
403
|
-
@if (e.properties && e.properties.length > 0) {
|
|
404
|
-
<p class="mb-2 mt-3 font-bold">{{ '@platform-dev-tools:module.terms.properties' | translate | async }} ({{ e.properties.length }})</p>
|
|
405
|
-
<div class="flex-1 min-h-0 overflow-auto border border-lightest rounded-md">
|
|
406
|
-
<table class="w-full border-collapse text-[13px]">
|
|
407
|
-
<thead>
|
|
408
|
-
<tr>
|
|
409
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</th>
|
|
410
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.title' | translate | async }}</th>
|
|
411
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.type' | translate | async }}</th>
|
|
412
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.description' | translate | async }}</th>
|
|
413
|
-
</tr>
|
|
414
|
-
</thead>
|
|
415
|
-
<tbody class="axp-entity-detail-tbody">
|
|
416
|
-
@for (p of e.properties; track p.name) {
|
|
417
|
-
<tr>
|
|
418
|
-
<td class="p-2 px-3 border-b border-lightest"><code class="text-xs bg-lighter px-1.5 py-0.5 rounded">{{ p.name }}</code></td>
|
|
419
|
-
<td class="p-2 px-3 border-b border-lightest">{{ p.title | translate | async }}</td>
|
|
420
|
-
<td class="p-2 px-3 border-b border-lightest">{{ p.schema.dataType }}</td>
|
|
421
|
-
<td class="p-2 px-3 border-b border-lightest">@if (p.description) { {{ p.description | translate | async }} } @else { – }</td>
|
|
422
|
-
</tr>
|
|
423
|
-
}
|
|
424
|
-
</tbody>
|
|
425
|
-
</table>
|
|
426
|
-
</div>
|
|
1263
|
+
buildTabs(detail) {
|
|
1264
|
+
if (!detail) {
|
|
1265
|
+
return [];
|
|
427
1266
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
1267
|
+
const extra = buildLayoutSections(detail.layout).filter((section) => !PRIMARY_ACTION_TABS.includes(section.kind));
|
|
1268
|
+
const tabs = [
|
|
1269
|
+
{ id: 'properties', textKey: '@platform-dev-tools:module.terms.properties' },
|
|
1270
|
+
];
|
|
1271
|
+
for (const kind of PRIMARY_ACTION_TABS) {
|
|
1272
|
+
tabs.push({ id: kind, textKey: `@platform-dev-tools:module.layouts.${kind}` });
|
|
1273
|
+
}
|
|
1274
|
+
for (const layout of extra) {
|
|
1275
|
+
tabs.push({
|
|
1276
|
+
id: layout.id,
|
|
1277
|
+
textKey: layout.kind === 'related'
|
|
1278
|
+
? '@platform-dev-tools:module.layouts.related'
|
|
1279
|
+
: `@platform-dev-tools:module.layouts.${layout.kind}`,
|
|
1280
|
+
extraText: layout.kind === 'related' ? layout.relatedTitle || layout.relatedEntity : undefined,
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
return tabs;
|
|
1284
|
+
}
|
|
1285
|
+
mergeProperties(detail) {
|
|
1286
|
+
if (!detail) {
|
|
1287
|
+
return [];
|
|
1288
|
+
}
|
|
1289
|
+
const pluginByField = pluginSourceByFieldName(detail.plugins);
|
|
1290
|
+
const widgetDataTypes = detail.widgetDataTypes ?? {};
|
|
1291
|
+
const normalizedByName = new Map((detail.normalized?.fields ?? []).map((field) => [field.name, field]));
|
|
1292
|
+
const rows = [];
|
|
1293
|
+
const seen = new Set();
|
|
1294
|
+
for (const property of detail.layout.properties ?? []) {
|
|
1295
|
+
seen.add(property.name);
|
|
1296
|
+
rows.push(this.toRow(property.name, pluginByField, widgetDataTypes, property, normalizedByName.get(property.name)));
|
|
1297
|
+
}
|
|
1298
|
+
for (const field of detail.normalized?.fields ?? []) {
|
|
1299
|
+
if (seen.has(field.name)) {
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1302
|
+
seen.add(field.name);
|
|
1303
|
+
rows.push(this.toRow(field.name, pluginByField, widgetDataTypes, undefined, field));
|
|
1304
|
+
}
|
|
1305
|
+
return rows;
|
|
1306
|
+
}
|
|
1307
|
+
toRow(name, pluginByField, widgetDataTypes, layout, normalized) {
|
|
1308
|
+
const plugin = pluginByField.get(name);
|
|
1309
|
+
const details = buildPropertyDetails(layout, normalized, widgetDataTypes);
|
|
1310
|
+
const title = this.asText(layout?.title) ?? this.asText(normalized?.title);
|
|
1311
|
+
const description = this.asText(layout?.description) ?? this.asText(normalized?.description);
|
|
1312
|
+
return {
|
|
1313
|
+
name,
|
|
1314
|
+
title,
|
|
1315
|
+
dataType: propertyPairsNamed(details, ['data-type'])[0]?.value ?? '',
|
|
1316
|
+
editor: propertyPairsNamed(details, ['editor'])[0]?.value ?? '',
|
|
1317
|
+
description,
|
|
1318
|
+
pluginName: plugin?.name,
|
|
1319
|
+
pluginTitle: plugin?.title,
|
|
1320
|
+
details,
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
asText(value) {
|
|
1324
|
+
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
1325
|
+
}
|
|
1326
|
+
matchesActionQuery(row, query) {
|
|
1327
|
+
return (row.commandName.toLowerCase().includes(query) ||
|
|
1328
|
+
(row.name?.toLowerCase().includes(query) ?? false) ||
|
|
1329
|
+
(row.title?.toLowerCase().includes(query) ?? false) ||
|
|
1330
|
+
(row.typeLabel?.toLowerCase().includes(query) ?? false) ||
|
|
1331
|
+
row.scope.toLowerCase().includes(query));
|
|
1332
|
+
}
|
|
1333
|
+
yesNoFlag(value) {
|
|
1334
|
+
if (value === 'yes') {
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
if (value === 'no') {
|
|
1338
|
+
return false;
|
|
1339
|
+
}
|
|
1340
|
+
return undefined;
|
|
1341
|
+
}
|
|
1342
|
+
expressionValue(value) {
|
|
1343
|
+
if (!value || value === 'yes' || value === 'no') {
|
|
1344
|
+
return undefined;
|
|
1345
|
+
}
|
|
1346
|
+
return value;
|
|
1347
|
+
}
|
|
1348
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerEntityDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1349
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerEntityDetailComponent, isStandalone: true, selector: "axp-platform-explorer-entity-detail", inputs: { payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col flex-1 min-h-0" }, ngImport: i0, template: "<div class=\"flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading entity layout ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Entity catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Entity documentation with field or action inspector ----- -->\n @else if (detail(); as d) {\n <ax-drawer-container class=\"axp-platform-explorer__docs\">\n <ax-content class=\"axp-platform-explorer__docs-main\">\n <div class=\"axp-platform-explorer__docs-shell\">\n <div class=\"axp-platform-explorer__docs-chrome\">\n <!--->\n <!-- ----- Attached plugins as chips ----- -->\n @if (d.plugins.length) {\n <div class=\"axp-platform-explorer__docs-plugins\">\n @for (plugin of d.plugins; track plugin.name) {\n <span class=\"axp-platform-explorer__docs-chip\">\n <i class=\"fa-light fa-plug\" aria-hidden=\"true\"></i>\n {{ (plugin.title || plugin.name) | translate | async }}\n </span>\n }\n </div>\n }\n <!--->\n <!-- ----- Field column headers stay outside the scrolling rows ----- -->\n @if (isFieldSection() && properties().length) {\n <div class=\"axp-platform-explorer__docs-table-head\" role=\"row\">\n <span role=\"columnheader\">{{ '@platform-dev-tools:module.terms.field' | translate | async }}</span>\n <span role=\"columnheader\">\n {{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}\n </span>\n <span role=\"columnheader\">\n {{ '@platform-dev-tools:module.property-details.nullable' | translate | async }}\n </span>\n </div>\n }\n </div>\n\n <!--->\n <!-- ----- Field table ----- -->\n @if (isFieldSection()) {\n <div class=\"axp-platform-explorer__docs-list\">\n <!--->\n <!-- ----- Empty property list ----- -->\n @if (properties().length === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.messages.no-properties' | translate | async }}\n </p>\n }\n <!-- ----- Field rows ----- -->\n @else {\n <div class=\"axp-platform-explorer__table-wrap axp-platform-explorer__table-wrap--fields\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead class=\"sr-only\">\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.nullable' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of properties(); track row.name) {\n <tr\n class=\"axp-platform-explorer__table-row\"\n [class.axp-platform-explorer__table-row--selected]=\"isSelected(row.name)\"\n (click)=\"selectProperty(row.name)\"\n >\n <td>\n <button\n type=\"button\"\n class=\"axp-platform-explorer__field-button\"\n [attr.aria-pressed]=\"isSelected(row.name)\"\n (click)=\"selectProperty(row.name); $event.stopPropagation()\"\n >\n <code dir=\"ltr\">{{ row.name }}</code>\n </button>\n <!--->\n <!-- ----- Translated property title under the field name ----- -->\n @if (row.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ row.title | translate | async }}\n </div>\n }\n </td>\n <td>\n <!--->\n <!-- ----- Stored data type chip ----- -->\n @if (row.dataType) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row.dataType }}</span>\n }\n <!-- ----- Missing data type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <ng-container\n *ngTemplateOutlet=\"boolCell; context: { value: flagValue(row.details, 'nullable') }\"\n />\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <p class=\"axp-platform-explorer__docs-footnote\">\n {{ '@platform-dev-tools:module.property-details.select-field' | translate | async }}\n </p>\n </div>\n }\n <!-- ----- Action table ----- -->\n @else if (activeLayout(); as layout) {\n <div class=\"axp-platform-explorer__docs-list axp-platform-explorer__docs-list--padded\">\n <div class=\"axp-platform-explorer__docs-toolbar\">\n <div>\n <h2 class=\"axp-platform-explorer__docs-heading\">\n {{ ('@platform-dev-tools:module.layouts.' + layout.kind) | translate | async }}\n </h2>\n <p class=\"axp-platform-explorer__docs-count\">\n {{ ('@platform-dev-tools:module.layouts.' + layout.kind + '-hint') | translate | async }}\n </p>\n <p class=\"axp-platform-explorer__docs-count\">\n <!--->\n <!-- ----- Filtered action count ----- -->\n @if (actionQuery().trim()) {\n {{\n '@platform-dev-tools:module.action-details.action-count-filtered'\n | translate: { params: { shown: filteredActions().length, count: layout.actionCount } }\n | async\n }}\n }\n <!-- ----- Full action count ----- -->\n @else {\n {{\n '@platform-dev-tools:module.layouts.action-count'\n | translate: { params: { count: layout.actionCount } }\n | async\n }}\n }\n </p>\n </div>\n <ax-search-box\n class=\"axp-platform-explorer__docs-search\"\n look=\"fill\"\n [delayTime]=\"200\"\n [value]=\"actionQuery()\"\n [placeholder]=\"\n ('@platform-dev-tools:module.action-details.search-actions' | translate | async) ?? ''\n \"\n (onValueChanged)=\"onActionSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n <div class=\"flex flex-wrap items-center gap-1.5 mb-4\">\n <!--->\n <!-- ----- Related entity identity ----- -->\n @if (layout.relatedEntity) {\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ layout.relatedEntity }}</code>\n }\n <!--->\n <!-- ----- Related layout type ----- -->\n @if (layout.relatedLayoutType) {\n <span class=\"inline-flex items-center rounded-full bg-lighter px-2 py-0.5 text-xs text-muted\">\n {{\n ('@platform-dev-tools:module.layouts.related-types.' + layout.relatedLayoutType)\n | translate | async\n }}\n </span>\n }\n <!--->\n <!-- ----- List query views ----- -->\n @for (view of layout.views; track view.name) {\n <span class=\"inline-flex items-center rounded-full bg-lighter px-2 py-0.5 text-xs text-muted\">\n {{ (view.title || view.name) | translate | async }}\n </span>\n }\n </div>\n <!--->\n <!-- ----- Optional stored layout title ----- -->\n @if (layout.layoutTitle) {\n <p class=\"m-0 mb-2 text-sm\">{{ layout.layoutTitle | translate | async }}</p>\n }\n <!--->\n <!-- ----- Optional stored layout description ----- -->\n @if (layout.layoutDescription) {\n <p class=\"m-0 mb-3 text-sm text-muted\">{{ layout.layoutDescription | translate | async }}</p>\n }\n\n <!--->\n <!-- ----- Empty action list ----- -->\n @if (layout.actionCount === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.messages.no-actions' | translate | async }}\n </p>\n }\n <!-- ----- Search matched no actions ----- -->\n @else if (filteredActions().length === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.action-details.no-matching-actions' | translate | async }}\n </p>\n }\n <!-- ----- Action rows ----- -->\n @else {\n <div class=\"axp-platform-explorer__table-wrap axp-platform-explorer__table-wrap--fields\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.action-details.item' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.priority' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.scope' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (action of filteredActions(); track action.id) {\n <tr\n class=\"axp-platform-explorer__table-row\"\n [class.axp-platform-explorer__table-row--selected]=\"isActionSelected(action.id)\"\n (click)=\"selectAction(action.id)\"\n >\n <td>\n <div [style.padding-inline-start.rem]=\"action.depth\">\n <button\n type=\"button\"\n class=\"axp-platform-explorer__field-button\"\n [attr.aria-pressed]=\"isActionSelected(action.id)\"\n (click)=\"selectAction(action.id); $event.stopPropagation()\"\n >\n <!--->\n <!-- ----- Action icon from the layout ----- -->\n @if (action.icon) {\n <i class=\"text-muted me-1\" [ngClass]=\"action.icon\" aria-hidden=\"true\"></i>\n }\n <code dir=\"ltr\">{{ action.commandName || action.name || '\u2013' }}</code>\n </button>\n <!--->\n <!-- ----- Translated action title ----- -->\n @if (action.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ action.title | translate | async }}\n </div>\n }\n </div>\n </td>\n <td>\n <!--->\n <!-- ----- Action type chip ----- -->\n @if (action.typeLabel) {\n <span class=\"axp-platform-explorer__type-chip\">{{ action.typeLabel }}</span>\n }\n <!-- ----- Missing action type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <span\n class=\"axp-platform-explorer__priority\"\n [class.is-primary]=\"action.priority === 'primary'\"\n >\n {{\n ('@platform-dev-tools:module.action-details.priorities.' + action.priority)\n | translate | async\n }}\n </span>\n </td>\n <td class=\"text-muted\">\n {{\n ('@platform-dev-tools:module.action-details.scopes.' + action.scope) | translate | async\n }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <p class=\"axp-platform-explorer__docs-footnote\">\n {{ '@platform-dev-tools:module.action-details.select-action' | translate | async }}\n </p>\n </div>\n }\n </div>\n </ax-content>\n <ax-drawer\n class=\"axp-platform-explorer__docs-side\"\n [location]=\"'end'\"\n [mode]=\"'push'\"\n [collapsed]=\"!inspectorOpen()\"\n >\n <ax-content\n class=\"axp-platform-explorer__docs-detail\"\n [attr.aria-label]=\"inspectorAriaKey() | translate | async\"\n >\n <!--->\n <!-- ----- Selected field definition ----- -->\n @if (isFieldSection()) {\n <ng-container *ngTemplateOutlet=\"fieldDetail\" />\n }\n <!-- ----- Selected action definition ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"actionDetail\" />\n }\n </ax-content>\n </ax-drawer>\n </ax-drawer-container>\n }\n</div>\n\n<ng-template #boolCell let-value=\"value\">\n <!-- ----- Affirmative flag ----- -->\n @if (value === true) {\n <span class=\"axp-platform-explorer__yes\">\n <i class=\"fa-light fa-check\" aria-hidden=\"true\"></i>\n {{ '@platform-dev-tools:module.property-details.yes' | translate | async }}\n </span>\n }\n <!-- ----- Negative flag ----- -->\n @else if (value === false) {\n {{ '@platform-dev-tools:module.property-details.no' | translate | async }}\n }\n <!-- ----- Unknown flag ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n</ng-template>\n\n<ng-template #kvList let-pairs=\"pairs\">\n <dl class=\"axp-platform-explorer__docs-dl axp-platform-explorer__docs-dl--json\">\n @for (pair of pairs; track pair.path) {\n <dt>\n <code dir=\"ltr\">{{ pair.path || '\u2013' }}</code>\n </dt>\n <dd>\n <code dir=\"ltr\">{{ pair.value }}</code>\n </dd>\n }\n </dl>\n</ng-template>\n\n<ng-template #fieldDetail>\n <!-- ----- Selected field definition ----- -->\n @if (selectedProperty(); as field) {\n <div class=\"axp-platform-explorer__docs-detail-header\">\n <div class=\"axp-platform-explorer__docs-eyebrow\">\n {{ '@platform-dev-tools:module.property-details.field-definition' | translate | async }}\n </div>\n <h2 class=\"axp-platform-explorer__docs-detail-title\">\n {{ (field.title || field.name) | translate | async }}\n </h2>\n <code class=\"axp-platform-explorer__docs-key\" dir=\"ltr\">{{ field.name }}</code>\n <!--->\n <!-- ----- Plugin source of the selected field ----- -->\n @if (field.pluginTitle) {\n <span class=\"axp-platform-explorer__docs-chip axp-platform-explorer__docs-chip--field\">\n <i class=\"fa-light fa-plug\" aria-hidden=\"true\"></i>\n {{ field.pluginTitle | translate | async }}\n </span>\n }\n </div>\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.terms.description' | translate | async }}</h3>\n <p class=\"axp-platform-explorer__docs-description\">\n <!--->\n <!-- ----- Translated field description ----- -->\n @if (field.description) {\n {{ field.description | translate | async }}\n }\n <!-- ----- Missing field description ----- -->\n @else {\n {{ '@platform-dev-tools:module.property-details.no-description' | translate | async }}\n }\n </p>\n </section>\n <!--->\n <!-- ----- Schema flags and scalar pairs ----- -->\n @if (selectedSchemaEntries(); as schema) {\n <!--->\n <!-- ----- Render schema when at least one entry exists ----- -->\n @if (schema.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.schema' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n @for (entry of schema; track entry.labelKey) {\n <dt>{{ ('@platform-dev-tools:module.property-details.' + entry.labelKey) | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Boolean schema flags ----- -->\n @if (entry.kind === 'flag') {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: entry.on }\" />\n }\n <!-- ----- Schema scalar values ----- -->\n @else {\n <!--->\n <!-- ----- Data type shown as a chip ----- -->\n @if (isTypePair(entry.labelKey)) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ entry.value }}</span>\n }\n <!-- ----- Code-like schema values ----- -->\n @else if (isCodePair(entry.labelKey)) {\n <code dir=\"ltr\">{{ entry.value }}</code>\n }\n <!-- ----- Plain schema values ----- -->\n @else {\n {{ entry.value }}\n }\n }\n </dd>\n }\n </dl>\n </section>\n }\n }\n <!--->\n <!-- ----- Presentation flags and widget pairs ----- -->\n @if (selectedPresentationEntries(); as presentation) {\n <!--->\n <!-- ----- Render presentation when at least one entry exists ----- -->\n @if (presentation.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.presentation' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n @for (entry of presentation; track entry.labelKey) {\n <dt>{{ ('@platform-dev-tools:module.property-details.' + entry.labelKey) | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Boolean presentation flags ----- -->\n @if (entry.kind === 'flag') {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: entry.on }\" />\n }\n <!-- ----- Presentation scalar values ----- -->\n @else {\n <!--->\n <!-- ----- Widget identifiers as code ----- -->\n @if (isCodePair(entry.labelKey) || isTypePair(entry.labelKey)) {\n <code dir=\"ltr\">{{ entry.value }}</code>\n }\n <!-- ----- Plain presentation values ----- -->\n @else {\n {{ entry.value }}\n }\n }\n </dd>\n }\n </dl>\n </section>\n }\n }\n <!--->\n <!-- ----- Widget triggers ----- -->\n @if (field.details.triggers.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.triggers' | translate | async }}</h3>\n <div class=\"axp-platform-explorer__prop-stack\">\n @for (trigger of field.details.triggers; track $index) {\n <div class=\"axp-platform-explorer__prop-card\">\n <div class=\"axp-platform-explorer__prop-trigger\">\n <span class=\"text-muted text-xs\">\n {{ '@platform-dev-tools:module.property-details.event' | translate | async }}\n </span>\n <code>{{ trigger.event || '\u2013' }}</code>\n <i class=\"fa-light fa-arrow-right text-muted\" aria-hidden=\"true\"></i>\n <span class=\"text-muted text-xs\">\n {{ '@platform-dev-tools:module.property-details.action' | translate | async }}\n </span>\n <code>{{ trigger.action || '\u2013' }}</code>\n </div>\n <!--->\n <!-- ----- Disabled trigger badge ----- -->\n @if (trigger.disabled) {\n <span class=\"axp-platform-explorer__prop-flag\">\n {{ '@platform-dev-tools:module.property-details.disabled' | translate | async }}\n </span>\n }\n </div>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Validation rules ----- -->\n @if (field.details.validations.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.validations' | translate | async }}</h3>\n <div class=\"axp-platform-explorer__prop-stack\">\n @for (rule of field.details.validations; track $index) {\n <div class=\"axp-platform-explorer__prop-card\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <code>{{ rule.rule }}</code>\n <!--->\n <!-- ----- Disabled validation badge ----- -->\n @if (rule.disabled) {\n <span class=\"axp-platform-explorer__prop-flag\">\n {{ '@platform-dev-tools:module.property-details.disabled' | translate | async }}\n </span>\n }\n </div>\n <!--->\n <!-- ----- Validation message ----- -->\n @if (rule.message) {\n <p class=\"m-0 text-xs text-muted\">{{ rule.message | translate | async }}</p>\n }\n <!--->\n <!-- ----- Flattened validation options ----- -->\n @if (rule.optionsPairs.length) {\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: rule.optionsPairs }\" />\n }\n </div>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Flattened nested JSON (widget options, transforms, children) ----- -->\n @if (field.details.jsonBlocks.length) {\n @for (block of field.details.jsonBlocks; track block.labelKey) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ ('@platform-dev-tools:module.property-details.' + block.labelKey) | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: block.pairs }\" />\n </section>\n }\n }\n }\n <!-- ----- No field selected ----- -->\n @else {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.property-details.select-field' | translate | async }}\n </p>\n }\n</ng-template>\n\n<ng-template #actionDetail>\n <!-- ----- Selected action definition ----- -->\n @if (selectedAction(); as action) {\n <div class=\"axp-platform-explorer__docs-detail-header\">\n <div class=\"axp-platform-explorer__docs-eyebrow\">\n {{ '@platform-dev-tools:module.action-details.action-definition' | translate | async }}\n </div>\n <h2 class=\"axp-platform-explorer__docs-detail-title\">\n {{ (action.title || action.commandName || action.name || '\u2013') | translate | async }}\n </h2>\n <code class=\"axp-platform-explorer__docs-key\" dir=\"ltr\">{{ action.commandName || action.name || '\u2013' }}</code>\n </div>\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.behavior' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n <dt>{{ '@platform-dev-tools:module.action-details.type' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Action type ----- -->\n @if (action.typeLabel) {\n <span class=\"axp-platform-explorer__type-chip\">{{ action.typeLabel }}</span>\n }\n <!-- ----- Missing action type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.priority' | translate | async }}</dt>\n <dd>\n {{ ('@platform-dev-tools:module.action-details.priorities.' + action.priority) | translate | async }}\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.scope' | translate | async }}</dt>\n <dd>{{ ('@platform-dev-tools:module.action-details.scopes.' + action.scope) | translate | async }}</dd>\n <dt>{{ '@platform-dev-tools:module.action-details.default' | translate | async }}</dt>\n <dd>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: action.isDefault }\" />\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.separated' | translate | async }}</dt>\n <dd>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: action.separated }\" />\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.hidden' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Hidden yes/no ----- -->\n @if (hiddenFlag(action) !== undefined) {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: hiddenFlag(action) }\" />\n }\n <!-- ----- Hidden expression ----- -->\n @else if (hiddenExpression(action); as expression) {\n <code dir=\"ltr\">{{ expression }}</code>\n }\n <!-- ----- Hidden unknown ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.disabled' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Disabled yes/no ----- -->\n @if (disabledFlag(action) !== undefined) {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: disabledFlag(action) }\" />\n }\n <!-- ----- Disabled expression ----- -->\n @else if (disabledExpression(action); as expression) {\n <code dir=\"ltr\">{{ expression }}</code>\n }\n <!-- ----- Disabled unknown ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <!--->\n <!-- ----- Named action key ----- -->\n @if (action.name) {\n <dt>{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd>\n <code dir=\"ltr\">{{ action.name }}</code>\n </dd>\n }\n <!--->\n <!-- ----- Color token ----- -->\n @if (action.color) {\n <dt>{{ '@platform-dev-tools:module.action-details.color' | translate | async }}</dt>\n <dd>\n <code dir=\"ltr\">{{ action.color }}</code>\n </dd>\n }\n <!--->\n <!-- ----- Sort order ----- -->\n @if (action.order != null) {\n <dt>{{ '@platform-dev-tools:module.action-details.order' | translate | async }}</dt>\n <dd>{{ action.order }}</dd>\n }\n </dl>\n </section>\n <!--->\n <!-- ----- Keyboard shortcuts ----- -->\n @if (action.shortcuts.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.shortcuts' | translate | async }}</h3>\n <div class=\"flex flex-wrap gap-1.5\">\n @for (shortcut of action.shortcuts; track shortcut) {\n <code>{{ shortcut }}</code>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Permission keys ----- -->\n @if (action.permissions.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.terms.permissions' | translate | async }}</h3>\n <div class=\"flex flex-wrap gap-1.5\">\n @for (permission of action.permissions; track permission) {\n <code>{{ permission }}</code>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Dynamic submenu expression ----- -->\n @if (action.submenuExpression) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.submenu' | translate | async }}</h3>\n <code dir=\"ltr\">{{ action.submenuExpression }}</code>\n </section>\n }\n <!--->\n <!-- ----- Flattened command options ----- -->\n @if (action.optionsPairs.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.options' | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: action.optionsPairs }\" />\n </section>\n }\n <!--->\n <!-- ----- Flattened command metadata ----- -->\n @if (action.metadataPairs.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.metadata' | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: action.metadataPairs }\" />\n </section>\n }\n }\n <!-- ----- No action selected ----- -->\n @else {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.action-details.select-action' | translate | async }}\n </p>\n }\n</ng-template>\n", styles: ["@layer properties;ax-drawer-container.axp-platform-explorer__docs,ax-content.axp-platform-explorer__docs-main{height:100%;min-height:0}.axp-platform-explorer__docs-main{display:flex;height:100%;min-height:0px;min-width:0px;flex:1;flex-direction:column;overflow:hidden;display:flex!important;overflow:hidden!important}.axp-platform-explorer__docs-shell{display:grid;grid-template-rows:auto minmax(0,1fr);height:100%;min-height:0;overflow:hidden}.axp-platform-explorer__docs-chrome{z-index:20;flex-shrink:0;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);scrollbar-gutter:stable}.axp-platform-explorer__docs-chrome:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:var(--color-dark);color:var(--color-on-dark);border-color:var(--color-border-dark)}.axp-platform-explorer__docs-plugins{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 1.5);padding-inline:calc(var(--spacing, .25rem) * 6);padding-block:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-table-head{display:grid;grid-template-columns:46% minmax(0,1fr) minmax(0,1fr);margin-inline:calc(var(--spacing, .25rem) * 6);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-table-head{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-table-head>*{padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}.axp-platform-explorer__docs-chip{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border:1px solid rgb(var(--ax-sys-color-border-warning-lightest-surface))}.axp-platform-explorer__docs-chip--field{margin-top:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__docs-list{min-height:0px;min-width:0px;overflow:auto;padding-inline:calc(var(--spacing, .25rem) * 6);padding-top:0;padding-bottom:calc(var(--spacing, .25rem) * 5);scrollbar-gutter:stable}.axp-platform-explorer__docs-list--padded{padding-top:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-toolbar{margin-bottom:calc(var(--spacing, .25rem) * 5);display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-heading{margin:0;font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__docs-count{margin:0;margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-count{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-search{width:calc(var(--spacing, .25rem) * 52);max-width:100%}.axp-platform-explorer__docs-empty,.axp-platform-explorer__docs-footnote{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-empty,.axp-platform-explorer__docs-footnote{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-empty{padding-block:calc(var(--spacing, .25rem) * 8);text-align:center}.axp-platform-explorer__docs-footnote{margin:0;padding-top:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__docs-side{width:calc(var(--spacing, .25rem) * 80);border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__docs-detail{display:flex;height:100%;min-width:0px;flex-direction:column;overflow:auto;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 5);padding-block:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-eyebrow{margin-bottom:calc(var(--spacing, .25rem) * 2.5);font-size:11px;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-widest, .1em);letter-spacing:var(--tracking-widest, .1em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-eyebrow{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-detail-title{margin:0;margin-bottom:var(--spacing, .25rem);font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);overflow-wrap:break-word}.axp-platform-explorer__docs-key{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__docs-detail-block{margin-top:calc(var(--spacing, .25rem) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-top:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__docs-detail-block h3{margin:0;margin-bottom:calc(var(--spacing, .25rem) * 2.5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__docs-description{margin:0;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-description{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-dl{margin:0;display:grid;column-gap:calc(var(--spacing, .25rem) * 3);row-gap:calc(var(--spacing, .25rem) * 2.5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));grid-template-columns:minmax(0,1fr) auto}.axp-platform-explorer__docs-dl dt{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-dl dt{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-dl dd{margin:0;max-width:calc(var(--spacing, .25rem) * 40);text-align:end;overflow-wrap:break-word}.axp-platform-explorer__docs-actions{display:flex;min-height:0px;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3);overflow:auto;padding-inline:calc(var(--spacing, .25rem) * 6);padding-block:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-layout{margin-top:calc(var(--spacing, .25rem) * 6);display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3);padding-inline:0px}.axp-platform-explorer__docs-actions .axp-platform-explorer__docs-layout{margin-top:0}.axp-platform-explorer__table-wrap{overflow-x:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__table-wrap--fields{overflow:visible;border-radius:0;border-style:var(--tw-border-style);border-width:0px}.axp-platform-explorer__table{width:100%;min-width:36rem;border-collapse:collapse;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table--fields{min-width:0px;table-layout:fixed}.axp-platform-explorer__table--fields th:first-child{width:46%}.axp-platform-explorer__table th{background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default));border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__table th{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__table--fields thead.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.axp-platform-explorer__table td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 4);vertical-align:middle;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__table--fields tbody tr{cursor:pointer}.axp-platform-explorer__table-row--alt td{background-color:rgba(var(--ax-sys-color-lighter-surface))}.axp-platform-explorer__table-row:hover td,.axp-platform-explorer__table-row--selected td{background-color:rgba(var(--ax-sys-color-primary-lightest-surface))}.axp-platform-explorer__table-row--selected td:first-child{box-shadow:inset 3px 0 0 var(--ax-color-primary, currentColor)}:dir(rtl) .axp-platform-explorer__table-row--selected td:first-child{box-shadow:inset -3px 0 0 var(--ax-color-primary, currentColor)}.axp-platform-explorer__table tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0px}.axp-platform-explorer__table-detail td{padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-dl--json{grid-template-columns:minmax(0,1.2fr) minmax(0,1fr)}.axp-platform-explorer__docs-dl--json dd{max-width:none}.axp-platform-explorer__docs-dl--json dt code,.axp-platform-explorer__docs-dl--json dd code{background-color:transparent;padding:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all}.axp-platform-explorer__field-button{margin:0;display:inline-flex;appearance:none;align-items:center;border-style:var(--tw-border-style);border-width:0px;background-color:transparent;padding:0;text-align:start;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-platform-explorer__field-button code{background-color:transparent;padding:0;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table-row--selected .axp-platform-explorer__field-button{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__field-button:hover{text-decoration:underline;text-underline-offset:3px}.axp-platform-explorer__field-title{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__type-chip{display:inline-block;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__unknown{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__unknown{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__yes{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__yes i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__prop-toggle,.axp-platform-explorer__prop-toggle-spacer{display:inline-flex;height:calc(var(--spacing, .25rem) * 7);width:calc(var(--spacing, .25rem) * 7);flex-shrink:0;align-items:center;justify-content:center;border-radius:var(--radius-md, .375rem)}.axp-platform-explorer__prop-toggle{cursor:pointer;appearance:none;border-style:var(--tw-border-style);border-width:0px;background-color:transparent;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-toggle{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-toggle:hover{background-color:rgba(var(--ax-sys-color-lighter-surface));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__prop-toggle i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .15s;transition-duration:.15s}.axp-platform-explorer__prop-toggle.is-open i{rotate:90deg}.axp-platform-explorer__prop-details{margin-inline-start:calc(var(--spacing, .25rem) * 9);display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 4);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__prop-flags{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-flag{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:var(--spacing, .25rem);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__prop-pairs{margin:0;display:grid;column-gap:calc(var(--spacing, .25rem) * 6);row-gap:calc(var(--spacing, .25rem) * 2);grid-template-columns:minmax(7rem,11rem) minmax(0,1fr)}.axp-platform-explorer__prop-pairs dt{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-pairs dt{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-pairs dd{margin:0;min-width:0px}.axp-platform-explorer__prop-pairs code,.axp-platform-explorer__prop-card code,.axp-platform-explorer__prop-trigger code{border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all}.axp-platform-explorer__prop-section{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-section-title{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-section-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-stack{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-card{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}.axp-platform-explorer__prop-trigger{display:flex;flex-wrap:wrap;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-json{margin:0;max-height:calc(var(--spacing, .25rem) * 48);overflow:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding:calc(var(--spacing, .25rem) * 3);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.axp-platform-explorer__table--actions{min-width:36rem}.axp-platform-explorer__priority{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__priority{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__priority.is-primary{--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-primary-surface))}@media(max-width:760px){.axp-platform-explorer__docs-side{width:calc(var(--spacing, .25rem) * 72)}.axp-platform-explorer__docs-plugins,.axp-platform-explorer__docs-list,.axp-platform-explorer__docs-actions{padding-inline:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-table-head{margin-inline:calc(var(--spacing, .25rem) * 5)}}@media(max-width:440px){.axp-platform-explorer__docs-toolbar{display:block}.axp-platform-explorer__docs-search{margin-top:calc(var(--spacing, .25rem) * 3);width:100%}}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@property --tw-duration{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial;--tw-duration: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i3$1.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i4.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "component", type: i5.AXDrawerComponent, selector: "ax-drawer", inputs: ["location", "showBackdrop", "mode", "transition", "closeOnBackdropClick", "backdropClass", "collapsed", "singleOpenMode"], outputs: ["onBackdropClick", "collapsedStateChanged"] }, { kind: "component", type: i5.AXDrawerContainerComponent, selector: "ax-drawer-container" }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
433
1350
|
}
|
|
434
1351
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerEntityDetailComponent, decorators: [{
|
|
435
1352
|
type: Component,
|
|
436
|
-
args: [{ selector: 'axp-platform-explorer-entity-detail', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush,
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
@if (e.formats.plural) {
|
|
446
|
-
<dt class="font-semibold text-muted">{{ '@platform-dev-tools:module.terms.plural' | translate | async }}</dt><dd class="m-0">{{ e.formats.plural | translate | async}}</dd>
|
|
447
|
-
}
|
|
448
|
-
</dl>
|
|
449
|
-
@if (e.properties && e.properties.length > 0) {
|
|
450
|
-
<p class="mb-2 mt-3 font-bold">{{ '@platform-dev-tools:module.terms.properties' | translate | async }} ({{ e.properties.length }})</p>
|
|
451
|
-
<div class="flex-1 min-h-0 overflow-auto border border-lightest rounded-md">
|
|
452
|
-
<table class="w-full border-collapse text-[13px]">
|
|
453
|
-
<thead>
|
|
454
|
-
<tr>
|
|
455
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</th>
|
|
456
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.title' | translate | async }}</th>
|
|
457
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.type' | translate | async }}</th>
|
|
458
|
-
<th class="text-start p-2 px-3 bg-lighter font-semibold border-b border-lightest">{{ '@platform-dev-tools:module.terms.description' | translate | async }}</th>
|
|
459
|
-
</tr>
|
|
460
|
-
</thead>
|
|
461
|
-
<tbody class="axp-entity-detail-tbody">
|
|
462
|
-
@for (p of e.properties; track p.name) {
|
|
463
|
-
<tr>
|
|
464
|
-
<td class="p-2 px-3 border-b border-lightest"><code class="text-xs bg-lighter px-1.5 py-0.5 rounded">{{ p.name }}</code></td>
|
|
465
|
-
<td class="p-2 px-3 border-b border-lightest">{{ p.title | translate | async }}</td>
|
|
466
|
-
<td class="p-2 px-3 border-b border-lightest">{{ p.schema.dataType }}</td>
|
|
467
|
-
<td class="p-2 px-3 border-b border-lightest">@if (p.description) { {{ p.description | translate | async }} } @else { – }</td>
|
|
468
|
-
</tr>
|
|
469
|
-
}
|
|
470
|
-
</tbody>
|
|
471
|
-
</table>
|
|
472
|
-
</div>
|
|
473
|
-
}
|
|
474
|
-
} @else if (loading()) {
|
|
475
|
-
<p class="m-0 text-muted">{{ '@platform-dev-tools:module.terms.loading-entity' | translate | async }}</p>
|
|
476
|
-
}
|
|
477
|
-
</div>
|
|
478
|
-
`, styles: [".axp-entity-detail-tbody tr:last-child td{border-bottom:none}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
1353
|
+
args: [{ selector: 'axp-platform-explorer-entity-detail', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'flex flex-col flex-1 min-h-0' }, imports: [
|
|
1354
|
+
CommonModule,
|
|
1355
|
+
NgTemplateOutlet,
|
|
1356
|
+
AXTranslationModule,
|
|
1357
|
+
AXLoadingModule,
|
|
1358
|
+
AXSearchBoxModule,
|
|
1359
|
+
AXDecoratorModule,
|
|
1360
|
+
AXDrawerModule,
|
|
1361
|
+
AXPStateMessageComponent,
|
|
1362
|
+
], template: "<div class=\"flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading entity layout ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Entity catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Entity documentation with field or action inspector ----- -->\n @else if (detail(); as d) {\n <ax-drawer-container class=\"axp-platform-explorer__docs\">\n <ax-content class=\"axp-platform-explorer__docs-main\">\n <div class=\"axp-platform-explorer__docs-shell\">\n <div class=\"axp-platform-explorer__docs-chrome\">\n <!--->\n <!-- ----- Attached plugins as chips ----- -->\n @if (d.plugins.length) {\n <div class=\"axp-platform-explorer__docs-plugins\">\n @for (plugin of d.plugins; track plugin.name) {\n <span class=\"axp-platform-explorer__docs-chip\">\n <i class=\"fa-light fa-plug\" aria-hidden=\"true\"></i>\n {{ (plugin.title || plugin.name) | translate | async }}\n </span>\n }\n </div>\n }\n <!--->\n <!-- ----- Field column headers stay outside the scrolling rows ----- -->\n @if (isFieldSection() && properties().length) {\n <div class=\"axp-platform-explorer__docs-table-head\" role=\"row\">\n <span role=\"columnheader\">{{ '@platform-dev-tools:module.terms.field' | translate | async }}</span>\n <span role=\"columnheader\">\n {{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}\n </span>\n <span role=\"columnheader\">\n {{ '@platform-dev-tools:module.property-details.nullable' | translate | async }}\n </span>\n </div>\n }\n </div>\n\n <!--->\n <!-- ----- Field table ----- -->\n @if (isFieldSection()) {\n <div class=\"axp-platform-explorer__docs-list\">\n <!--->\n <!-- ----- Empty property list ----- -->\n @if (properties().length === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.messages.no-properties' | translate | async }}\n </p>\n }\n <!-- ----- Field rows ----- -->\n @else {\n <div class=\"axp-platform-explorer__table-wrap axp-platform-explorer__table-wrap--fields\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead class=\"sr-only\">\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.nullable' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of properties(); track row.name) {\n <tr\n class=\"axp-platform-explorer__table-row\"\n [class.axp-platform-explorer__table-row--selected]=\"isSelected(row.name)\"\n (click)=\"selectProperty(row.name)\"\n >\n <td>\n <button\n type=\"button\"\n class=\"axp-platform-explorer__field-button\"\n [attr.aria-pressed]=\"isSelected(row.name)\"\n (click)=\"selectProperty(row.name); $event.stopPropagation()\"\n >\n <code dir=\"ltr\">{{ row.name }}</code>\n </button>\n <!--->\n <!-- ----- Translated property title under the field name ----- -->\n @if (row.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ row.title | translate | async }}\n </div>\n }\n </td>\n <td>\n <!--->\n <!-- ----- Stored data type chip ----- -->\n @if (row.dataType) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row.dataType }}</span>\n }\n <!-- ----- Missing data type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <ng-container\n *ngTemplateOutlet=\"boolCell; context: { value: flagValue(row.details, 'nullable') }\"\n />\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <p class=\"axp-platform-explorer__docs-footnote\">\n {{ '@platform-dev-tools:module.property-details.select-field' | translate | async }}\n </p>\n </div>\n }\n <!-- ----- Action table ----- -->\n @else if (activeLayout(); as layout) {\n <div class=\"axp-platform-explorer__docs-list axp-platform-explorer__docs-list--padded\">\n <div class=\"axp-platform-explorer__docs-toolbar\">\n <div>\n <h2 class=\"axp-platform-explorer__docs-heading\">\n {{ ('@platform-dev-tools:module.layouts.' + layout.kind) | translate | async }}\n </h2>\n <p class=\"axp-platform-explorer__docs-count\">\n {{ ('@platform-dev-tools:module.layouts.' + layout.kind + '-hint') | translate | async }}\n </p>\n <p class=\"axp-platform-explorer__docs-count\">\n <!--->\n <!-- ----- Filtered action count ----- -->\n @if (actionQuery().trim()) {\n {{\n '@platform-dev-tools:module.action-details.action-count-filtered'\n | translate: { params: { shown: filteredActions().length, count: layout.actionCount } }\n | async\n }}\n }\n <!-- ----- Full action count ----- -->\n @else {\n {{\n '@platform-dev-tools:module.layouts.action-count'\n | translate: { params: { count: layout.actionCount } }\n | async\n }}\n }\n </p>\n </div>\n <ax-search-box\n class=\"axp-platform-explorer__docs-search\"\n look=\"fill\"\n [delayTime]=\"200\"\n [value]=\"actionQuery()\"\n [placeholder]=\"\n ('@platform-dev-tools:module.action-details.search-actions' | translate | async) ?? ''\n \"\n (onValueChanged)=\"onActionSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n <div class=\"flex flex-wrap items-center gap-1.5 mb-4\">\n <!--->\n <!-- ----- Related entity identity ----- -->\n @if (layout.relatedEntity) {\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ layout.relatedEntity }}</code>\n }\n <!--->\n <!-- ----- Related layout type ----- -->\n @if (layout.relatedLayoutType) {\n <span class=\"inline-flex items-center rounded-full bg-lighter px-2 py-0.5 text-xs text-muted\">\n {{\n ('@platform-dev-tools:module.layouts.related-types.' + layout.relatedLayoutType)\n | translate | async\n }}\n </span>\n }\n <!--->\n <!-- ----- List query views ----- -->\n @for (view of layout.views; track view.name) {\n <span class=\"inline-flex items-center rounded-full bg-lighter px-2 py-0.5 text-xs text-muted\">\n {{ (view.title || view.name) | translate | async }}\n </span>\n }\n </div>\n <!--->\n <!-- ----- Optional stored layout title ----- -->\n @if (layout.layoutTitle) {\n <p class=\"m-0 mb-2 text-sm\">{{ layout.layoutTitle | translate | async }}</p>\n }\n <!--->\n <!-- ----- Optional stored layout description ----- -->\n @if (layout.layoutDescription) {\n <p class=\"m-0 mb-3 text-sm text-muted\">{{ layout.layoutDescription | translate | async }}</p>\n }\n\n <!--->\n <!-- ----- Empty action list ----- -->\n @if (layout.actionCount === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.messages.no-actions' | translate | async }}\n </p>\n }\n <!-- ----- Search matched no actions ----- -->\n @else if (filteredActions().length === 0) {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.action-details.no-matching-actions' | translate | async }}\n </p>\n }\n <!-- ----- Action rows ----- -->\n @else {\n <div class=\"axp-platform-explorer__table-wrap axp-platform-explorer__table-wrap--fields\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.action-details.item' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.priority' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.action-details.scope' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (action of filteredActions(); track action.id) {\n <tr\n class=\"axp-platform-explorer__table-row\"\n [class.axp-platform-explorer__table-row--selected]=\"isActionSelected(action.id)\"\n (click)=\"selectAction(action.id)\"\n >\n <td>\n <div [style.padding-inline-start.rem]=\"action.depth\">\n <button\n type=\"button\"\n class=\"axp-platform-explorer__field-button\"\n [attr.aria-pressed]=\"isActionSelected(action.id)\"\n (click)=\"selectAction(action.id); $event.stopPropagation()\"\n >\n <!--->\n <!-- ----- Action icon from the layout ----- -->\n @if (action.icon) {\n <i class=\"text-muted me-1\" [ngClass]=\"action.icon\" aria-hidden=\"true\"></i>\n }\n <code dir=\"ltr\">{{ action.commandName || action.name || '\u2013' }}</code>\n </button>\n <!--->\n <!-- ----- Translated action title ----- -->\n @if (action.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ action.title | translate | async }}\n </div>\n }\n </div>\n </td>\n <td>\n <!--->\n <!-- ----- Action type chip ----- -->\n @if (action.typeLabel) {\n <span class=\"axp-platform-explorer__type-chip\">{{ action.typeLabel }}</span>\n }\n <!-- ----- Missing action type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <span\n class=\"axp-platform-explorer__priority\"\n [class.is-primary]=\"action.priority === 'primary'\"\n >\n {{\n ('@platform-dev-tools:module.action-details.priorities.' + action.priority)\n | translate | async\n }}\n </span>\n </td>\n <td class=\"text-muted\">\n {{\n ('@platform-dev-tools:module.action-details.scopes.' + action.scope) | translate | async\n }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <p class=\"axp-platform-explorer__docs-footnote\">\n {{ '@platform-dev-tools:module.action-details.select-action' | translate | async }}\n </p>\n </div>\n }\n </div>\n </ax-content>\n <ax-drawer\n class=\"axp-platform-explorer__docs-side\"\n [location]=\"'end'\"\n [mode]=\"'push'\"\n [collapsed]=\"!inspectorOpen()\"\n >\n <ax-content\n class=\"axp-platform-explorer__docs-detail\"\n [attr.aria-label]=\"inspectorAriaKey() | translate | async\"\n >\n <!--->\n <!-- ----- Selected field definition ----- -->\n @if (isFieldSection()) {\n <ng-container *ngTemplateOutlet=\"fieldDetail\" />\n }\n <!-- ----- Selected action definition ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"actionDetail\" />\n }\n </ax-content>\n </ax-drawer>\n </ax-drawer-container>\n }\n</div>\n\n<ng-template #boolCell let-value=\"value\">\n <!-- ----- Affirmative flag ----- -->\n @if (value === true) {\n <span class=\"axp-platform-explorer__yes\">\n <i class=\"fa-light fa-check\" aria-hidden=\"true\"></i>\n {{ '@platform-dev-tools:module.property-details.yes' | translate | async }}\n </span>\n }\n <!-- ----- Negative flag ----- -->\n @else if (value === false) {\n {{ '@platform-dev-tools:module.property-details.no' | translate | async }}\n }\n <!-- ----- Unknown flag ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n</ng-template>\n\n<ng-template #kvList let-pairs=\"pairs\">\n <dl class=\"axp-platform-explorer__docs-dl axp-platform-explorer__docs-dl--json\">\n @for (pair of pairs; track pair.path) {\n <dt>\n <code dir=\"ltr\">{{ pair.path || '\u2013' }}</code>\n </dt>\n <dd>\n <code dir=\"ltr\">{{ pair.value }}</code>\n </dd>\n }\n </dl>\n</ng-template>\n\n<ng-template #fieldDetail>\n <!-- ----- Selected field definition ----- -->\n @if (selectedProperty(); as field) {\n <div class=\"axp-platform-explorer__docs-detail-header\">\n <div class=\"axp-platform-explorer__docs-eyebrow\">\n {{ '@platform-dev-tools:module.property-details.field-definition' | translate | async }}\n </div>\n <h2 class=\"axp-platform-explorer__docs-detail-title\">\n {{ (field.title || field.name) | translate | async }}\n </h2>\n <code class=\"axp-platform-explorer__docs-key\" dir=\"ltr\">{{ field.name }}</code>\n <!--->\n <!-- ----- Plugin source of the selected field ----- -->\n @if (field.pluginTitle) {\n <span class=\"axp-platform-explorer__docs-chip axp-platform-explorer__docs-chip--field\">\n <i class=\"fa-light fa-plug\" aria-hidden=\"true\"></i>\n {{ field.pluginTitle | translate | async }}\n </span>\n }\n </div>\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.terms.description' | translate | async }}</h3>\n <p class=\"axp-platform-explorer__docs-description\">\n <!--->\n <!-- ----- Translated field description ----- -->\n @if (field.description) {\n {{ field.description | translate | async }}\n }\n <!-- ----- Missing field description ----- -->\n @else {\n {{ '@platform-dev-tools:module.property-details.no-description' | translate | async }}\n }\n </p>\n </section>\n <!--->\n <!-- ----- Schema flags and scalar pairs ----- -->\n @if (selectedSchemaEntries(); as schema) {\n <!--->\n <!-- ----- Render schema when at least one entry exists ----- -->\n @if (schema.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.schema' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n @for (entry of schema; track entry.labelKey) {\n <dt>{{ ('@platform-dev-tools:module.property-details.' + entry.labelKey) | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Boolean schema flags ----- -->\n @if (entry.kind === 'flag') {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: entry.on }\" />\n }\n <!-- ----- Schema scalar values ----- -->\n @else {\n <!--->\n <!-- ----- Data type shown as a chip ----- -->\n @if (isTypePair(entry.labelKey)) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ entry.value }}</span>\n }\n <!-- ----- Code-like schema values ----- -->\n @else if (isCodePair(entry.labelKey)) {\n <code dir=\"ltr\">{{ entry.value }}</code>\n }\n <!-- ----- Plain schema values ----- -->\n @else {\n {{ entry.value }}\n }\n }\n </dd>\n }\n </dl>\n </section>\n }\n }\n <!--->\n <!-- ----- Presentation flags and widget pairs ----- -->\n @if (selectedPresentationEntries(); as presentation) {\n <!--->\n <!-- ----- Render presentation when at least one entry exists ----- -->\n @if (presentation.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.presentation' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n @for (entry of presentation; track entry.labelKey) {\n <dt>{{ ('@platform-dev-tools:module.property-details.' + entry.labelKey) | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Boolean presentation flags ----- -->\n @if (entry.kind === 'flag') {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: entry.on }\" />\n }\n <!-- ----- Presentation scalar values ----- -->\n @else {\n <!--->\n <!-- ----- Widget identifiers as code ----- -->\n @if (isCodePair(entry.labelKey) || isTypePair(entry.labelKey)) {\n <code dir=\"ltr\">{{ entry.value }}</code>\n }\n <!-- ----- Plain presentation values ----- -->\n @else {\n {{ entry.value }}\n }\n }\n </dd>\n }\n </dl>\n </section>\n }\n }\n <!--->\n <!-- ----- Widget triggers ----- -->\n @if (field.details.triggers.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.triggers' | translate | async }}</h3>\n <div class=\"axp-platform-explorer__prop-stack\">\n @for (trigger of field.details.triggers; track $index) {\n <div class=\"axp-platform-explorer__prop-card\">\n <div class=\"axp-platform-explorer__prop-trigger\">\n <span class=\"text-muted text-xs\">\n {{ '@platform-dev-tools:module.property-details.event' | translate | async }}\n </span>\n <code>{{ trigger.event || '\u2013' }}</code>\n <i class=\"fa-light fa-arrow-right text-muted\" aria-hidden=\"true\"></i>\n <span class=\"text-muted text-xs\">\n {{ '@platform-dev-tools:module.property-details.action' | translate | async }}\n </span>\n <code>{{ trigger.action || '\u2013' }}</code>\n </div>\n <!--->\n <!-- ----- Disabled trigger badge ----- -->\n @if (trigger.disabled) {\n <span class=\"axp-platform-explorer__prop-flag\">\n {{ '@platform-dev-tools:module.property-details.disabled' | translate | async }}\n </span>\n }\n </div>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Validation rules ----- -->\n @if (field.details.validations.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.property-details.validations' | translate | async }}</h3>\n <div class=\"axp-platform-explorer__prop-stack\">\n @for (rule of field.details.validations; track $index) {\n <div class=\"axp-platform-explorer__prop-card\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <code>{{ rule.rule }}</code>\n <!--->\n <!-- ----- Disabled validation badge ----- -->\n @if (rule.disabled) {\n <span class=\"axp-platform-explorer__prop-flag\">\n {{ '@platform-dev-tools:module.property-details.disabled' | translate | async }}\n </span>\n }\n </div>\n <!--->\n <!-- ----- Validation message ----- -->\n @if (rule.message) {\n <p class=\"m-0 text-xs text-muted\">{{ rule.message | translate | async }}</p>\n }\n <!--->\n <!-- ----- Flattened validation options ----- -->\n @if (rule.optionsPairs.length) {\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: rule.optionsPairs }\" />\n }\n </div>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Flattened nested JSON (widget options, transforms, children) ----- -->\n @if (field.details.jsonBlocks.length) {\n @for (block of field.details.jsonBlocks; track block.labelKey) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ ('@platform-dev-tools:module.property-details.' + block.labelKey) | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: block.pairs }\" />\n </section>\n }\n }\n }\n <!-- ----- No field selected ----- -->\n @else {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.property-details.select-field' | translate | async }}\n </p>\n }\n</ng-template>\n\n<ng-template #actionDetail>\n <!-- ----- Selected action definition ----- -->\n @if (selectedAction(); as action) {\n <div class=\"axp-platform-explorer__docs-detail-header\">\n <div class=\"axp-platform-explorer__docs-eyebrow\">\n {{ '@platform-dev-tools:module.action-details.action-definition' | translate | async }}\n </div>\n <h2 class=\"axp-platform-explorer__docs-detail-title\">\n {{ (action.title || action.commandName || action.name || '\u2013') | translate | async }}\n </h2>\n <code class=\"axp-platform-explorer__docs-key\" dir=\"ltr\">{{ action.commandName || action.name || '\u2013' }}</code>\n </div>\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.behavior' | translate | async }}</h3>\n <dl class=\"axp-platform-explorer__docs-dl\">\n <dt>{{ '@platform-dev-tools:module.action-details.type' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Action type ----- -->\n @if (action.typeLabel) {\n <span class=\"axp-platform-explorer__type-chip\">{{ action.typeLabel }}</span>\n }\n <!-- ----- Missing action type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.priority' | translate | async }}</dt>\n <dd>\n {{ ('@platform-dev-tools:module.action-details.priorities.' + action.priority) | translate | async }}\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.scope' | translate | async }}</dt>\n <dd>{{ ('@platform-dev-tools:module.action-details.scopes.' + action.scope) | translate | async }}</dd>\n <dt>{{ '@platform-dev-tools:module.action-details.default' | translate | async }}</dt>\n <dd>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: action.isDefault }\" />\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.separated' | translate | async }}</dt>\n <dd>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: action.separated }\" />\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.hidden' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Hidden yes/no ----- -->\n @if (hiddenFlag(action) !== undefined) {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: hiddenFlag(action) }\" />\n }\n <!-- ----- Hidden expression ----- -->\n @else if (hiddenExpression(action); as expression) {\n <code dir=\"ltr\">{{ expression }}</code>\n }\n <!-- ----- Hidden unknown ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <dt>{{ '@platform-dev-tools:module.action-details.disabled' | translate | async }}</dt>\n <dd>\n <!--->\n <!-- ----- Disabled yes/no ----- -->\n @if (disabledFlag(action) !== undefined) {\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: disabledFlag(action) }\" />\n }\n <!-- ----- Disabled expression ----- -->\n @else if (disabledExpression(action); as expression) {\n <code dir=\"ltr\">{{ expression }}</code>\n }\n <!-- ----- Disabled unknown ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </dd>\n <!--->\n <!-- ----- Named action key ----- -->\n @if (action.name) {\n <dt>{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd>\n <code dir=\"ltr\">{{ action.name }}</code>\n </dd>\n }\n <!--->\n <!-- ----- Color token ----- -->\n @if (action.color) {\n <dt>{{ '@platform-dev-tools:module.action-details.color' | translate | async }}</dt>\n <dd>\n <code dir=\"ltr\">{{ action.color }}</code>\n </dd>\n }\n <!--->\n <!-- ----- Sort order ----- -->\n @if (action.order != null) {\n <dt>{{ '@platform-dev-tools:module.action-details.order' | translate | async }}</dt>\n <dd>{{ action.order }}</dd>\n }\n </dl>\n </section>\n <!--->\n <!-- ----- Keyboard shortcuts ----- -->\n @if (action.shortcuts.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.shortcuts' | translate | async }}</h3>\n <div class=\"flex flex-wrap gap-1.5\">\n @for (shortcut of action.shortcuts; track shortcut) {\n <code>{{ shortcut }}</code>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Permission keys ----- -->\n @if (action.permissions.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.terms.permissions' | translate | async }}</h3>\n <div class=\"flex flex-wrap gap-1.5\">\n @for (permission of action.permissions; track permission) {\n <code>{{ permission }}</code>\n }\n </div>\n </section>\n }\n <!--->\n <!-- ----- Dynamic submenu expression ----- -->\n @if (action.submenuExpression) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.submenu' | translate | async }}</h3>\n <code dir=\"ltr\">{{ action.submenuExpression }}</code>\n </section>\n }\n <!--->\n <!-- ----- Flattened command options ----- -->\n @if (action.optionsPairs.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.options' | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: action.optionsPairs }\" />\n </section>\n }\n <!--->\n <!-- ----- Flattened command metadata ----- -->\n @if (action.metadataPairs.length) {\n <section class=\"axp-platform-explorer__docs-detail-block\">\n <h3>{{ '@platform-dev-tools:module.action-details.metadata' | translate | async }}</h3>\n <ng-container *ngTemplateOutlet=\"kvList; context: { pairs: action.metadataPairs }\" />\n </section>\n }\n }\n <!-- ----- No action selected ----- -->\n @else {\n <p class=\"axp-platform-explorer__docs-empty\">\n {{ '@platform-dev-tools:module.action-details.select-action' | translate | async }}\n </p>\n }\n</ng-template>\n", styles: ["@layer properties;ax-drawer-container.axp-platform-explorer__docs,ax-content.axp-platform-explorer__docs-main{height:100%;min-height:0}.axp-platform-explorer__docs-main{display:flex;height:100%;min-height:0px;min-width:0px;flex:1;flex-direction:column;overflow:hidden;display:flex!important;overflow:hidden!important}.axp-platform-explorer__docs-shell{display:grid;grid-template-rows:auto minmax(0,1fr);height:100%;min-height:0;overflow:hidden}.axp-platform-explorer__docs-chrome{z-index:20;flex-shrink:0;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);scrollbar-gutter:stable}.axp-platform-explorer__docs-chrome:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:var(--color-dark);color:var(--color-on-dark);border-color:var(--color-border-dark)}.axp-platform-explorer__docs-plugins{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 1.5);padding-inline:calc(var(--spacing, .25rem) * 6);padding-block:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-table-head{display:grid;grid-template-columns:46% minmax(0,1fr) minmax(0,1fr);margin-inline:calc(var(--spacing, .25rem) * 6);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-table-head{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-table-head>*{padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}.axp-platform-explorer__docs-chip{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border:1px solid rgb(var(--ax-sys-color-border-warning-lightest-surface))}.axp-platform-explorer__docs-chip--field{margin-top:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__docs-list{min-height:0px;min-width:0px;overflow:auto;padding-inline:calc(var(--spacing, .25rem) * 6);padding-top:0;padding-bottom:calc(var(--spacing, .25rem) * 5);scrollbar-gutter:stable}.axp-platform-explorer__docs-list--padded{padding-top:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-toolbar{margin-bottom:calc(var(--spacing, .25rem) * 5);display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-heading{margin:0;font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__docs-count{margin:0;margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-count{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-search{width:calc(var(--spacing, .25rem) * 52);max-width:100%}.axp-platform-explorer__docs-empty,.axp-platform-explorer__docs-footnote{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-empty,.axp-platform-explorer__docs-footnote{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-empty{padding-block:calc(var(--spacing, .25rem) * 8);text-align:center}.axp-platform-explorer__docs-footnote{margin:0;padding-top:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__docs-side{width:calc(var(--spacing, .25rem) * 80);border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__docs-detail{display:flex;height:100%;min-width:0px;flex-direction:column;overflow:auto;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 5);padding-block:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-eyebrow{margin-bottom:calc(var(--spacing, .25rem) * 2.5);font-size:11px;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-widest, .1em);letter-spacing:var(--tracking-widest, .1em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-eyebrow{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-detail-title{margin:0;margin-bottom:var(--spacing, .25rem);font-size:var(--text-lg, 1.125rem);line-height:var(--tw-leading, var(--text-lg--line-height, calc(1.75 / 1.125)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);overflow-wrap:break-word}.axp-platform-explorer__docs-key{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__docs-detail-block{margin-top:calc(var(--spacing, .25rem) * 4);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-top:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__docs-detail-block h3{margin:0;margin-bottom:calc(var(--spacing, .25rem) * 2.5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__docs-description{margin:0;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-description{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-dl{margin:0;display:grid;column-gap:calc(var(--spacing, .25rem) * 3);row-gap:calc(var(--spacing, .25rem) * 2.5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));grid-template-columns:minmax(0,1fr) auto}.axp-platform-explorer__docs-dl dt{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-dl dt{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__docs-dl dd{margin:0;max-width:calc(var(--spacing, .25rem) * 40);text-align:end;overflow-wrap:break-word}.axp-platform-explorer__docs-actions{display:flex;min-height:0px;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3);overflow:auto;padding-inline:calc(var(--spacing, .25rem) * 6);padding-block:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-layout{margin-top:calc(var(--spacing, .25rem) * 6);display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3);padding-inline:0px}.axp-platform-explorer__docs-actions .axp-platform-explorer__docs-layout{margin-top:0}.axp-platform-explorer__table-wrap{overflow-x:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__table-wrap--fields{overflow:visible;border-radius:0;border-style:var(--tw-border-style);border-width:0px}.axp-platform-explorer__table{width:100%;min-width:36rem;border-collapse:collapse;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table--fields{min-width:0px;table-layout:fixed}.axp-platform-explorer__table--fields th:first-child{width:46%}.axp-platform-explorer__table th{background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default));border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__table th{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__table--fields thead.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.axp-platform-explorer__table td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 4);vertical-align:middle;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__table--fields tbody tr{cursor:pointer}.axp-platform-explorer__table-row--alt td{background-color:rgba(var(--ax-sys-color-lighter-surface))}.axp-platform-explorer__table-row:hover td,.axp-platform-explorer__table-row--selected td{background-color:rgba(var(--ax-sys-color-primary-lightest-surface))}.axp-platform-explorer__table-row--selected td:first-child{box-shadow:inset 3px 0 0 var(--ax-color-primary, currentColor)}:dir(rtl) .axp-platform-explorer__table-row--selected td:first-child{box-shadow:inset -3px 0 0 var(--ax-color-primary, currentColor)}.axp-platform-explorer__table tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0px}.axp-platform-explorer__table-detail td{padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 3)}.axp-platform-explorer__docs-dl--json{grid-template-columns:minmax(0,1.2fr) minmax(0,1fr)}.axp-platform-explorer__docs-dl--json dd{max-width:none}.axp-platform-explorer__docs-dl--json dt code,.axp-platform-explorer__docs-dl--json dd code{background-color:transparent;padding:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all}.axp-platform-explorer__field-button{margin:0;display:inline-flex;appearance:none;align-items:center;border-style:var(--tw-border-style);border-width:0px;background-color:transparent;padding:0;text-align:start;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-platform-explorer__field-button code{background-color:transparent;padding:0;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table-row--selected .axp-platform-explorer__field-button{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__field-button:hover{text-decoration:underline;text-underline-offset:3px}.axp-platform-explorer__field-title{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__type-chip{display:inline-block;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__unknown{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__unknown{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__yes{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__yes i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__prop-toggle,.axp-platform-explorer__prop-toggle-spacer{display:inline-flex;height:calc(var(--spacing, .25rem) * 7);width:calc(var(--spacing, .25rem) * 7);flex-shrink:0;align-items:center;justify-content:center;border-radius:var(--radius-md, .375rem)}.axp-platform-explorer__prop-toggle{cursor:pointer;appearance:none;border-style:var(--tw-border-style);border-width:0px;background-color:transparent;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-toggle{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-toggle:hover{background-color:rgba(var(--ax-sys-color-lighter-surface));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__prop-toggle i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function, cubic-bezier(.4, 0, .2, 1)));transition-duration:var(--tw-duration, var(--default-transition-duration, .15s));--tw-duration: .15s;transition-duration:.15s}.axp-platform-explorer__prop-toggle.is-open i{rotate:90deg}.axp-platform-explorer__prop-details{margin-inline-start:calc(var(--spacing, .25rem) * 9);display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 4);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding:calc(var(--spacing, .25rem) * 4)}.axp-platform-explorer__prop-flags{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-flag{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:var(--spacing, .25rem);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__prop-pairs{margin:0;display:grid;column-gap:calc(var(--spacing, .25rem) * 6);row-gap:calc(var(--spacing, .25rem) * 2);grid-template-columns:minmax(7rem,11rem) minmax(0,1fr)}.axp-platform-explorer__prop-pairs dt{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-pairs dt{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-pairs dd{margin:0;min-width:0px}.axp-platform-explorer__prop-pairs code,.axp-platform-explorer__prop-card code,.axp-platform-explorer__prop-trigger code{border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all}.axp-platform-explorer__prop-section{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-section-title{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__prop-section-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__prop-stack{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-card{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}.axp-platform-explorer__prop-trigger{display:flex;flex-wrap:wrap;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__prop-json{margin:0;max-height:calc(var(--spacing, .25rem) * 48);overflow:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding:calc(var(--spacing, .25rem) * 3);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.axp-platform-explorer__table--actions{min-width:36rem}.axp-platform-explorer__priority{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__priority{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__priority.is-primary{--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-primary-surface))}@media(max-width:760px){.axp-platform-explorer__docs-side{width:calc(var(--spacing, .25rem) * 72)}.axp-platform-explorer__docs-plugins,.axp-platform-explorer__docs-list,.axp-platform-explorer__docs-actions{padding-inline:calc(var(--spacing, .25rem) * 5)}.axp-platform-explorer__docs-table-head{margin-inline:calc(var(--spacing, .25rem) * 5)}}@media(max-width:440px){.axp-platform-explorer__docs-toolbar{display:block}.axp-platform-explorer__docs-search{margin-top:calc(var(--spacing, .25rem) * 3);width:100%}}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@property --tw-duration{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial;--tw-duration: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
479
1363
|
}], ctorParameters: () => [], propDecorators: { payload: [{ type: i0.Input, args: [{ isSignal: true, alias: "payload", required: false }] }] } });
|
|
480
1364
|
|
|
481
|
-
//#region ---- Imports ----
|
|
482
1365
|
//#endregion
|
|
483
|
-
|
|
1366
|
+
//#region ----- Property rows -----
|
|
1367
|
+
function asRecord(value) {
|
|
1368
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
return value;
|
|
1372
|
+
}
|
|
1373
|
+
function asText(value) {
|
|
1374
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
1375
|
+
}
|
|
1376
|
+
function hasRequired(def) {
|
|
1377
|
+
if (def['required'] === true) {
|
|
1378
|
+
return true;
|
|
1379
|
+
}
|
|
1380
|
+
const validations = def['validations'];
|
|
1381
|
+
if (!Array.isArray(validations)) {
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
return validations.some((rule) => asRecord(rule)?.['rule'] === 'required');
|
|
1385
|
+
}
|
|
1386
|
+
function dataTypeOf(def) {
|
|
1387
|
+
const dataType = def['dataType'];
|
|
1388
|
+
if (typeof dataType === 'string' && dataType.trim()) {
|
|
1389
|
+
return dataType.trim();
|
|
1390
|
+
}
|
|
1391
|
+
const iface = asRecord(def['interface']);
|
|
1392
|
+
const name = iface?.['name'];
|
|
1393
|
+
if (typeof name === 'string' && name.trim()) {
|
|
1394
|
+
return name.trim();
|
|
1395
|
+
}
|
|
1396
|
+
return undefined;
|
|
1397
|
+
}
|
|
1398
|
+
function joinNotes(def, extra, omitCondition = false) {
|
|
1399
|
+
const parts = [
|
|
1400
|
+
...extra,
|
|
1401
|
+
omitCondition ? '' : asText(def['condition']),
|
|
1402
|
+
asText(def['notes']),
|
|
1403
|
+
].filter(Boolean);
|
|
1404
|
+
return parts.length ? parts.join(' · ') : undefined;
|
|
1405
|
+
}
|
|
1406
|
+
function toIoRows(defs) {
|
|
1407
|
+
if (!Array.isArray(defs)) {
|
|
1408
|
+
return [];
|
|
1409
|
+
}
|
|
1410
|
+
const rows = [];
|
|
1411
|
+
const seen = new Set();
|
|
1412
|
+
for (const item of defs) {
|
|
1413
|
+
const def = asRecord(item);
|
|
1414
|
+
if (!def) {
|
|
1415
|
+
continue;
|
|
1416
|
+
}
|
|
1417
|
+
const name = asText(def['name']);
|
|
1418
|
+
if (!name || seen.has(name)) {
|
|
1419
|
+
continue;
|
|
1420
|
+
}
|
|
1421
|
+
seen.add(name);
|
|
1422
|
+
const title = asText(def['title']) || undefined;
|
|
1423
|
+
const dataType = dataTypeOf(def);
|
|
1424
|
+
const note = joinNotes(def, []);
|
|
1425
|
+
rows.push({
|
|
1426
|
+
name,
|
|
1427
|
+
...(title ? { title } : {}),
|
|
1428
|
+
...(dataType ? { dataType } : {}),
|
|
1429
|
+
required: hasRequired(def),
|
|
1430
|
+
...(note ? { note } : {}),
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
return rows;
|
|
1434
|
+
}
|
|
1435
|
+
function capabilityProperties(section) {
|
|
1436
|
+
const row = asRecord(section);
|
|
1437
|
+
if (!row || row['enabled'] !== true) {
|
|
1438
|
+
return [];
|
|
1439
|
+
}
|
|
1440
|
+
return toIoRows(row['definition']);
|
|
1441
|
+
}
|
|
1442
|
+
function queryOutputRows(query) {
|
|
1443
|
+
const columns = toIoRows(query['columns']);
|
|
1444
|
+
if (columns.length) {
|
|
1445
|
+
return columns;
|
|
1446
|
+
}
|
|
1447
|
+
const valueType = asText(query['valueType']);
|
|
1448
|
+
if (valueType) {
|
|
1449
|
+
return [{ name: 'value', dataType: valueType, required: false }];
|
|
1450
|
+
}
|
|
1451
|
+
return [];
|
|
1452
|
+
}
|
|
1453
|
+
function queryInputRows(query) {
|
|
1454
|
+
const args = capabilityProperties(query['args']);
|
|
1455
|
+
const filter = capabilityProperties(query['filter']);
|
|
1456
|
+
if (!args.length) {
|
|
1457
|
+
return filter;
|
|
1458
|
+
}
|
|
1459
|
+
if (!filter.length) {
|
|
1460
|
+
return args;
|
|
1461
|
+
}
|
|
1462
|
+
const seen = new Set(args.map((row) => row.name));
|
|
1463
|
+
return [...args, ...filter.filter((row) => !seen.has(row.name))];
|
|
1464
|
+
}
|
|
1465
|
+
function emptyTables(showOutput) {
|
|
1466
|
+
return {
|
|
1467
|
+
input: [],
|
|
1468
|
+
output: [],
|
|
1469
|
+
showOutput,
|
|
1470
|
+
contributions: [],
|
|
1471
|
+
extensionKeys: [],
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
//#endregion
|
|
1475
|
+
//#region ----- Plugin contributions -----
|
|
1476
|
+
function parseJsonObject(value) {
|
|
1477
|
+
if (typeof value === 'string') {
|
|
1478
|
+
const trimmed = value.trim();
|
|
1479
|
+
if (!trimmed) {
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1482
|
+
try {
|
|
1483
|
+
return asRecord(JSON.parse(trimmed));
|
|
1484
|
+
}
|
|
1485
|
+
catch {
|
|
1486
|
+
return null;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return asRecord(value);
|
|
1490
|
+
}
|
|
1491
|
+
function namedRows(list, nameKeys, extraKind) {
|
|
1492
|
+
if (!Array.isArray(list)) {
|
|
1493
|
+
return [];
|
|
1494
|
+
}
|
|
1495
|
+
const rows = [];
|
|
1496
|
+
for (const item of list) {
|
|
1497
|
+
const def = asRecord(item);
|
|
1498
|
+
if (!def) {
|
|
1499
|
+
continue;
|
|
1500
|
+
}
|
|
1501
|
+
let name = '';
|
|
1502
|
+
for (const key of nameKeys) {
|
|
1503
|
+
name = asText(def[key]);
|
|
1504
|
+
if (name) {
|
|
1505
|
+
break;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
if (!name) {
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
const title = asText(def['title']) || undefined;
|
|
1512
|
+
const fromOption = asText(def['nameFromOption'] || def['idFromOption']);
|
|
1513
|
+
const extra = extraKind === 'scope'
|
|
1514
|
+
? asText(def['scope']) || undefined
|
|
1515
|
+
: extraKind === 'condition'
|
|
1516
|
+
? asText(def['condition']) || undefined
|
|
1517
|
+
: undefined;
|
|
1518
|
+
const note = joinNotes(def, fromOption ? [`options.${fromOption}`] : [], extraKind === 'condition');
|
|
1519
|
+
const dataType = dataTypeOf(def);
|
|
1520
|
+
rows.push({
|
|
1521
|
+
name,
|
|
1522
|
+
...(title ? { title } : {}),
|
|
1523
|
+
...(dataType ? { dataType } : {}),
|
|
1524
|
+
required: hasRequired(def),
|
|
1525
|
+
...(extra && extraKind ? { extra, extraKind } : {}),
|
|
1526
|
+
...(note ? { note } : {}),
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
return rows;
|
|
1530
|
+
}
|
|
1531
|
+
function contributionSections(json) {
|
|
1532
|
+
const parsed = parseJsonObject(json);
|
|
1533
|
+
if (!parsed) {
|
|
1534
|
+
return { contributions: [], extensionKeys: [] };
|
|
1535
|
+
}
|
|
1536
|
+
const contributions = [];
|
|
1537
|
+
const add = (kind, rows, extraKey) => {
|
|
1538
|
+
if (!rows.length) {
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
contributions.push({ kind, rows, ...(extraKey ? { extraKey } : {}) });
|
|
1542
|
+
};
|
|
1543
|
+
add('properties', namedRows(parsed['properties'], ['name']));
|
|
1544
|
+
add('columns', namedRows(parsed['columns'], ['name'], 'condition'), 'condition');
|
|
1545
|
+
add('actions', namedRows(parsed['actions'], ['name'], 'scope'), 'scope');
|
|
1546
|
+
add('groups', namedRows(parsed['groups'], ['id', 'name']));
|
|
1547
|
+
add('pages', namedRows(parsed['pages'], ['name'], 'condition'), 'condition');
|
|
1548
|
+
add('related-entities', namedRows(parsed['relatedEntities'], ['entity', 'name']));
|
|
1549
|
+
const extensionKeys = Array.isArray(parsed['extensionKeys'])
|
|
1550
|
+
? parsed['extensionKeys'].filter((key) => typeof key === 'string' && key.trim().length > 0)
|
|
1551
|
+
: [];
|
|
1552
|
+
return { contributions, extensionKeys };
|
|
1553
|
+
}
|
|
1554
|
+
//#endregion
|
|
1555
|
+
//#region ----- Catalog I/O -----
|
|
1556
|
+
function catalogIoFromDetail(kind, detail) {
|
|
1557
|
+
if (!detail) {
|
|
1558
|
+
return null;
|
|
1559
|
+
}
|
|
1560
|
+
if (kind === 'command' && detail.command) {
|
|
1561
|
+
return {
|
|
1562
|
+
...emptyTables(true),
|
|
1563
|
+
input: toIoRows(detail.command.inputOptionDefinitions),
|
|
1564
|
+
output: toIoRows(detail.command.outputOptionDefinitions),
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
if (kind === 'query' && detail.query) {
|
|
1568
|
+
const query = detail.query;
|
|
1569
|
+
return {
|
|
1570
|
+
...emptyTables(true),
|
|
1571
|
+
input: queryInputRows(query),
|
|
1572
|
+
output: queryOutputRows(query),
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
if (kind === 'widget' && detail.widget) {
|
|
1576
|
+
return {
|
|
1577
|
+
...emptyTables(true),
|
|
1578
|
+
input: toIoRows(detail.widget.inputOptionDefinitions),
|
|
1579
|
+
output: toIoRows(detail.widget.outputOptionDefinitions),
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
if (kind === 'plugin' && detail.plugin) {
|
|
1583
|
+
const contributed = contributionSections(detail.plugin.contributionsJson);
|
|
1584
|
+
return {
|
|
1585
|
+
...emptyTables(false),
|
|
1586
|
+
input: toIoRows(detail.plugin.optionDefinitions),
|
|
1587
|
+
contributions: contributed.contributions,
|
|
1588
|
+
extensionKeys: contributed.extensionKeys,
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
return null;
|
|
1592
|
+
}
|
|
1593
|
+
function stringList(value) {
|
|
1594
|
+
if (!Array.isArray(value)) {
|
|
1595
|
+
return [];
|
|
1596
|
+
}
|
|
1597
|
+
const items = [];
|
|
1598
|
+
const seen = new Set();
|
|
1599
|
+
for (const item of value) {
|
|
1600
|
+
const text = asText(item);
|
|
1601
|
+
if (!text || seen.has(text)) {
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
seen.add(text);
|
|
1605
|
+
items.push(text);
|
|
1606
|
+
}
|
|
1607
|
+
return items;
|
|
1608
|
+
}
|
|
1609
|
+
function categoryLabels(value) {
|
|
1610
|
+
if (!Array.isArray(value)) {
|
|
1611
|
+
return [];
|
|
1612
|
+
}
|
|
1613
|
+
const items = [];
|
|
1614
|
+
const seen = new Set();
|
|
1615
|
+
for (const item of value) {
|
|
1616
|
+
const text = asText(item) || asText(asRecord(item)?.['title']) || asText(asRecord(item)?.['name']);
|
|
1617
|
+
if (!text || seen.has(text)) {
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
seen.add(text);
|
|
1621
|
+
items.push(text);
|
|
1622
|
+
}
|
|
1623
|
+
return items;
|
|
1624
|
+
}
|
|
1625
|
+
//#endregion
|
|
1626
|
+
|
|
1627
|
+
//#region ----- Imports -----
|
|
1628
|
+
//#endregion
|
|
1629
|
+
//#region ----- Component -----
|
|
1630
|
+
class AXPlatformExplorerCatalogDetailComponent {
|
|
1631
|
+
//#endregion
|
|
484
1632
|
constructor() {
|
|
485
|
-
this.
|
|
486
|
-
...(ngDevMode ? [{ debugName: "
|
|
1633
|
+
this.kind = input.required(/* @ts-ignore */
|
|
1634
|
+
...(ngDevMode ? [{ debugName: "kind" }] : /* istanbul ignore next */ []));
|
|
1635
|
+
this.item = input(/* @ts-ignore */
|
|
1636
|
+
...(ngDevMode ? [undefined, { debugName: "item" }] : /* istanbul ignore next */ []));
|
|
1637
|
+
//#region ----- Services & Dependencies -----
|
|
487
1638
|
this.dataService = inject(PlatformExplorerDataService);
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
},
|
|
501
|
-
});
|
|
1639
|
+
//#endregion
|
|
1640
|
+
//#region ----- State Signals -----
|
|
1641
|
+
this.detail = signal(null, /* @ts-ignore */
|
|
1642
|
+
...(ngDevMode ? [{ debugName: "detail" }] : /* istanbul ignore next */ []));
|
|
1643
|
+
this.loading = signal(false, /* @ts-ignore */
|
|
1644
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
1645
|
+
this.loadError = signal(false, /* @ts-ignore */
|
|
1646
|
+
...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
1647
|
+
//#endregion
|
|
1648
|
+
//#region ----- Computed Properties -----
|
|
1649
|
+
this.ioTables = computed(() => catalogIoFromDetail(this.kind(), this.detail()), /* @ts-ignore */
|
|
1650
|
+
...(ngDevMode ? [{ debugName: "ioTables" }] : /* istanbul ignore next */ []));
|
|
502
1651
|
effect(() => {
|
|
503
|
-
this.
|
|
504
|
-
this.
|
|
1652
|
+
const kind = this.kind();
|
|
1653
|
+
const item = this.item();
|
|
1654
|
+
void this.load(kind, item?.name);
|
|
505
1655
|
});
|
|
506
1656
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
1657
|
+
record() {
|
|
1658
|
+
const detail = this.detail();
|
|
1659
|
+
if (!detail) {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
return (detail.command ?? detail.query ?? detail.plugin ?? detail.widget ?? null);
|
|
1663
|
+
}
|
|
1664
|
+
displayTitle(record) {
|
|
1665
|
+
return String(record['catalogTitle'] ?? record['title'] ?? record['name'] ?? '');
|
|
1666
|
+
}
|
|
1667
|
+
//#region ----- Helpers -----
|
|
1668
|
+
asText(value) {
|
|
1669
|
+
return typeof value === 'string' ? value : '';
|
|
1670
|
+
}
|
|
1671
|
+
asStringList(value) {
|
|
1672
|
+
return stringList(value);
|
|
1673
|
+
}
|
|
1674
|
+
asCategoryLabels(value) {
|
|
1675
|
+
return categoryLabels(value);
|
|
1676
|
+
}
|
|
1677
|
+
isNumber(value) {
|
|
1678
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
1679
|
+
}
|
|
1680
|
+
//#endregion
|
|
1681
|
+
//#region ----- Data Loading -----
|
|
1682
|
+
async load(kind, name) {
|
|
1683
|
+
if (!name) {
|
|
1684
|
+
this.detail.set(null);
|
|
1685
|
+
this.loading.set(false);
|
|
1686
|
+
this.loadError.set(false);
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
this.loading.set(true);
|
|
1690
|
+
this.loadError.set(false);
|
|
1691
|
+
this.detail.set(null);
|
|
1692
|
+
try {
|
|
1693
|
+
const detail = await this.dataService.getCatalogItem(kind, name);
|
|
1694
|
+
if (this.item()?.name === name && this.kind() === kind) {
|
|
1695
|
+
this.detail.set(detail);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
catch {
|
|
1699
|
+
if (this.item()?.name === name && this.kind() === kind) {
|
|
1700
|
+
this.loadError.set(true);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
finally {
|
|
1704
|
+
if (this.item()?.name === name && this.kind() === kind) {
|
|
1705
|
+
this.loading.set(false);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerCatalogDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1710
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerCatalogDetailComponent, isStandalone: true, selector: "axp-platform-explorer-catalog-detail", inputs: { kind: { classPropertyName: "kind", publicName: "kind", isSignal: true, isRequired: true, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col flex-1 min-h-0" }, ngImport: i0, template: "<div class=\"flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading catalog row ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Catalog row fields ----- -->\n @else if (record(); as row) {\n <section class=\"flex flex-col gap-6 p-4 overflow-auto\">\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ row['name'] }}</code></dd>\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.title' | translate | async }}</dt>\n <dd class=\"m-0\">{{ displayTitle(row) | translate | async }}</dd>\n @if (row['description']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.description' | translate | async }}</dt>\n <dd class=\"m-0\">{{ asText(row['description']) | translate | async }}</dd>\n }\n @if (row['executionMode']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.execution-mode' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['executionMode'] }}</dd>\n }\n @if (row['sourceModule']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.source-module' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['sourceModule'] }}</dd>\n }\n @if (row['type']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.type' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['type'] }}</dd>\n }\n @if (row['dataType']) {\n <dt class=\"font-semibold text-muted\">\n {{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}\n </dt>\n <dd class=\"m-0\">\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row['dataType'] }}</span>\n </dd>\n }\n @if (asText(row['icon']); as icon) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.icon' | translate | async }}</dt>\n <dd class=\"m-0 flex items-center gap-2\">\n <i [ngClass]=\"icon\" aria-hidden=\"true\"></i>\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ icon }}</code>\n </dd>\n }\n @if (isNumber(row['order'])) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.order' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['order'] }}</dd>\n }\n @if (row['defaultFilterWidgetName']) {\n <dt class=\"font-semibold text-muted\">\n {{ '@platform-dev-tools:module.terms.default-filter-widget' | translate | async }}\n </dt>\n <dd class=\"m-0\">\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ row['defaultFilterWidgetName'] }}</code>\n </dd>\n }\n @if (asStringList(row['groups']); as groups) {\n <!--->\n <!-- ----- Widget group tags ----- -->\n @if (groups.length) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.groups' | translate | async }}</dt>\n <dd class=\"m-0\">\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (group of groups; track group) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ group }}</span>\n }\n </div>\n </dd>\n }\n }\n @if (asCategoryLabels(row['categories']); as categories) {\n <!--->\n <!-- ----- Catalog categories ----- -->\n @if (categories.length) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.categories' | translate | async }}</dt>\n <dd class=\"m-0\">\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (category of categories; track category) {\n <span class=\"axp-platform-explorer__type-chip\">{{ category | translate | async }}</span>\n }\n </div>\n </dd>\n }\n }\n </dl>\n\n <!--->\n <!-- ----- Input, output, and plugin contribution tables ----- -->\n @if (ioTables(); as io) {\n <div class=\"axp-platform-explorer__catalog-io\">\n <section>\n <h2>{{ '@platform-dev-tools:module.terms.input' | translate | async }}</h2>\n <!--->\n <!-- ----- Empty input list ----- -->\n @if (io.input.length === 0) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-input' | translate | async }}\n </p>\n }\n <!-- ----- Input rows ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: io.input }\" />\n }\n </section>\n <!--->\n <!-- ----- Output contract for commands, queries, and widgets ----- -->\n @if (io.showOutput) {\n <section>\n <h2>{{ '@platform-dev-tools:module.terms.output' | translate | async }}</h2>\n <!--->\n <!-- ----- Empty output list ----- -->\n @if (io.output.length === 0) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-output' | translate | async }}\n </p>\n }\n <!-- ----- Output rows ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: io.output }\" />\n }\n </section>\n }\n <!--->\n <!-- ----- Plugin host contributions from the catalog definition ----- -->\n @if (io.contributions.length) {\n @for (section of io.contributions; track section.kind) {\n <section>\n <h2>{{ ('@platform-dev-tools:module.contributions.' + section.kind) | translate | async }}</h2>\n <!--->\n <!-- ----- Contributed properties use the schema table ----- -->\n @if (section.kind === 'properties') {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: section.rows }\" />\n }\n <!-- ----- Columns, actions, groups, pages, related entities ----- -->\n @else {\n <ng-container\n *ngTemplateOutlet=\"itemTable; context: { rows: section.rows, extraKey: section.extraKey }\"\n />\n }\n </section>\n }\n }\n <!-- ----- Plugin declared no host contributions ----- -->\n @else if (!io.showOutput) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-contributions' | translate | async }}\n </p>\n }\n <!--->\n <!-- ----- Middleware extension keys ----- -->\n @if (io.extensionKeys.length) {\n <section>\n <h2>{{ '@platform-dev-tools:module.contributions.extension-keys' | translate | async }}</h2>\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (key of io.extensionKeys; track key) {\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ key }}</code>\n }\n </div>\n </section>\n }\n </div>\n }\n </section>\n }\n</div>\n\n<ng-template #schemaTable let-rows=\"rows\">\n <div class=\"axp-platform-explorer__table-wrap\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.terms.required' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track row.name) {\n <tr>\n <td>\n <ng-container *ngTemplateOutlet=\"nameCell; context: { row: row }\" />\n </td>\n <td>\n <!--->\n <!-- ----- Stored data type chip ----- -->\n @if (row.dataType) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row.dataType }}</span>\n }\n <!-- ----- Missing data type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: row.required }\" />\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</ng-template>\n\n<ng-template #itemTable let-rows=\"rows\" let-extraKey=\"extraKey\">\n <div class=\"axp-platform-explorer__table-wrap\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <!--->\n <!-- ----- Extra column for scope or condition ----- -->\n @if (extraKey) {\n <th>{{ ('@platform-dev-tools:module.contributions.' + extraKey) | translate | async }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track row.name) {\n <tr>\n <td>\n <ng-container *ngTemplateOutlet=\"nameCell; context: { row: row }\" />\n </td>\n <!--->\n <!-- ----- Extra cell when the section declares one ----- -->\n @if (extraKey) {\n <td>\n <!--->\n <!-- ----- Action scope ----- -->\n @if (row.extraKind === 'scope' && row.extra) {\n {{ ('@platform-dev-tools:module.contributions.scopes.' + row.extra) | translate | async }}\n }\n <!-- ----- Condition expression ----- -->\n @else if (row.extra) {\n <code dir=\"ltr\">{{ row.extra }}</code>\n }\n <!-- ----- Missing extra ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</ng-template>\n\n<ng-template #nameCell let-row=\"row\">\n <code dir=\"ltr\">{{ row.name }}</code>\n <!--->\n <!-- ----- Translated title under the field name ----- -->\n @if (row.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ row.title | translate | async }}\n </div>\n }\n <!--->\n <!-- ----- Definition notes and option-sourced names ----- -->\n @if (row.note) {\n <div class=\"axp-platform-explorer__field-note\" dir=\"ltr\">{{ row.note }}</div>\n }\n</ng-template>\n\n<ng-template #boolCell let-value=\"value\">\n <!-- ----- Affirmative flag ----- -->\n @if (value === true) {\n <span class=\"axp-platform-explorer__yes\">\n <i class=\"fa-light fa-check\" aria-hidden=\"true\"></i>\n {{ '@platform-dev-tools:module.property-details.yes' | translate | async }}\n </span>\n }\n <!-- ----- Negative flag ----- -->\n @else {\n {{ '@platform-dev-tools:module.property-details.no' | translate | async }}\n }\n</ng-template>\n", styles: ["@layer properties;.axp-platform-explorer__catalog-io{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 6)}.axp-platform-explorer__catalog-io h2{margin:0;margin-bottom:calc(var(--spacing, .25rem) * 2);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__catalog-io-empty{padding-block:calc(var(--spacing, .25rem) * 4);text-align:start}.axp-platform-explorer__table-wrap{overflow-x:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__table{width:100%;min-width:36rem;border-collapse:collapse;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table--fields{min-width:0px;table-layout:fixed}.axp-platform-explorer__table--fields th:first-child{width:46%}.axp-platform-explorer__table th{background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default));border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__table th{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__table td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 4);vertical-align:middle;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__table tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0px}.axp-platform-explorer__field-title{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__field-note{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-note{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__catalog-chips{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__type-chip{display:inline-block;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__unknown{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__unknown{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__yes{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__yes i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__docs-empty{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-empty{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1711
|
+
}
|
|
1712
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerCatalogDetailComponent, decorators: [{
|
|
1713
|
+
type: Component,
|
|
1714
|
+
args: [{ selector: 'axp-platform-explorer-catalog-detail', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'flex flex-col flex-1 min-h-0' }, imports: [CommonModule, AXTranslationModule, AXLoadingModule, AXPStateMessageComponent], template: "<div class=\"flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading catalog row ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Catalog row fields ----- -->\n @else if (record(); as row) {\n <section class=\"flex flex-col gap-6 p-4 overflow-auto\">\n <dl class=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 m-0\">\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.name' | translate | async }}</dt>\n <dd class=\"m-0\"><code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\">{{ row['name'] }}</code></dd>\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.title' | translate | async }}</dt>\n <dd class=\"m-0\">{{ displayTitle(row) | translate | async }}</dd>\n @if (row['description']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.description' | translate | async }}</dt>\n <dd class=\"m-0\">{{ asText(row['description']) | translate | async }}</dd>\n }\n @if (row['executionMode']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.execution-mode' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['executionMode'] }}</dd>\n }\n @if (row['sourceModule']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.source-module' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['sourceModule'] }}</dd>\n }\n @if (row['type']) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.type' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['type'] }}</dd>\n }\n @if (row['dataType']) {\n <dt class=\"font-semibold text-muted\">\n {{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}\n </dt>\n <dd class=\"m-0\">\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row['dataType'] }}</span>\n </dd>\n }\n @if (asText(row['icon']); as icon) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.icon' | translate | async }}</dt>\n <dd class=\"m-0 flex items-center gap-2\">\n <i [ngClass]=\"icon\" aria-hidden=\"true\"></i>\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ icon }}</code>\n </dd>\n }\n @if (isNumber(row['order'])) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.order' | translate | async }}</dt>\n <dd class=\"m-0\">{{ row['order'] }}</dd>\n }\n @if (row['defaultFilterWidgetName']) {\n <dt class=\"font-semibold text-muted\">\n {{ '@platform-dev-tools:module.terms.default-filter-widget' | translate | async }}\n </dt>\n <dd class=\"m-0\">\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ row['defaultFilterWidgetName'] }}</code>\n </dd>\n }\n @if (asStringList(row['groups']); as groups) {\n <!--->\n <!-- ----- Widget group tags ----- -->\n @if (groups.length) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.groups' | translate | async }}</dt>\n <dd class=\"m-0\">\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (group of groups; track group) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ group }}</span>\n }\n </div>\n </dd>\n }\n }\n @if (asCategoryLabels(row['categories']); as categories) {\n <!--->\n <!-- ----- Catalog categories ----- -->\n @if (categories.length) {\n <dt class=\"font-semibold text-muted\">{{ '@platform-dev-tools:module.terms.categories' | translate | async }}</dt>\n <dd class=\"m-0\">\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (category of categories; track category) {\n <span class=\"axp-platform-explorer__type-chip\">{{ category | translate | async }}</span>\n }\n </div>\n </dd>\n }\n }\n </dl>\n\n <!--->\n <!-- ----- Input, output, and plugin contribution tables ----- -->\n @if (ioTables(); as io) {\n <div class=\"axp-platform-explorer__catalog-io\">\n <section>\n <h2>{{ '@platform-dev-tools:module.terms.input' | translate | async }}</h2>\n <!--->\n <!-- ----- Empty input list ----- -->\n @if (io.input.length === 0) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-input' | translate | async }}\n </p>\n }\n <!-- ----- Input rows ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: io.input }\" />\n }\n </section>\n <!--->\n <!-- ----- Output contract for commands, queries, and widgets ----- -->\n @if (io.showOutput) {\n <section>\n <h2>{{ '@platform-dev-tools:module.terms.output' | translate | async }}</h2>\n <!--->\n <!-- ----- Empty output list ----- -->\n @if (io.output.length === 0) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-output' | translate | async }}\n </p>\n }\n <!-- ----- Output rows ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: io.output }\" />\n }\n </section>\n }\n <!--->\n <!-- ----- Plugin host contributions from the catalog definition ----- -->\n @if (io.contributions.length) {\n @for (section of io.contributions; track section.kind) {\n <section>\n <h2>{{ ('@platform-dev-tools:module.contributions.' + section.kind) | translate | async }}</h2>\n <!--->\n <!-- ----- Contributed properties use the schema table ----- -->\n @if (section.kind === 'properties') {\n <ng-container *ngTemplateOutlet=\"schemaTable; context: { rows: section.rows }\" />\n }\n <!-- ----- Columns, actions, groups, pages, related entities ----- -->\n @else {\n <ng-container\n *ngTemplateOutlet=\"itemTable; context: { rows: section.rows, extraKey: section.extraKey }\"\n />\n }\n </section>\n }\n }\n <!-- ----- Plugin declared no host contributions ----- -->\n @else if (!io.showOutput) {\n <p class=\"axp-platform-explorer__docs-empty axp-platform-explorer__catalog-io-empty\">\n {{ '@platform-dev-tools:module.messages.no-contributions' | translate | async }}\n </p>\n }\n <!--->\n <!-- ----- Middleware extension keys ----- -->\n @if (io.extensionKeys.length) {\n <section>\n <h2>{{ '@platform-dev-tools:module.contributions.extension-keys' | translate | async }}</h2>\n <div class=\"axp-platform-explorer__catalog-chips\">\n @for (key of io.extensionKeys; track key) {\n <code class=\"text-xs bg-lighter px-1.5 py-0.5 rounded\" dir=\"ltr\">{{ key }}</code>\n }\n </div>\n </section>\n }\n </div>\n }\n </section>\n }\n</div>\n\n<ng-template #schemaTable let-rows=\"rows\">\n <div class=\"axp-platform-explorer__table-wrap\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.property-details.data-type' | translate | async }}</th>\n <th>{{ '@platform-dev-tools:module.terms.required' | translate | async }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track row.name) {\n <tr>\n <td>\n <ng-container *ngTemplateOutlet=\"nameCell; context: { row: row }\" />\n </td>\n <td>\n <!--->\n <!-- ----- Stored data type chip ----- -->\n @if (row.dataType) {\n <span class=\"axp-platform-explorer__type-chip\" dir=\"ltr\">{{ row.dataType }}</span>\n }\n <!-- ----- Missing data type ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n <td>\n <ng-container *ngTemplateOutlet=\"boolCell; context: { value: row.required }\" />\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</ng-template>\n\n<ng-template #itemTable let-rows=\"rows\" let-extraKey=\"extraKey\">\n <div class=\"axp-platform-explorer__table-wrap\">\n <table class=\"axp-platform-explorer__table axp-platform-explorer__table--fields\">\n <thead>\n <tr>\n <th>{{ '@platform-dev-tools:module.terms.field' | translate | async }}</th>\n <!--->\n <!-- ----- Extra column for scope or condition ----- -->\n @if (extraKey) {\n <th>{{ ('@platform-dev-tools:module.contributions.' + extraKey) | translate | async }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track row.name) {\n <tr>\n <td>\n <ng-container *ngTemplateOutlet=\"nameCell; context: { row: row }\" />\n </td>\n <!--->\n <!-- ----- Extra cell when the section declares one ----- -->\n @if (extraKey) {\n <td>\n <!--->\n <!-- ----- Action scope ----- -->\n @if (row.extraKind === 'scope' && row.extra) {\n {{ ('@platform-dev-tools:module.contributions.scopes.' + row.extra) | translate | async }}\n }\n <!-- ----- Condition expression ----- -->\n @else if (row.extra) {\n <code dir=\"ltr\">{{ row.extra }}</code>\n }\n <!-- ----- Missing extra ----- -->\n @else {\n <span class=\"axp-platform-explorer__unknown\">\u2013</span>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</ng-template>\n\n<ng-template #nameCell let-row=\"row\">\n <code dir=\"ltr\">{{ row.name }}</code>\n <!--->\n <!-- ----- Translated title under the field name ----- -->\n @if (row.title) {\n <div class=\"axp-platform-explorer__field-title\">\n {{ row.title | translate | async }}\n </div>\n }\n <!--->\n <!-- ----- Definition notes and option-sourced names ----- -->\n @if (row.note) {\n <div class=\"axp-platform-explorer__field-note\" dir=\"ltr\">{{ row.note }}</div>\n }\n</ng-template>\n\n<ng-template #boolCell let-value=\"value\">\n <!-- ----- Affirmative flag ----- -->\n @if (value === true) {\n <span class=\"axp-platform-explorer__yes\">\n <i class=\"fa-light fa-check\" aria-hidden=\"true\"></i>\n {{ '@platform-dev-tools:module.property-details.yes' | translate | async }}\n </span>\n }\n <!-- ----- Negative flag ----- -->\n @else {\n {{ '@platform-dev-tools:module.property-details.no' | translate | async }}\n }\n</ng-template>\n", styles: ["@layer properties;.axp-platform-explorer__catalog-io{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 6)}.axp-platform-explorer__catalog-io h2{margin:0;margin-bottom:calc(var(--spacing, .25rem) * 2);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-platform-explorer__catalog-io-empty{padding-block:calc(var(--spacing, .25rem) * 4);text-align:start}.axp-platform-explorer__table-wrap{overflow-x:auto;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface))}.axp-platform-explorer__table{width:100%;min-width:36rem;border-collapse:collapse;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}.axp-platform-explorer__table--fields{min-width:0px;table-layout:fixed}.axp-platform-explorer__table--fields th:first-child{width:46%}.axp-platform-explorer__table th{background-color:rgba(var(--ax-sys-color-lighter-surface));text-align:start;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-text-default));border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2.5)}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__table th{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__table td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 4);vertical-align:middle;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__table tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0px}.axp-platform-explorer__field-title{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__field-note{margin-top:calc(var(--spacing, .25rem) * .5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));word-break:break-all;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__field-note{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__catalog-chips{display:flex;flex-wrap:wrap;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__type-chip{display:inline-block;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lighter-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);padding-block:calc(var(--spacing, .25rem) * .5);font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__unknown{color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__unknown{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__yes{display:inline-flex;align-items:center;gap:var(--spacing, .25rem);color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__yes i{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)))}.axp-platform-explorer__docs-empty{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__docs-empty{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
1715
|
+
}], ctorParameters: () => [], propDecorators: { kind: [{ type: i0.Input, args: [{ isSignal: true, alias: "kind", required: true }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }] } });
|
|
1716
|
+
|
|
1717
|
+
//#region ----- Constants -----
|
|
1718
|
+
const EXPLORER_ENTITY_NODE_TYPE = 'explorer-entity';
|
|
1719
|
+
/** Crow's-foot / UML multiplicity shown on ERD ports (not i18n). */
|
|
1720
|
+
const ERD_CARDINALITY_ONE = '1..1';
|
|
1721
|
+
const ERD_CARDINALITY_MANY = '0..*';
|
|
1722
|
+
const NODE_W = 280;
|
|
1723
|
+
const NODE_HEAD_H = 52;
|
|
1724
|
+
/** Room per connector so relation names on parallel edges do not touch. */
|
|
1725
|
+
const PORT_SLOT_H = 24;
|
|
1726
|
+
const PORT_BAND_PAD = 28;
|
|
1727
|
+
const NODE_GAP_Y = 40;
|
|
1728
|
+
const EXTERNAL_GAP_X = 160;
|
|
1729
|
+
/** Grid spacing for entities that have no relations. */
|
|
1730
|
+
const ISOLATED_GAP_X = 48;
|
|
1731
|
+
const ISOLATED_GAP_Y = 88;
|
|
1732
|
+
const INTERNAL_ORIGIN = { x: 48, y: 48 };
|
|
1733
|
+
//#endregion
|
|
1734
|
+
//#region ----- Node helpers -----
|
|
1735
|
+
function isExplorerEntityNode(node) {
|
|
1736
|
+
return node.type === EXPLORER_ENTITY_NODE_TYPE;
|
|
1737
|
+
}
|
|
1738
|
+
function explorerEntityData(node) {
|
|
1739
|
+
const data = node.data;
|
|
1740
|
+
return data?.kind === 'entity' ? data : null;
|
|
1741
|
+
}
|
|
1742
|
+
//#endregion
|
|
1743
|
+
//#region ----- Build diagram -----
|
|
1744
|
+
function relationName(edge) {
|
|
1745
|
+
const labeled = edge.label?.trim();
|
|
1746
|
+
if (labeled) {
|
|
1747
|
+
return labeled;
|
|
1748
|
+
}
|
|
1749
|
+
const dot = edge.to.lastIndexOf('.');
|
|
1750
|
+
return dot > 0 ? edge.to.slice(dot + 1) : edge.to;
|
|
1751
|
+
}
|
|
1752
|
+
function sourceCardinality(kind) {
|
|
1753
|
+
return kind === 'lookup' ? ERD_CARDINALITY_MANY : ERD_CARDINALITY_ONE;
|
|
1754
|
+
}
|
|
1755
|
+
function targetCardinality(kind) {
|
|
1756
|
+
return kind === 'lookup' ? ERD_CARDINALITY_ONE : ERD_CARDINALITY_MANY;
|
|
1757
|
+
}
|
|
1758
|
+
function outboundPortId(edge) {
|
|
1759
|
+
return `${edge.from}:out:${edge.kind}:${edge.to}:${edge.label ?? ''}`;
|
|
1760
|
+
}
|
|
1761
|
+
function inboundPortId(edge) {
|
|
1762
|
+
return `${edge.to}:in:${edge.kind}:${edge.from}:${edge.label ?? ''}`;
|
|
1763
|
+
}
|
|
1764
|
+
function portRatio(index, count) {
|
|
1765
|
+
if (count <= 1) {
|
|
1766
|
+
return 0.5;
|
|
1767
|
+
}
|
|
1768
|
+
return (index + 1) / (count + 1);
|
|
1769
|
+
}
|
|
1770
|
+
function inboundPorts(incoming) {
|
|
1771
|
+
return incoming.map((edge, index) => ({
|
|
1772
|
+
id: inboundPortId(edge),
|
|
1773
|
+
kind: 'inbound',
|
|
1774
|
+
side: 'left',
|
|
1775
|
+
ratio: portRatio(index, incoming.length),
|
|
1776
|
+
label: targetCardinality(edge.kind),
|
|
1777
|
+
allowMultiple: false,
|
|
1778
|
+
readonly: true,
|
|
1779
|
+
}));
|
|
1780
|
+
}
|
|
1781
|
+
function outboundPorts(outgoing) {
|
|
1782
|
+
return outgoing.map((edge, index) => ({
|
|
1783
|
+
id: outboundPortId(edge),
|
|
1784
|
+
kind: 'outbound',
|
|
1785
|
+
side: 'right',
|
|
1786
|
+
ratio: portRatio(index, outgoing.length),
|
|
1787
|
+
label: sourceCardinality(edge.kind),
|
|
1788
|
+
readonly: true,
|
|
1789
|
+
}));
|
|
1790
|
+
}
|
|
1791
|
+
function lookupFieldKeys(edges) {
|
|
1792
|
+
const keys = new Set();
|
|
1793
|
+
for (const edge of edges) {
|
|
1794
|
+
if (edge.kind === 'lookup' && edge.label) {
|
|
1795
|
+
keys.add(`${edge.from}\0${edge.label}`);
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
return keys;
|
|
1799
|
+
}
|
|
1800
|
+
function cardHeight(incoming, outgoing) {
|
|
1801
|
+
const slots = Math.max(incoming, outgoing);
|
|
1802
|
+
return slots <= 1 ? NODE_HEAD_H : Math.max(NODE_HEAD_H, PORT_BAND_PAD + slots * PORT_SLOT_H);
|
|
1803
|
+
}
|
|
1804
|
+
function toEntityData(item, moduleTitle, skipLookupFields) {
|
|
1805
|
+
return {
|
|
1806
|
+
kind: 'entity',
|
|
1807
|
+
fullName: item.fullName,
|
|
1808
|
+
name: item.name,
|
|
1809
|
+
title: item.title,
|
|
1810
|
+
module: item.module,
|
|
1811
|
+
moduleTitle,
|
|
1812
|
+
external: item.external,
|
|
1813
|
+
icon: item.icon || 'fa-light fa-table',
|
|
1814
|
+
properties: (item.properties ?? []).filter((property) => !skipLookupFields.has(`${item.fullName}\0${property.name}`)),
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
function entityNode(data, outgoing, incoming) {
|
|
1818
|
+
const color = data.external ? 'warning' : 'primary';
|
|
1819
|
+
return {
|
|
1820
|
+
id: data.fullName,
|
|
1821
|
+
type: EXPLORER_ENTITY_NODE_TYPE,
|
|
1822
|
+
title: data.fullName,
|
|
1823
|
+
icon: data.icon,
|
|
1824
|
+
shape: 'rectangle',
|
|
1825
|
+
position: { x: 0, y: 0 },
|
|
1826
|
+
size: { width: NODE_W, height: cardHeight(incoming.length, outgoing.length) },
|
|
1827
|
+
inboundPorts: inboundPorts(incoming),
|
|
1828
|
+
outboundPorts: outboundPorts(outgoing),
|
|
1829
|
+
readonly: true,
|
|
1830
|
+
color,
|
|
1831
|
+
borderColor: color,
|
|
1832
|
+
data: { ...data },
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function connectors(edges) {
|
|
1836
|
+
return edges.map((edge) => ({
|
|
1837
|
+
id: outboundPortId(edge),
|
|
1838
|
+
sourceNodeId: edge.from,
|
|
1839
|
+
sourcePortId: outboundPortId(edge),
|
|
1840
|
+
targetNodeId: edge.to,
|
|
1841
|
+
targetPortId: inboundPortId(edge),
|
|
1842
|
+
readonly: true,
|
|
1843
|
+
color: (edge.kind === 'related' ? 'success' : 'primary'),
|
|
1844
|
+
borderColor: (edge.kind === 'related' ? 'success' : 'primary'),
|
|
1845
|
+
label: relationName(edge),
|
|
1846
|
+
data: { kind: edge.kind },
|
|
1847
|
+
}));
|
|
1848
|
+
}
|
|
1849
|
+
function nodesBBox(nodes) {
|
|
1850
|
+
if (nodes.length === 0) {
|
|
1851
|
+
return { minX: INTERNAL_ORIGIN.x, minY: INTERNAL_ORIGIN.y, maxX: INTERNAL_ORIGIN.x, maxY: INTERNAL_ORIGIN.y };
|
|
1852
|
+
}
|
|
1853
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
1854
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
1855
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
1856
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
1857
|
+
for (const node of nodes) {
|
|
1858
|
+
minX = Math.min(minX, node.position.x);
|
|
1859
|
+
minY = Math.min(minY, node.position.y);
|
|
1860
|
+
maxX = Math.max(maxX, node.position.x + node.size.width);
|
|
1861
|
+
maxY = Math.max(maxY, node.position.y + node.size.height);
|
|
1862
|
+
}
|
|
1863
|
+
return { minX, minY, maxX, maxY };
|
|
1864
|
+
}
|
|
1865
|
+
function groupEdgesBy(edges, keyOf) {
|
|
1866
|
+
const map = new Map();
|
|
1867
|
+
for (const edge of edges) {
|
|
1868
|
+
const key = keyOf(edge);
|
|
1869
|
+
const list = map.get(key);
|
|
1870
|
+
if (list) {
|
|
1871
|
+
list.push(edge);
|
|
1872
|
+
}
|
|
1873
|
+
else {
|
|
1874
|
+
map.set(key, [edge]);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
for (const list of map.values()) {
|
|
1878
|
+
list.sort((a, b) => relationName(a).localeCompare(relationName(b)) || a.from.localeCompare(b.from));
|
|
1879
|
+
}
|
|
1880
|
+
return map;
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Tiles unrelated entities in rows under the related cluster. A single column
|
|
1884
|
+
* would make the canvas very tall, which forces fit-to-content to a tiny zoom.
|
|
1885
|
+
*/
|
|
1886
|
+
function tileIsolatedNodes(nodes, startY, availableWidth) {
|
|
1887
|
+
const placed = new Map();
|
|
1888
|
+
const columns = Math.max(1, Math.floor((availableWidth + ISOLATED_GAP_X) / (NODE_W + ISOLATED_GAP_X)));
|
|
1889
|
+
let rowY = startY;
|
|
1890
|
+
let rowHeight = 0;
|
|
1891
|
+
nodes.forEach((node, index) => {
|
|
1892
|
+
const column = index % columns;
|
|
1893
|
+
if (column === 0 && index > 0) {
|
|
1894
|
+
rowY += rowHeight + NODE_GAP_Y;
|
|
1895
|
+
rowHeight = 0;
|
|
1896
|
+
}
|
|
1897
|
+
placed.set(node.id, {
|
|
1898
|
+
...node,
|
|
1899
|
+
position: { x: INTERNAL_ORIGIN.x + column * (NODE_W + ISOLATED_GAP_X), y: rowY },
|
|
1900
|
+
});
|
|
1901
|
+
rowHeight = Math.max(rowHeight, node.size.height);
|
|
1902
|
+
});
|
|
1903
|
+
return placed;
|
|
1904
|
+
}
|
|
1905
|
+
/**
|
|
1906
|
+
* Converts the explorer entity graph into a readonly ERD. Related entities are
|
|
1907
|
+
* arranged left to right, external targets cluster on the right with a yellow
|
|
1908
|
+
* header, and unrelated entities tile in a grid underneath. Cards stay
|
|
1909
|
+
* header-sized; the property list is shown/hidden without changing layout.
|
|
1910
|
+
*/
|
|
1911
|
+
function buildExplorerEntityDiagram(graph, resolveModuleTitle) {
|
|
1912
|
+
if (!graph?.nodes.length) {
|
|
1913
|
+
return null;
|
|
1914
|
+
}
|
|
1915
|
+
const nodeIds = new Set(graph.nodes.map((item) => item.fullName));
|
|
1916
|
+
const validEdges = graph.edges.filter((edge) => nodeIds.has(edge.from) && nodeIds.has(edge.to));
|
|
1917
|
+
const outgoing = groupEdgesBy(validEdges, (edge) => edge.from);
|
|
1918
|
+
const incoming = groupEdgesBy(validEdges, (edge) => edge.to);
|
|
1919
|
+
const skipLookupFields = lookupFieldKeys(validEdges);
|
|
1920
|
+
const relatedIds = new Set(validEdges.flatMap((edge) => [edge.from, edge.to]));
|
|
1921
|
+
const entityNodes = graph.nodes.map((item) => {
|
|
1922
|
+
const data = toEntityData(item, resolveModuleTitle(item.module), skipLookupFields);
|
|
1923
|
+
return entityNode(data, outgoing.get(item.fullName) ?? [], incoming.get(item.fullName) ?? []);
|
|
1924
|
+
});
|
|
1925
|
+
const internalRelatedIds = entityNodes
|
|
1926
|
+
.filter((node) => !explorerEntityData(node)?.external && relatedIds.has(node.id))
|
|
1927
|
+
.map((node) => node.id);
|
|
1928
|
+
const arranged = arrangeWorkflowDiagram({
|
|
1929
|
+
nodes: entityNodes,
|
|
1930
|
+
connectors: connectors(validEdges),
|
|
1931
|
+
}, {
|
|
1932
|
+
nodeIds: internalRelatedIds,
|
|
1933
|
+
origin: INTERNAL_ORIGIN,
|
|
1934
|
+
direction: 'horizontal',
|
|
1935
|
+
horizontalGap: 220,
|
|
1936
|
+
verticalGap: 72,
|
|
1937
|
+
margin: 48,
|
|
1938
|
+
groupDisconnected: true,
|
|
1939
|
+
});
|
|
1940
|
+
const internals = arranged.nodes.filter((node) => !explorerEntityData(node)?.external && relatedIds.has(node.id));
|
|
1941
|
+
const box = nodesBBox(internals);
|
|
1942
|
+
const externals = arranged.nodes
|
|
1943
|
+
.filter((node) => explorerEntityData(node)?.external)
|
|
1944
|
+
.sort((a, b) => {
|
|
1945
|
+
const moduleCmp = (explorerEntityData(a)?.module ?? '').localeCompare(explorerEntityData(b)?.module ?? '');
|
|
1946
|
+
return moduleCmp !== 0 ? moduleCmp : a.title.localeCompare(b.title);
|
|
1947
|
+
});
|
|
1948
|
+
const externalX = box.maxX + EXTERNAL_GAP_X;
|
|
1949
|
+
let externalY = INTERNAL_ORIGIN.y;
|
|
1950
|
+
const positioned = new Map();
|
|
1951
|
+
for (const node of externals) {
|
|
1952
|
+
positioned.set(node.id, {
|
|
1953
|
+
...node,
|
|
1954
|
+
position: { x: externalX, y: externalY },
|
|
1955
|
+
});
|
|
1956
|
+
externalY += node.size.height + NODE_GAP_Y;
|
|
1957
|
+
}
|
|
1958
|
+
const isolated = arranged.nodes
|
|
1959
|
+
.filter((node) => !explorerEntityData(node)?.external && !relatedIds.has(node.id))
|
|
1960
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
1961
|
+
if (isolated.length) {
|
|
1962
|
+
const clusterBottom = Math.max(box.maxY, externalY - NODE_GAP_Y, INTERNAL_ORIGIN.y);
|
|
1963
|
+
const clusterWidth = Math.max(NODE_W, (externals.length ? externalX + NODE_W : box.maxX) - INTERNAL_ORIGIN.x);
|
|
1964
|
+
const startY = internals.length || externals.length ? clusterBottom + ISOLATED_GAP_Y : INTERNAL_ORIGIN.y;
|
|
1965
|
+
for (const [id, node] of tileIsolatedNodes(isolated, startY, clusterWidth)) {
|
|
1966
|
+
positioned.set(id, node);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return {
|
|
1970
|
+
nodes: arranged.nodes.map((node) => positioned.get(node.id) ?? node),
|
|
1971
|
+
connectors: arranged.connectors,
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
function connectedNodeIds(model, nodeId) {
|
|
1975
|
+
const ids = new Set([nodeId]);
|
|
1976
|
+
for (const connector of model.connectors) {
|
|
1977
|
+
if (connector.sourceNodeId === nodeId) {
|
|
1978
|
+
ids.add(connector.targetNodeId);
|
|
1979
|
+
}
|
|
1980
|
+
if (connector.targetNodeId === nodeId) {
|
|
1981
|
+
ids.add(connector.sourceNodeId);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return [...ids];
|
|
527
1985
|
}
|
|
528
|
-
|
|
529
|
-
type: Component,
|
|
530
|
-
args: [{
|
|
531
|
-
selector: 'axp-platform-explorer-permissions-list-detail',
|
|
532
|
-
standalone: true,
|
|
533
|
-
encapsulation: ViewEncapsulation.None,
|
|
534
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
535
|
-
imports: [CommonModule, AXDataTableModule, AXTranslationModule],
|
|
536
|
-
host: { class: 'flex flex-col flex-1 min-h-0' },
|
|
537
|
-
template: `
|
|
538
|
-
<div class="flex flex-1 min-h-0 pt-0 overflow-auto">
|
|
539
|
-
<ax-data-table
|
|
540
|
-
class="flex-1 border border-lightest rounded-md overflow-hidden"
|
|
541
|
-
[paging]="true"
|
|
542
|
-
[allowReordering]="true"
|
|
543
|
-
[dataSource]="dataSource"
|
|
544
|
-
>
|
|
545
|
-
<ax-text-column [dataField]="'name'" [caption]="'@platform-dev-tools:module.terms.name' | translate | async" [width]="'420px'" [allowResizing]="true"></ax-text-column>
|
|
546
|
-
<ax-text-column [dataField]="'title'" [caption]="'@platform-dev-tools:module.terms.title' | translate | async" [cellTemplate]="titleTpl" [width]="'260px'" [allowResizing]="true"></ax-text-column>
|
|
547
|
-
<ax-text-column [dataField]="'description'" [caption]="'@platform-dev-tools:module.terms.description' | translate | async" [cellTemplate]="descTpl" [width]="'380px'" [allowResizing]="true"></ax-text-column>
|
|
548
|
-
</ax-data-table>
|
|
549
|
-
</div>
|
|
550
|
-
<ng-template #titleTpl let-item>
|
|
551
|
-
{{ $safeNavigationMigration(item.data?.title) | translate | async }}</ng-template>
|
|
552
|
-
<ng-template #descTpl let-item>
|
|
553
|
-
@if (item.data?.description) { {{ item.data.description | translate | async }} } @else { – }
|
|
554
|
-
</ng-template>
|
|
555
|
-
`,
|
|
556
|
-
}]
|
|
557
|
-
}], ctorParameters: () => [], propDecorators: { moduleName: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleName", required: true }] }] } });
|
|
1986
|
+
//#endregion
|
|
558
1987
|
|
|
559
|
-
//#region
|
|
1988
|
+
//#region ----- Imports -----
|
|
560
1989
|
//#endregion
|
|
561
|
-
|
|
1990
|
+
//#region ----- Component -----
|
|
1991
|
+
class AXPlatformExplorerEntitiesGraphComponent {
|
|
1992
|
+
//#endregion
|
|
562
1993
|
constructor() {
|
|
563
1994
|
this.moduleName = input.required(/* @ts-ignore */
|
|
564
1995
|
...(ngDevMode ? [{ debugName: "moduleName" }] : /* istanbul ignore next */ []));
|
|
1996
|
+
//#region ----- Services & Dependencies -----
|
|
565
1997
|
this.dataService = inject(PlatformExplorerDataService);
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
});
|
|
1998
|
+
//#endregion
|
|
1999
|
+
//#region ----- Constants -----
|
|
2000
|
+
/** Readonly diagram: no spare drawing area, so fit-to-content keeps cards readable. */
|
|
2001
|
+
this.canvasMinSize = { width: 0, height: 0 };
|
|
2002
|
+
//#endregion
|
|
2003
|
+
//#region ----- State Signals -----
|
|
2004
|
+
this.loading = signal(false, /* @ts-ignore */
|
|
2005
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
2006
|
+
this.loadError = signal(false, /* @ts-ignore */
|
|
2007
|
+
...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
2008
|
+
this.diagram = signal(null, /* @ts-ignore */
|
|
2009
|
+
...(ngDevMode ? [{ debugName: "diagram" }] : /* istanbul ignore next */ []));
|
|
2010
|
+
this.highlightedNodeIds = signal([], /* @ts-ignore */
|
|
2011
|
+
...(ngDevMode ? [{ debugName: "highlightedNodeIds" }] : /* istanbul ignore next */ []));
|
|
2012
|
+
this.expandedNodeIds = signal(new Set(), /* @ts-ignore */
|
|
2013
|
+
...(ngDevMode ? [{ debugName: "expandedNodeIds" }] : /* istanbul ignore next */ []));
|
|
580
2014
|
effect(() => {
|
|
581
|
-
this.moduleName();
|
|
582
|
-
this.
|
|
2015
|
+
const moduleName = this.moduleName();
|
|
2016
|
+
void this.load(moduleName);
|
|
583
2017
|
});
|
|
584
2018
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
2019
|
+
//#region ----- Event Handlers -----
|
|
2020
|
+
entityOf(node) {
|
|
2021
|
+
return explorerEntityData(node);
|
|
2022
|
+
}
|
|
2023
|
+
entityLabel(entity) {
|
|
2024
|
+
return entity.fullName || `${entity.module}.${entity.name}`;
|
|
2025
|
+
}
|
|
2026
|
+
isExpanded(id) {
|
|
2027
|
+
return this.expandedNodeIds().has(id);
|
|
2028
|
+
}
|
|
2029
|
+
propertyToggleLabel(expanded) {
|
|
2030
|
+
return expanded
|
|
2031
|
+
? '@platform-dev-tools:module.graph.hide-properties'
|
|
2032
|
+
: '@platform-dev-tools:module.graph.show-properties';
|
|
2033
|
+
}
|
|
2034
|
+
onToggleProperties(event, id) {
|
|
2035
|
+
event.preventDefault();
|
|
2036
|
+
event.stopPropagation();
|
|
2037
|
+
const next = new Set(this.expandedNodeIds());
|
|
2038
|
+
if (next.has(id)) {
|
|
2039
|
+
next.delete(id);
|
|
2040
|
+
}
|
|
2041
|
+
else {
|
|
2042
|
+
next.add(id);
|
|
2043
|
+
}
|
|
2044
|
+
this.expandedNodeIds.set(next);
|
|
2045
|
+
}
|
|
2046
|
+
onNodeClick(event) {
|
|
2047
|
+
const model = this.diagram();
|
|
2048
|
+
if (!model) {
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
this.highlightedNodeIds.set(connectedNodeIds(model, event.node.id));
|
|
2052
|
+
}
|
|
2053
|
+
onCanvasClick() {
|
|
2054
|
+
this.highlightedNodeIds.set([]);
|
|
2055
|
+
this.expandedNodeIds.set(new Set());
|
|
2056
|
+
}
|
|
2057
|
+
//#endregion
|
|
2058
|
+
//#region ----- Data Loading -----
|
|
2059
|
+
async load(moduleName) {
|
|
2060
|
+
this.loading.set(true);
|
|
2061
|
+
this.loadError.set(false);
|
|
2062
|
+
this.diagram.set(null);
|
|
2063
|
+
this.highlightedNodeIds.set([]);
|
|
2064
|
+
this.expandedNodeIds.set(new Set());
|
|
2065
|
+
try {
|
|
2066
|
+
const catalog = await this.dataService.getModule(moduleName);
|
|
2067
|
+
if (this.moduleName() !== moduleName) {
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
const graph = catalog?.entityGraph ?? {
|
|
2071
|
+
nodes: (catalog?.entities ?? []).map((item) => ({
|
|
2072
|
+
fullName: item.fullName,
|
|
2073
|
+
module: item.module,
|
|
2074
|
+
name: item.name,
|
|
2075
|
+
title: item.title,
|
|
2076
|
+
icon: item.icon,
|
|
2077
|
+
external: false,
|
|
2078
|
+
})),
|
|
2079
|
+
edges: [],
|
|
2080
|
+
};
|
|
2081
|
+
this.diagram.set(buildExplorerEntityDiagram(graph, (name) => this.dataService.moduleTitle(name)));
|
|
2082
|
+
}
|
|
2083
|
+
catch {
|
|
2084
|
+
if (this.moduleName() === moduleName) {
|
|
2085
|
+
this.loadError.set(true);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
finally {
|
|
2089
|
+
if (this.moduleName() === moduleName) {
|
|
2090
|
+
this.loading.set(false);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerEntitiesGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2095
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerEntitiesGraphComponent, isStandalone: true, selector: "axp-platform-explorer-entities-graph", inputs: { moduleName: { classPropertyName: "moduleName", publicName: "moduleName", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "axp-explorer-graph-host flex flex-col flex-1 min-h-0" }, ngImport: i0, template: "<div class=\"axp-explorer-graph flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading module entity graph ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Module has no entities ----- -->\n @else if (!diagram()) {\n <axp-state-message\n icon=\"fa-light fa-diagram-project\"\n [title]=\"'@platform-dev-tools:module.messages.no-entities'\"\n [description]=\"'@platform-dev-tools:module.messages.no-entities-hint'\"\n />\n }\n <!-- ----- Entity-relationship diagram ----- -->\n @else {\n <div class=\"axp-explorer-graph__canvas\">\n <axp-workflow-designer\n [model]=\"diagram()!\"\n [readonly]=\"true\"\n [showPortLabels]=\"true\"\n [showPorts]=\"false\"\n [connectorStub]=\"56\"\n [canvasPadding]=\"80\"\n [minCanvasSize]=\"canvasMinSize\"\n [highlightedNodeIds]=\"highlightedNodeIds()\"\n [nodeBodyTemplate]=\"nodeBodyTpl\"\n (nodeClick)=\"onNodeClick($event)\"\n (designerClick)=\"onCanvasClick()\"\n />\n </div>\n <div class=\"axp-explorer-graph__footer\">\n <p class=\"axp-explorer-graph__hint\">\n {{ '@platform-dev-tools:module.descriptions.entities' | translate | async }}\n </p>\n <div class=\"axp-explorer-graph__legend\">\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__swatch axp-explorer-graph__swatch--internal\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.local-entity' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__swatch axp-explorer-graph__swatch--external\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.external-entity' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.pk' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.pk-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.cardinality-one' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.cardinality-one-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.cardinality-many' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.cardinality-many-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__line axp-explorer-graph__line--lookup\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.lookup' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__line axp-explorer-graph__line--related\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.related' | translate | async }}\n </span>\n </div>\n </div>\n }\n</div>\n\n<ng-template #nodeBodyTpl let-node=\"node\">\n <!-- ----- Entity table ----- -->\n @if (entityOf(node); as entity) {\n <div\n class=\"axp-explorer-graph__entity\"\n [class.axp-explorer-graph__entity--external]=\"entity.external\"\n [class.axp-explorer-graph__entity--expanded]=\"isExpanded(entity.fullName)\"\n >\n <div class=\"axp-explorer-graph__entity-head\">\n <div class=\"axp-explorer-graph__entity-head-main\">\n <span class=\"axp-explorer-graph__entity-name\">{{ entityLabel(entity) }}</span>\n <!--------------------------------------------------------------->\n <!-- ----- Translated catalog title when it differs from the entity name ----- -->\n @if (entity.title && entity.title !== entity.name && entity.title !== entity.fullName) {\n <span class=\"axp-explorer-graph__entity-title\">{{ entity.title | translate | async }}</span>\n }\n </div>\n <!--------------------------------------------------------------->\n <!-- ----- Expand non-lookup properties under the header ----- -->\n @if (entity.properties.length) {\n <button\n type=\"button\"\n class=\"axp-explorer-graph__entity-toggle\"\n [attr.aria-expanded]=\"isExpanded(entity.fullName)\"\n [attr.aria-label]=\"(propertyToggleLabel(isExpanded(entity.fullName)) | translate | async) ?? ''\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onToggleProperties($event, entity.fullName)\"\n >\n <i\n class=\"fa-light\"\n [class.fa-chevron-down]=\"!isExpanded(entity.fullName)\"\n [class.fa-chevron-up]=\"isExpanded(entity.fullName)\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n <!--------------------------------------------------------------->\n <!-- ----- Same-card property list; visibility is toggled from the header ----- -->\n @if (entity.properties.length) {\n <div class=\"axp-explorer-graph__entity-props\" (pointerdown)=\"$event.stopPropagation()\">\n @for (prop of entity.properties; track prop.name) {\n <div class=\"axp-explorer-graph__entity-prop\">\n <!--------------------------------------------------------------->\n <!-- ----- Primary-key badge when the field is id ----- -->\n @if (prop.kind === 'pk') {\n <span class=\"axp-explorer-graph__entity-prop-kind\">\n {{ '@platform-dev-tools:module.graph.pk' | translate | async }}\n </span>\n }\n <span class=\"axp-explorer-graph__entity-prop-name\">{{ prop.name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@layer properties;.axp-explorer-graph__footer{display:flex;flex-shrink:0;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 4);padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:calc(var(--spacing, .25rem) * 3)}.axp-explorer-graph__hint{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-explorer-graph__hint{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-explorer-graph__legend{display:flex;flex-wrap:wrap;align-items:center;column-gap:calc(var(--spacing, .25rem) * 4);row-gap:calc(var(--spacing, .25rem) * 2);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-explorer-graph__legend{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-explorer-graph__legend-item{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-explorer-graph__legend-sep{display:none;height:calc(var(--spacing, .25rem) * 3);width:1px;flex-shrink:0;background-color:rgba(var(--ax-sys-color-lightest-surface))}@media(width>=40rem){.axp-explorer-graph__legend-sep{display:inline-block}}.axp-explorer-graph__swatch{display:inline-block;height:calc(var(--spacing, .25rem) * 2.5);width:calc(var(--spacing, .25rem) * 2.5);flex-shrink:0;border-radius:var(--radius-sm, .25rem)}.axp-explorer-graph__swatch--internal{background:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__swatch--external{background:rgb(var(--ax-sys-color-warning-500))}.axp-explorer-graph__line{display:inline-block;height:calc(var(--spacing, .25rem) * .5);width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px)}.axp-explorer-graph__line--lookup{background:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__line--related{background:rgb(var(--ax-sys-color-success-500))}.axp-explorer-graph__canvas{margin:calc(var(--spacing, .25rem) * 3);margin-bottom:0;min-height:0px;flex:1;overflow:hidden;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));min-height:360px}.axp-explorer-graph__canvas .axp-workflow-designer__edge.axp-primary-surface{stroke:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__canvas .axp-workflow-designer__edge.axp-success-surface{stroke:rgb(var(--ax-sys-color-success-500))}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity){overflow:visible}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape,.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-primary-surface,.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-warning-surface{background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));overflow:visible;border-radius:8px}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-warning-surface{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-body{padding:0;align-items:stretch;justify-content:stretch;overflow:visible}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity--expanded){z-index:8}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity--expanded) .axp-workflow-designer__node-shape{border-radius:8px 8px 0 0;border-bottom-width:0}.axp-explorer-graph__canvas .axp-workflow-designer__port{width:7px;height:7px;background:rgb(var(--ax-sys-color-neutral-400));pointer-events:none}.axp-explorer-graph__canvas .axp-workflow-designer__port-label-svg,.axp-explorer-graph__canvas .axp-workflow-designer__edge-label-svg{fill:rgb(var(--ax-sys-color-on-surface));stroke:rgb(var(--ax-sys-color-lightest-surface));font-size:11px;font-weight:700;letter-spacing:.02em}.axp-explorer-graph__entity{display:flex;height:100%;width:100%;min-width:0px;flex-direction:column;position:relative;overflow:visible}.axp-explorer-graph__entity-head{display:flex;flex-direction:row;align-items:center;gap:calc(var(--spacing, .25rem) * 2);flex:1 1 auto;min-height:100%;padding:8px 10px;box-sizing:border-box;background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-radius:8px}.axp-explorer-graph__entity--expanded .axp-explorer-graph__entity-head{border-radius:8px 8px 0 0}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-head{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-explorer-graph__entity-head-main{display:flex;min-width:0px;flex:1;flex-direction:column;justify-content:center;gap:calc(var(--spacing, .25rem) * .5)}.axp-explorer-graph__entity-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-explorer-graph__entity-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);opacity:.85}.axp-explorer-graph__entity-toggle{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:28px;height:28px;margin:0;padding:0;border:0;border-radius:6px;background:transparent;color:inherit;cursor:pointer}.axp-explorer-graph__entity-toggle:hover{background:rgb(var(--ax-sys-color-on-primary-lightest-surface) / .08)}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-toggle:hover{background:rgb(var(--ax-sys-color-on-warning-lightest-surface) / .08)}.axp-explorer-graph__entity-props{display:none;flex-direction:column;position:absolute;top:100%;left:0;right:0;z-index:6;margin:0;padding:6px 8px 8px;box-sizing:border-box;background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border:2px solid rgb(var(--ax-sys-color-border-primary-lightest-surface));border-top:1px solid rgb(var(--ax-sys-color-on-primary-lightest-surface) / .16);border-radius:0 0 8px 8px;max-height:320px;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgb(var(--ax-sys-color-on-primary-lightest-surface) / .3) transparent}.axp-explorer-graph__entity--expanded .axp-explorer-graph__entity-props{display:flex}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-props{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface));border-top-color:rgb(var(--ax-sys-color-on-warning-lightest-surface) / .16)}.axp-explorer-graph__entity-prop{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);font-size:11px;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);min-height:22px;margin:0;padding:3px 6px;border-radius:4px;box-sizing:border-box}.axp-explorer-graph__entity-prop-kind{flex-shrink:0;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);min-width:1.75rem;opacity:.85}.axp-explorer-graph__entity-prop-name{min-width:0px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:inherit}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "component", type: AXPWorkflowDesignerComponent, selector: "axp-workflow-designer", inputs: ["model", "readonly", "highlightedNodeIds", "gridSize", "snapToGrid", "connectionPreviewStyle", "connectorStub", "backgroundPattern", "canConnect", "paletteItems", "showPortLabels", "showPorts", "showConnectorLabels", "canvasPadding", "minCanvasSize", "nodeBodyTemplate"], outputs: ["modelChange", "zoomChange", "designerPointerDown", "designerClick", "designerDoubleClick", "nodePointerDown", "nodeClick", "nodeDoubleClick", "nodeContextMenu", "nodeDragStart", "nodeDragEnd", "portPointerDown", "linkDragStart", "linkDragMove", "linkDragEnd", "connectorClick", "connectorDoubleClick", "connectionCreated", "connectionRejected", "activationChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
605
2096
|
}
|
|
606
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type:
|
|
2097
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerEntitiesGraphComponent, decorators: [{
|
|
607
2098
|
type: Component,
|
|
608
|
-
args: [{
|
|
609
|
-
selector: 'axp-platform-explorer-features-list-detail',
|
|
610
|
-
standalone: true,
|
|
611
|
-
encapsulation: ViewEncapsulation.None,
|
|
612
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
613
|
-
imports: [CommonModule, AXDataTableModule, AXTranslationModule],
|
|
614
|
-
host: { class: 'flex flex-col flex-1 min-h-0' },
|
|
615
|
-
template: `
|
|
616
|
-
<div class="flex flex-1 min-h-0 pt-0 overflow-auto">
|
|
617
|
-
<ax-data-table
|
|
618
|
-
class="flex-1 border border-lightest rounded-md overflow-hidden"
|
|
619
|
-
[paging]="true"
|
|
620
|
-
[allowReordering]="true"
|
|
621
|
-
[dataSource]="dataSource"
|
|
622
|
-
>
|
|
623
|
-
<ax-text-column dataField="key" [caption]="'@platform-dev-tools:module.terms.key' | translate | async" [width]="'240px'" [allowResizing]="true"></ax-text-column>
|
|
624
|
-
<ax-text-column dataField="title" [caption]="'@platform-dev-tools:module.terms.title' | translate | async" [cellTemplate]="titleTpl" [width]="'280px'" [allowResizing]="true"></ax-text-column>
|
|
625
|
-
<ax-text-column dataField="type" caption="Type" [width]="'100px'" [cellTemplate]="typeTpl" [allowResizing]="true"></ax-text-column>
|
|
626
|
-
<ax-text-column dataField="description" [caption]="'@platform-dev-tools:module.terms.description' | translate | async" [cellTemplate]="descTpl" [width]="'340px'" [allowResizing]="true"></ax-text-column>
|
|
627
|
-
<ax-text-column dataField="defaultValue" [caption]="'@platform-dev-tools:module.terms.default-value' | translate | async" [width]="'140px'" [allowResizing]="true"></ax-text-column>
|
|
628
|
-
</ax-data-table>
|
|
629
|
-
</div>
|
|
630
|
-
<ng-template #titleTpl let-item>{{ $safeNavigationMigration(item.data?.title) | translate | async }}</ng-template>
|
|
631
|
-
<ng-template #typeTpl let-item>{{ item.data?.type ?? '–' }}</ng-template>
|
|
632
|
-
<ng-template #descTpl let-item>@if (item.data?.description) { {{ item.data.description | translate | async }} } @else { – }</ng-template>
|
|
633
|
-
`,
|
|
634
|
-
}]
|
|
2099
|
+
args: [{ selector: 'axp-platform-explorer-entities-graph', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'axp-explorer-graph-host flex flex-col flex-1 min-h-0' }, imports: [CommonModule, AXTranslationModule, AXLoadingModule, AXPStateMessageComponent, AXPWorkflowDesignerComponent], template: "<div class=\"axp-explorer-graph flex flex-col flex-1 min-h-0\">\n <!-- ----- Loading module entity graph ----- -->\n @if (loading()) {\n <div class=\"flex flex-1 items-center justify-center p-6\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- Module has no entities ----- -->\n @else if (!diagram()) {\n <axp-state-message\n icon=\"fa-light fa-diagram-project\"\n [title]=\"'@platform-dev-tools:module.messages.no-entities'\"\n [description]=\"'@platform-dev-tools:module.messages.no-entities-hint'\"\n />\n }\n <!-- ----- Entity-relationship diagram ----- -->\n @else {\n <div class=\"axp-explorer-graph__canvas\">\n <axp-workflow-designer\n [model]=\"diagram()!\"\n [readonly]=\"true\"\n [showPortLabels]=\"true\"\n [showPorts]=\"false\"\n [connectorStub]=\"56\"\n [canvasPadding]=\"80\"\n [minCanvasSize]=\"canvasMinSize\"\n [highlightedNodeIds]=\"highlightedNodeIds()\"\n [nodeBodyTemplate]=\"nodeBodyTpl\"\n (nodeClick)=\"onNodeClick($event)\"\n (designerClick)=\"onCanvasClick()\"\n />\n </div>\n <div class=\"axp-explorer-graph__footer\">\n <p class=\"axp-explorer-graph__hint\">\n {{ '@platform-dev-tools:module.descriptions.entities' | translate | async }}\n </p>\n <div class=\"axp-explorer-graph__legend\">\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__swatch axp-explorer-graph__swatch--internal\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.local-entity' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__swatch axp-explorer-graph__swatch--external\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.external-entity' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.pk' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.pk-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.cardinality-one' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.cardinality-one-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n {{ '@platform-dev-tools:module.graph.cardinality-many' | translate | async }}\n =\n {{ '@platform-dev-tools:module.graph.cardinality-many-hint' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-sep\" aria-hidden=\"true\"></span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__line axp-explorer-graph__line--lookup\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.lookup' | translate | async }}\n </span>\n <span class=\"axp-explorer-graph__legend-item\">\n <span class=\"axp-explorer-graph__line axp-explorer-graph__line--related\" aria-hidden=\"true\"></span>\n {{ '@platform-dev-tools:module.graph.related' | translate | async }}\n </span>\n </div>\n </div>\n }\n</div>\n\n<ng-template #nodeBodyTpl let-node=\"node\">\n <!-- ----- Entity table ----- -->\n @if (entityOf(node); as entity) {\n <div\n class=\"axp-explorer-graph__entity\"\n [class.axp-explorer-graph__entity--external]=\"entity.external\"\n [class.axp-explorer-graph__entity--expanded]=\"isExpanded(entity.fullName)\"\n >\n <div class=\"axp-explorer-graph__entity-head\">\n <div class=\"axp-explorer-graph__entity-head-main\">\n <span class=\"axp-explorer-graph__entity-name\">{{ entityLabel(entity) }}</span>\n <!--------------------------------------------------------------->\n <!-- ----- Translated catalog title when it differs from the entity name ----- -->\n @if (entity.title && entity.title !== entity.name && entity.title !== entity.fullName) {\n <span class=\"axp-explorer-graph__entity-title\">{{ entity.title | translate | async }}</span>\n }\n </div>\n <!--------------------------------------------------------------->\n <!-- ----- Expand non-lookup properties under the header ----- -->\n @if (entity.properties.length) {\n <button\n type=\"button\"\n class=\"axp-explorer-graph__entity-toggle\"\n [attr.aria-expanded]=\"isExpanded(entity.fullName)\"\n [attr.aria-label]=\"(propertyToggleLabel(isExpanded(entity.fullName)) | translate | async) ?? ''\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"onToggleProperties($event, entity.fullName)\"\n >\n <i\n class=\"fa-light\"\n [class.fa-chevron-down]=\"!isExpanded(entity.fullName)\"\n [class.fa-chevron-up]=\"isExpanded(entity.fullName)\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n <!--------------------------------------------------------------->\n <!-- ----- Same-card property list; visibility is toggled from the header ----- -->\n @if (entity.properties.length) {\n <div class=\"axp-explorer-graph__entity-props\" (pointerdown)=\"$event.stopPropagation()\">\n @for (prop of entity.properties; track prop.name) {\n <div class=\"axp-explorer-graph__entity-prop\">\n <!--------------------------------------------------------------->\n <!-- ----- Primary-key badge when the field is id ----- -->\n @if (prop.kind === 'pk') {\n <span class=\"axp-explorer-graph__entity-prop-kind\">\n {{ '@platform-dev-tools:module.graph.pk' | translate | async }}\n </span>\n }\n <span class=\"axp-explorer-graph__entity-prop-name\">{{ prop.name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: ["@layer properties;.axp-explorer-graph__footer{display:flex;flex-shrink:0;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 4);padding-top:calc(var(--spacing, .25rem) * 2);padding-bottom:calc(var(--spacing, .25rem) * 3)}.axp-explorer-graph__hint{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-explorer-graph__hint{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-explorer-graph__legend{display:flex;flex-wrap:wrap;align-items:center;column-gap:calc(var(--spacing, .25rem) * 4);row-gap:calc(var(--spacing, .25rem) * 2);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-explorer-graph__legend{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-explorer-graph__legend-item{display:inline-flex;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-explorer-graph__legend-sep{display:none;height:calc(var(--spacing, .25rem) * 3);width:1px;flex-shrink:0;background-color:rgba(var(--ax-sys-color-lightest-surface))}@media(width>=40rem){.axp-explorer-graph__legend-sep{display:inline-block}}.axp-explorer-graph__swatch{display:inline-block;height:calc(var(--spacing, .25rem) * 2.5);width:calc(var(--spacing, .25rem) * 2.5);flex-shrink:0;border-radius:var(--radius-sm, .25rem)}.axp-explorer-graph__swatch--internal{background:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__swatch--external{background:rgb(var(--ax-sys-color-warning-500))}.axp-explorer-graph__line{display:inline-block;height:calc(var(--spacing, .25rem) * .5);width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px)}.axp-explorer-graph__line--lookup{background:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__line--related{background:rgb(var(--ax-sys-color-success-500))}.axp-explorer-graph__canvas{margin:calc(var(--spacing, .25rem) * 3);margin-bottom:0;min-height:0px;flex:1;overflow:hidden;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-lightest-surface));min-height:360px}.axp-explorer-graph__canvas .axp-workflow-designer__edge.axp-primary-surface{stroke:rgb(var(--ax-sys-color-primary-500))}.axp-explorer-graph__canvas .axp-workflow-designer__edge.axp-success-surface{stroke:rgb(var(--ax-sys-color-success-500))}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity){overflow:visible}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape,.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-primary-surface,.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-warning-surface{background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));overflow:visible;border-radius:8px}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-shape.axp-warning-surface{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity) .axp-workflow-designer__node-body{padding:0;align-items:stretch;justify-content:stretch;overflow:visible}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity--expanded){z-index:8}.axp-explorer-graph__canvas .axp-workflow-designer__node:has(.axp-explorer-graph__entity--expanded) .axp-workflow-designer__node-shape{border-radius:8px 8px 0 0;border-bottom-width:0}.axp-explorer-graph__canvas .axp-workflow-designer__port{width:7px;height:7px;background:rgb(var(--ax-sys-color-neutral-400));pointer-events:none}.axp-explorer-graph__canvas .axp-workflow-designer__port-label-svg,.axp-explorer-graph__canvas .axp-workflow-designer__edge-label-svg{fill:rgb(var(--ax-sys-color-on-surface));stroke:rgb(var(--ax-sys-color-lightest-surface));font-size:11px;font-weight:700;letter-spacing:.02em}.axp-explorer-graph__entity{display:flex;height:100%;width:100%;min-width:0px;flex-direction:column;position:relative;overflow:visible}.axp-explorer-graph__entity-head{display:flex;flex-direction:row;align-items:center;gap:calc(var(--spacing, .25rem) * 2);flex:1 1 auto;min-height:100%;padding:8px 10px;box-sizing:border-box;background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-radius:8px}.axp-explorer-graph__entity--expanded .axp-explorer-graph__entity-head{border-radius:8px 8px 0 0}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-head{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-explorer-graph__entity-head-main{display:flex;min-width:0px;flex:1;flex-direction:column;justify-content:center;gap:calc(var(--spacing, .25rem) * .5)}.axp-explorer-graph__entity-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}.axp-explorer-graph__entity-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);opacity:.85}.axp-explorer-graph__entity-toggle{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:28px;height:28px;margin:0;padding:0;border:0;border-radius:6px;background:transparent;color:inherit;cursor:pointer}.axp-explorer-graph__entity-toggle:hover{background:rgb(var(--ax-sys-color-on-primary-lightest-surface) / .08)}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-toggle:hover{background:rgb(var(--ax-sys-color-on-warning-lightest-surface) / .08)}.axp-explorer-graph__entity-props{display:none;flex-direction:column;position:absolute;top:100%;left:0;right:0;z-index:6;margin:0;padding:6px 8px 8px;box-sizing:border-box;background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border:2px solid rgb(var(--ax-sys-color-border-primary-lightest-surface));border-top:1px solid rgb(var(--ax-sys-color-on-primary-lightest-surface) / .16);border-radius:0 0 8px 8px;max-height:320px;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgb(var(--ax-sys-color-on-primary-lightest-surface) / .3) transparent}.axp-explorer-graph__entity--expanded .axp-explorer-graph__entity-props{display:flex}.axp-explorer-graph__entity--external .axp-explorer-graph__entity-props{background:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface));border-top-color:rgb(var(--ax-sys-color-on-warning-lightest-surface) / .16)}.axp-explorer-graph__entity-prop{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);font-size:11px;--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);min-height:22px;margin:0;padding:3px 6px;border-radius:4px;box-sizing:border-box}.axp-explorer-graph__entity-prop-kind{flex-shrink:0;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);min-width:1.75rem;opacity:.85}.axp-explorer-graph__entity-prop-name{min-width:0px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));color:inherit}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
635
2100
|
}], ctorParameters: () => [], propDecorators: { moduleName: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleName", required: true }] }] } });
|
|
636
2101
|
|
|
637
|
-
//#region
|
|
2102
|
+
//#region ----- Imports -----
|
|
638
2103
|
//#endregion
|
|
639
|
-
//#region
|
|
2104
|
+
//#region ----- Component -----
|
|
640
2105
|
class AXPlatformExplorerDetailComponent {
|
|
641
2106
|
constructor() {
|
|
642
2107
|
this.node = input.required(/* @ts-ignore */
|
|
643
2108
|
...(ngDevMode ? [{ debugName: "node" }] : /* istanbul ignore next */ []));
|
|
644
2109
|
}
|
|
2110
|
+
asModule(payload) {
|
|
2111
|
+
return payload;
|
|
2112
|
+
}
|
|
2113
|
+
asEntity(payload) {
|
|
2114
|
+
return payload;
|
|
2115
|
+
}
|
|
2116
|
+
asNamed(payload) {
|
|
2117
|
+
return payload;
|
|
2118
|
+
}
|
|
645
2119
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
646
2120
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerDetailComponent, isStandalone: true, selector: "axp-platform-explorer-detail", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "flex flex-col flex-1 min-h-0" }, ngImport: i0, template: `
|
|
647
2121
|
<div class="flex flex-col flex-1 min-h-0">
|
|
648
2122
|
@switch (node().kind) {
|
|
649
2123
|
@case ('module') {
|
|
650
|
-
<axp-platform-explorer-module-detail [payload]="
|
|
2124
|
+
<axp-platform-explorer-module-detail [payload]="asModule(node().payload)" />
|
|
651
2125
|
}
|
|
652
2126
|
@case ('entity') {
|
|
653
|
-
<axp-platform-explorer-entity-detail [payload]="
|
|
2127
|
+
<axp-platform-explorer-entity-detail [payload]="asEntity(node().payload)" />
|
|
2128
|
+
}
|
|
2129
|
+
@case ('command') {
|
|
2130
|
+
<axp-platform-explorer-catalog-detail kind="command" [item]="asNamed(node().payload)" />
|
|
654
2131
|
}
|
|
655
|
-
@case ('
|
|
656
|
-
<axp-platform-explorer-
|
|
2132
|
+
@case ('query') {
|
|
2133
|
+
<axp-platform-explorer-catalog-detail kind="query" [item]="asNamed(node().payload)" />
|
|
657
2134
|
}
|
|
658
|
-
@case ('
|
|
659
|
-
<axp-platform-explorer-
|
|
2135
|
+
@case ('plugin') {
|
|
2136
|
+
<axp-platform-explorer-catalog-detail kind="plugin" [item]="asNamed(node().payload)" />
|
|
660
2137
|
}
|
|
661
|
-
@
|
|
662
|
-
<
|
|
2138
|
+
@case ('widget') {
|
|
2139
|
+
<axp-platform-explorer-catalog-detail kind="widget" [item]="asNamed(node().payload)" />
|
|
2140
|
+
}
|
|
2141
|
+
@case ('diagram') {
|
|
2142
|
+
<axp-platform-explorer-entities-graph [moduleName]="node().moduleName!" />
|
|
663
2143
|
}
|
|
664
2144
|
}
|
|
665
2145
|
</div>
|
|
666
|
-
`, isInline: true,
|
|
2146
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPlatformExplorerModuleDetailComponent, selector: "axp-platform-explorer-module-detail", inputs: ["payload"] }, { kind: "component", type: AXPlatformExplorerEntityDetailComponent, selector: "axp-platform-explorer-entity-detail", inputs: ["payload"] }, { kind: "component", type: AXPlatformExplorerCatalogDetailComponent, selector: "axp-platform-explorer-catalog-detail", inputs: ["kind", "item"] }, { kind: "component", type: AXPlatformExplorerEntitiesGraphComponent, selector: "axp-platform-explorer-entities-graph", inputs: ["moduleName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
667
2147
|
}
|
|
668
2148
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerDetailComponent, decorators: [{
|
|
669
2149
|
type: Component,
|
|
670
|
-
args: [{
|
|
2150
|
+
args: [{
|
|
2151
|
+
selector: 'axp-platform-explorer-detail',
|
|
2152
|
+
standalone: true,
|
|
2153
|
+
encapsulation: ViewEncapsulation.None,
|
|
2154
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2155
|
+
host: { class: 'flex flex-col flex-1 min-h-0' },
|
|
2156
|
+
imports: [
|
|
671
2157
|
AXTranslationModule,
|
|
672
2158
|
AXPlatformExplorerModuleDetailComponent,
|
|
673
2159
|
AXPlatformExplorerEntityDetailComponent,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
],
|
|
2160
|
+
AXPlatformExplorerCatalogDetailComponent,
|
|
2161
|
+
AXPlatformExplorerEntitiesGraphComponent,
|
|
2162
|
+
],
|
|
2163
|
+
template: `
|
|
677
2164
|
<div class="flex flex-col flex-1 min-h-0">
|
|
678
2165
|
@switch (node().kind) {
|
|
679
2166
|
@case ('module') {
|
|
680
|
-
<axp-platform-explorer-module-detail [payload]="
|
|
2167
|
+
<axp-platform-explorer-module-detail [payload]="asModule(node().payload)" />
|
|
681
2168
|
}
|
|
682
2169
|
@case ('entity') {
|
|
683
|
-
<axp-platform-explorer-entity-detail [payload]="
|
|
2170
|
+
<axp-platform-explorer-entity-detail [payload]="asEntity(node().payload)" />
|
|
684
2171
|
}
|
|
685
|
-
@case ('
|
|
686
|
-
<axp-platform-explorer-
|
|
2172
|
+
@case ('command') {
|
|
2173
|
+
<axp-platform-explorer-catalog-detail kind="command" [item]="asNamed(node().payload)" />
|
|
687
2174
|
}
|
|
688
|
-
@case ('
|
|
689
|
-
<axp-platform-explorer-
|
|
2175
|
+
@case ('query') {
|
|
2176
|
+
<axp-platform-explorer-catalog-detail kind="query" [item]="asNamed(node().payload)" />
|
|
690
2177
|
}
|
|
691
|
-
@
|
|
692
|
-
<
|
|
2178
|
+
@case ('plugin') {
|
|
2179
|
+
<axp-platform-explorer-catalog-detail kind="plugin" [item]="asNamed(node().payload)" />
|
|
2180
|
+
}
|
|
2181
|
+
@case ('widget') {
|
|
2182
|
+
<axp-platform-explorer-catalog-detail kind="widget" [item]="asNamed(node().payload)" />
|
|
2183
|
+
}
|
|
2184
|
+
@case ('diagram') {
|
|
2185
|
+
<axp-platform-explorer-entities-graph [moduleName]="node().moduleName!" />
|
|
693
2186
|
}
|
|
694
2187
|
}
|
|
695
2188
|
</div>
|
|
696
|
-
`,
|
|
2189
|
+
`,
|
|
2190
|
+
}]
|
|
697
2191
|
}], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }] } });
|
|
698
2192
|
|
|
699
|
-
//#region
|
|
2193
|
+
//#region ----- Imports -----
|
|
700
2194
|
//#endregion
|
|
701
|
-
//#region
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
2195
|
+
//#region ----- Constants -----
|
|
2196
|
+
const CATEGORY_SUFFIXES = ['entities', 'commands', 'queries', 'plugins', 'widgets'];
|
|
2197
|
+
const MODULE_LIST_MIN_WIDTH = 256;
|
|
2198
|
+
const MODULE_LIST_DEFAULT_WIDTH = 288;
|
|
2199
|
+
const MODULE_LIST_MAX_WIDTH = 560;
|
|
2200
|
+
const MODULE_LIST_WIDTH_KEY = 'axp.platform-explorer.module-list-width';
|
|
2201
|
+
function readStoredModuleListWidth() {
|
|
2202
|
+
try {
|
|
2203
|
+
const parsed = Number(localStorage.getItem(MODULE_LIST_WIDTH_KEY));
|
|
2204
|
+
if (Number.isFinite(parsed) &&
|
|
2205
|
+
parsed >= MODULE_LIST_MIN_WIDTH &&
|
|
2206
|
+
parsed <= MODULE_LIST_MAX_WIDTH) {
|
|
2207
|
+
return parsed;
|
|
714
2208
|
}
|
|
715
|
-
|
|
716
|
-
|
|
2209
|
+
}
|
|
2210
|
+
catch {
|
|
2211
|
+
// ignore missing storage
|
|
2212
|
+
}
|
|
2213
|
+
return MODULE_LIST_DEFAULT_WIDTH;
|
|
2214
|
+
}
|
|
2215
|
+
//#endregion
|
|
2216
|
+
//#region ----- Tree mapping -----
|
|
2217
|
+
function toTreeViewNode(node, childrenCount) {
|
|
2218
|
+
const count = childrenCount ?? node.itemCount;
|
|
2219
|
+
return {
|
|
2220
|
+
id: node.id,
|
|
2221
|
+
title: node.label,
|
|
2222
|
+
childrenCount: count && count > 0 ? count : undefined,
|
|
2223
|
+
data: { treeNode: node },
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function parseCategoryParent(parentId) {
|
|
2227
|
+
for (const suffix of CATEGORY_SUFFIXES) {
|
|
2228
|
+
const token = `-${suffix}`;
|
|
2229
|
+
if (parentId.startsWith('module-') && parentId.endsWith(token)) {
|
|
2230
|
+
return {
|
|
2231
|
+
moduleName: parentId.slice('module-'.length, parentId.length - token.length),
|
|
2232
|
+
kind: suffix,
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
return null;
|
|
717
2237
|
}
|
|
718
2238
|
//#endregion
|
|
719
|
-
//#region
|
|
2239
|
+
//#region ----- Component -----
|
|
720
2240
|
class AXPlatformExplorerPageComponent extends AXPPageLayoutBaseComponent {
|
|
721
2241
|
constructor() {
|
|
722
2242
|
super();
|
|
723
2243
|
this.dataService = inject(PlatformExplorerDataService);
|
|
2244
|
+
this.deviceService = inject(AXPDeviceService);
|
|
2245
|
+
this.route = inject(ActivatedRoute);
|
|
724
2246
|
this.loading = signal(true, /* @ts-ignore */
|
|
725
2247
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
2248
|
+
this.loadError = signal(false, /* @ts-ignore */
|
|
2249
|
+
...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
726
2250
|
this.selectedNode = signal(null, /* @ts-ignore */
|
|
727
2251
|
...(ngDevMode ? [{ debugName: "selectedNode" }] : /* istanbul ignore next */ []));
|
|
728
2252
|
this.moduleNodes = signal([], /* @ts-ignore */
|
|
729
2253
|
...(ngDevMode ? [{ debugName: "moduleNodes" }] : /* istanbul ignore next */ []));
|
|
2254
|
+
this.hasCatalogModules = computed(() => this.moduleNodes().some((node) => node.kind === 'module'), /* @ts-ignore */
|
|
2255
|
+
...(ngDevMode ? [{ debugName: "hasCatalogModules" }] : /* istanbul ignore next */ []));
|
|
2256
|
+
this.search = signal('', /* @ts-ignore */
|
|
2257
|
+
...(ngDevMode ? [{ debugName: "search" }] : /* istanbul ignore next */ []));
|
|
730
2258
|
this.tree = viewChild('tree', /* @ts-ignore */
|
|
731
2259
|
...(ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []));
|
|
732
|
-
|
|
2260
|
+
this.entityTabs = this.dataService.entityTabs;
|
|
2261
|
+
this.activeEntitySection = this.dataService.activeEntitySection;
|
|
2262
|
+
this.moduleListMinWidth = MODULE_LIST_MIN_WIDTH;
|
|
2263
|
+
this.moduleListDefaultWidth = MODULE_LIST_DEFAULT_WIDTH;
|
|
2264
|
+
this.moduleListMaxWidth = MODULE_LIST_MAX_WIDTH;
|
|
2265
|
+
this.moduleListWidth = signal(readStoredModuleListWidth(), /* @ts-ignore */
|
|
2266
|
+
...(ngDevMode ? [{ debugName: "moduleListWidth" }] : /* istanbul ignore next */ []));
|
|
2267
|
+
this.catalogReady = false;
|
|
2268
|
+
this.syncingFromUrl = false;
|
|
733
2269
|
this.datasource = async (parentId) => {
|
|
734
2270
|
if (!parentId) {
|
|
735
|
-
|
|
736
|
-
|
|
2271
|
+
return this.moduleNodes().map((node) => toTreeViewNode(node, node.itemCount));
|
|
2272
|
+
}
|
|
2273
|
+
const category = parseCategoryParent(parentId);
|
|
2274
|
+
if (category) {
|
|
2275
|
+
const children = await this.dataService.getCategoryChildren(category.moduleName, category.kind);
|
|
2276
|
+
return children.map((node) => toTreeViewNode(node));
|
|
2277
|
+
}
|
|
2278
|
+
if (parentId.startsWith('module-')) {
|
|
2279
|
+
const moduleName = parentId.slice('module-'.length);
|
|
2280
|
+
const children = await this.dataService.getModuleChildren(moduleName);
|
|
2281
|
+
return children.map((node) => toTreeViewNode(node, node.itemCount));
|
|
737
2282
|
}
|
|
738
|
-
|
|
739
|
-
return toTreeViewNodes(children, false);
|
|
2283
|
+
return [];
|
|
740
2284
|
};
|
|
741
|
-
this.
|
|
2285
|
+
this.route.queryParamMap.pipe(takeUntilDestroyed()).subscribe((params) => {
|
|
2286
|
+
void this.onQueryChanged(params);
|
|
2287
|
+
});
|
|
2288
|
+
void this.boot();
|
|
742
2289
|
}
|
|
743
|
-
async
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
}
|
|
2290
|
+
async onSearchChanged(event) {
|
|
2291
|
+
const text = typeof event.value === 'string' ? event.value : '';
|
|
2292
|
+
this.search.set(text);
|
|
2293
|
+
this.dataService.clearCache();
|
|
2294
|
+
await this.initializeModules(text);
|
|
2295
|
+
await this.tree()?.reloadData();
|
|
2296
|
+
this.writeQuery(this.selectedNode());
|
|
2297
|
+
await this.revealSelection();
|
|
752
2298
|
}
|
|
753
2299
|
async getPageTitle() {
|
|
754
2300
|
const node = this.selectedNode();
|
|
755
2301
|
if (!node) {
|
|
756
|
-
return this.translateService.translateAsync('@platform-dev-tools:module.title');
|
|
2302
|
+
return this.translateService.translateAsync('@platform-dev-tools:module.menus.platform-explorer.title');
|
|
757
2303
|
}
|
|
758
2304
|
const moduleTitleKey = node.moduleTitle ?? node.label;
|
|
759
2305
|
const moduleTitle = await this.translateService.translateAsync(moduleTitleKey);
|
|
760
|
-
const contextParts = [];
|
|
761
2306
|
switch (node.kind) {
|
|
2307
|
+
case 'type-group':
|
|
2308
|
+
return this.translateService.translateAsync('@platform-dev-tools:module.menus.platform-explorer.title');
|
|
762
2309
|
case 'module':
|
|
763
2310
|
return moduleTitle;
|
|
764
|
-
case 'entities':
|
|
765
|
-
contextParts.push(await this.translateService.translateAsync('@platform-dev-tools:module.terms.entities'));
|
|
766
|
-
break;
|
|
767
2311
|
case 'entity':
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
case '
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
default:
|
|
778
|
-
return moduleTitle;
|
|
2312
|
+
case 'command':
|
|
2313
|
+
case 'query':
|
|
2314
|
+
case 'plugin':
|
|
2315
|
+
case 'widget':
|
|
2316
|
+
return [moduleTitle, node.label].join(' · ');
|
|
2317
|
+
default: {
|
|
2318
|
+
const folder = await this.translateService.translateAsync(node.label);
|
|
2319
|
+
return [moduleTitle, folder].join(' · ');
|
|
2320
|
+
}
|
|
779
2321
|
}
|
|
780
|
-
return [moduleTitle, ...contextParts].join(' - ');
|
|
781
2322
|
}
|
|
782
2323
|
getPageDescription() {
|
|
783
2324
|
const node = this.selectedNode();
|
|
784
|
-
if (!node)
|
|
785
|
-
return
|
|
2325
|
+
if (!node) {
|
|
2326
|
+
return this.translateService.translateAsync('@platform-dev-tools:module.description');
|
|
2327
|
+
}
|
|
2328
|
+
if (node.kind === 'entity') {
|
|
2329
|
+
const entity = node.payload;
|
|
2330
|
+
return entity?.fullName ?? null;
|
|
2331
|
+
}
|
|
786
2332
|
const key = this.descriptionKeyForKind(node.kind);
|
|
787
2333
|
return key ? this.translateService.translateAsync(key) : null;
|
|
788
2334
|
}
|
|
@@ -796,182 +2342,335 @@ class AXPlatformExplorerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
796
2342
|
}
|
|
797
2343
|
return items;
|
|
798
2344
|
}
|
|
2345
|
+
onModuleListResized(event) {
|
|
2346
|
+
if (!event.isUserInteraction || event.value == null) {
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
const width = Math.min(MODULE_LIST_MAX_WIDTH, Math.max(MODULE_LIST_MIN_WIDTH, event.value));
|
|
2350
|
+
this.moduleListWidth.set(width);
|
|
2351
|
+
try {
|
|
2352
|
+
localStorage.setItem(MODULE_LIST_WIDTH_KEY, String(width));
|
|
2353
|
+
}
|
|
2354
|
+
catch {
|
|
2355
|
+
// ignore quota / private mode
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
async onNodeClick(event) {
|
|
2359
|
+
const data = event.node?.['data'];
|
|
2360
|
+
const treeNode = data?.treeNode;
|
|
2361
|
+
if (!treeNode || treeNode.kind === 'type-group') {
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
if (isExplorerFolderKind(treeNode.kind)) {
|
|
2365
|
+
const tree = this.tree();
|
|
2366
|
+
if (tree) {
|
|
2367
|
+
await tree.toggleNodeExpansion(treeNode.id);
|
|
2368
|
+
const current = this.selectedNode();
|
|
2369
|
+
if (current) {
|
|
2370
|
+
tree.selectNode(current.id);
|
|
2371
|
+
}
|
|
2372
|
+
else {
|
|
2373
|
+
tree.deselectNode(treeNode.id);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
this.selectPageNode(treeNode);
|
|
2379
|
+
}
|
|
2380
|
+
onEntityTabChanged(event) {
|
|
2381
|
+
const key = event.tab?.key || this.entityTabs()[event.index]?.id;
|
|
2382
|
+
if (!key || key === this.dataService.activeEntitySection()) {
|
|
2383
|
+
return;
|
|
2384
|
+
}
|
|
2385
|
+
this.dataService.selectEntitySection(key);
|
|
2386
|
+
}
|
|
799
2387
|
descriptionKeyForKind(kind) {
|
|
800
2388
|
switch (kind) {
|
|
801
2389
|
case 'module':
|
|
802
2390
|
return '@platform-dev-tools:module.descriptions.module';
|
|
803
|
-
case '
|
|
804
|
-
return '@platform-dev-tools:module.descriptions.
|
|
805
|
-
case '
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
case '
|
|
810
|
-
return '@platform-dev-tools:module.descriptions.
|
|
2391
|
+
case 'diagram':
|
|
2392
|
+
return '@platform-dev-tools:module.descriptions.diagram';
|
|
2393
|
+
case 'commands':
|
|
2394
|
+
case 'command':
|
|
2395
|
+
return '@platform-dev-tools:module.descriptions.command';
|
|
2396
|
+
case 'queries':
|
|
2397
|
+
case 'query':
|
|
2398
|
+
return '@platform-dev-tools:module.descriptions.query';
|
|
2399
|
+
case 'plugins':
|
|
2400
|
+
case 'plugin':
|
|
2401
|
+
return '@platform-dev-tools:module.descriptions.plugin';
|
|
2402
|
+
case 'widgets':
|
|
2403
|
+
case 'widget':
|
|
2404
|
+
return '@platform-dev-tools:module.descriptions.widget';
|
|
811
2405
|
default:
|
|
812
2406
|
return null;
|
|
813
2407
|
}
|
|
814
2408
|
}
|
|
815
|
-
|
|
816
|
-
const
|
|
817
|
-
const
|
|
818
|
-
const
|
|
819
|
-
if (
|
|
820
|
-
this.
|
|
2409
|
+
async onQueryChanged(params) {
|
|
2410
|
+
const state = explorerStateFromQuery(params);
|
|
2411
|
+
const nextSearch = state.search ?? '';
|
|
2412
|
+
const searchChanged = nextSearch !== this.search();
|
|
2413
|
+
if (searchChanged) {
|
|
2414
|
+
this.search.set(nextSearch);
|
|
2415
|
+
}
|
|
2416
|
+
if (!this.catalogReady) {
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
if (searchChanged) {
|
|
2420
|
+
this.dataService.clearCache();
|
|
2421
|
+
await this.initializeModules(nextSearch);
|
|
2422
|
+
await this.tree()?.reloadData();
|
|
2423
|
+
}
|
|
2424
|
+
await this.applyRouteState(state);
|
|
2425
|
+
}
|
|
2426
|
+
async boot() {
|
|
2427
|
+
const state = explorerStateFromQuery(this.route.snapshot.queryParamMap);
|
|
2428
|
+
if (state.search) {
|
|
2429
|
+
this.search.set(state.search);
|
|
2430
|
+
}
|
|
2431
|
+
await this.initializeModules(this.search());
|
|
2432
|
+
this.catalogReady = true;
|
|
2433
|
+
await this.applyRouteState(state);
|
|
2434
|
+
}
|
|
2435
|
+
selectPageNode(treeNode) {
|
|
2436
|
+
this.dataService.clearEntityTabs();
|
|
2437
|
+
this.selectedNode.set(treeNode);
|
|
2438
|
+
this.recompute();
|
|
2439
|
+
this.writeQuery(treeNode);
|
|
2440
|
+
}
|
|
2441
|
+
writeQuery(node) {
|
|
2442
|
+
if (this.syncingFromUrl) {
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
void this.router.navigate([], {
|
|
2446
|
+
relativeTo: this.route,
|
|
2447
|
+
queryParams: queryParamsFromExplorer(node, this.search()),
|
|
2448
|
+
replaceUrl: true,
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
async applyRouteState(state) {
|
|
2452
|
+
this.syncingFromUrl = true;
|
|
2453
|
+
try {
|
|
2454
|
+
const node = await this.dataService.resolveExplorerSelection(state, this.moduleNodes());
|
|
2455
|
+
if (sameExplorerNode(this.selectedNode(), node)) {
|
|
2456
|
+
await this.revealSelection();
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2459
|
+
this.dataService.clearEntityTabs();
|
|
2460
|
+
this.selectedNode.set(node);
|
|
821
2461
|
this.recompute();
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
2462
|
+
await this.revealSelection();
|
|
2463
|
+
}
|
|
2464
|
+
finally {
|
|
2465
|
+
this.syncingFromUrl = false;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
async revealSelection() {
|
|
2469
|
+
const node = this.selectedNode();
|
|
2470
|
+
if (!node) {
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
const tree = await this.waitForTree();
|
|
2474
|
+
if (!tree) {
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2477
|
+
const ids = explorerRevealIds(node);
|
|
2478
|
+
for (const id of ids.slice(0, -1)) {
|
|
2479
|
+
try {
|
|
2480
|
+
await tree.expandNode(id);
|
|
2481
|
+
}
|
|
2482
|
+
catch {
|
|
2483
|
+
// node may not be in the filtered tree
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
try {
|
|
2487
|
+
tree.selectNode(node.id);
|
|
2488
|
+
}
|
|
2489
|
+
catch {
|
|
2490
|
+
// ignore missing tree node
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
async waitForTree() {
|
|
2494
|
+
for (let attempt = 0; attempt < 12; attempt++) {
|
|
2495
|
+
const tree = this.tree();
|
|
2496
|
+
if (tree) {
|
|
2497
|
+
return tree;
|
|
828
2498
|
}
|
|
2499
|
+
await new Promise((resolve) => setTimeout(resolve, 16));
|
|
829
2500
|
}
|
|
2501
|
+
return this.tree();
|
|
830
2502
|
}
|
|
831
|
-
|
|
832
|
-
|
|
2503
|
+
async initializeModules(search) {
|
|
2504
|
+
this.loading.set(true);
|
|
2505
|
+
this.loadError.set(false);
|
|
2506
|
+
try {
|
|
2507
|
+
const modules = await this.dataService.listModules(search);
|
|
2508
|
+
this.moduleNodes.set(this.dataService.toModuleTreeNodes(modules));
|
|
2509
|
+
}
|
|
2510
|
+
catch {
|
|
2511
|
+
this.loadError.set(true);
|
|
2512
|
+
this.moduleNodes.set([]);
|
|
2513
|
+
}
|
|
2514
|
+
finally {
|
|
2515
|
+
this.loading.set(false);
|
|
2516
|
+
}
|
|
833
2517
|
}
|
|
834
2518
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
835
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerPageComponent, isStandalone: true, selector: "axp-platform-explorer-page", providers: [
|
|
2519
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerPageComponent, isStandalone: true, selector: "axp-platform-explorer-page", host: { classAttribute: "axp-platform-explorer" }, providers: [
|
|
836
2520
|
PlatformExplorerDataService,
|
|
837
2521
|
{
|
|
838
2522
|
provide: AXPPageLayoutBase,
|
|
839
2523
|
useExisting: AXPlatformExplorerPageComponent,
|
|
840
2524
|
},
|
|
841
|
-
], viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout>\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{ '@platform-dev-tools:module.menus.platform-explorer.title' | translate | async\n }}</axp-layout-title>\n </axp-layout-header>\n <axp-layout-content class=\"axp-platform-explorer__tree-wrap\">\n @if (loading()) {\n <p class=\"axp-platform-explorer__loading\">Loading...</p>\n } @else if (moduleNodes().length === 0) {\n <p class=\"axp-platform-explorer__empty\">{{ '@platform-dev-tools:module.messages.no-modules' | translate | async }}\n </p>\n } @else {\n <ax-tree-view #tree [datasource]=\"datasource\" [selectMode]=\"'single'\" [showIcons]=\"false\"\n [showChildrenBadge]=\"true\" [dragBehavior]=\"'none'\" look=\"default\" [nodeTemplate]=\"nodeTemplate\"\n (onNodeClick)=\"onNodeClick($event)\" (onNodeToggle)=\"onNodeToggle($event)\" />\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-content class=\"min-h-0 pt-0\">\n @if (selectedNode()) {\n <axp-platform-explorer-detail [node]=\"selectedNode()!\" />\n } @else {\n <p class=\"axp-platform-explorer__hint\">{{ '@platform-dev-tools:module.messages.select-node' | translate | async }}\n </p>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Node template: icon per kind (with color) + label (translated) + badge -->\n<ng-template #nodeTemplate let-node=\"node\">\n @let data = node['data'];\n @let treeNode = $safeNavigationMigration(data?.treeNode);\n @let kind = $safeNavigationMigration(treeNode?.kind);\n @let count = node['childrenCount'] ?? treeNode?.itemCount;\n <span class=\"axp-platform-explorer__node\">\n @switch (kind) {\n @case ('module') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--module fa-light fa-cube\"\n aria-hidden=\"true\"></i>\n }\n @case ('entities') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entities fa-light fa-table-list\"\n aria-hidden=\"true\"></i>\n }\n @case ('entity') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entity fa-light fa-table\"\n aria-hidden=\"true\"></i>\n }\n @case ('permissions') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--permissions fa-light fa-shield-halved\"\n aria-hidden=\"true\"></i>\n }\n @case ('features') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--features fa-light fa-sliders\"\n aria-hidden=\"true\"></i>\n }\n @default {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--default fa-light fa-circle-dot\"\n aria-hidden=\"true\"></i>\n }\n }\n <span class=\"axp-platform-explorer__node-label\">{{ node['title'] | translate | async }}</span>\n @if (count != null && count > 0) {\n <span class=\"axp-platform-explorer__node-badge\">{{ count }}</span>\n }\n </span>\n</ng-template>", styles: ["@layer properties;.axp-platform-explorer .axp-platform-explorer__tree-wrap{display:flex;min-height:0px;min-width:calc(var(--spacing, .25rem) * 64);flex-direction:column;overflow-x:auto;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 4);max-height:calc(100vh - 180px)}.axp-platform-explorer .axp-platform-explorer__loading,.axp-platform-explorer .axp-platform-explorer__empty{margin:0;padding:calc(var(--spacing, .25rem) * 4);color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__hint{padding:calc(var(--spacing, .25rem) * 6);color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer .axp-platform-explorer__node-icon{width:1em;flex-shrink:0}.axp-platform-explorer .axp-platform-explorer__node-icon--module{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--entities{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node-icon--entity{color:rgba(var(--ax-sys-color-accent1-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--permissions{color:rgba(var(--ax-sys-color-success-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--features{color:rgba(var(--ax-sys-color-warning-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--default{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node-label{min-width:0px;flex:1;white-space:nowrap}.axp-platform-explorer .axp-platform-explorer__node-badge{margin-left:auto;min-width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 1.5);text-align:center;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "alternate", "nodeTemplate", "idField", "titleField", "highlightText", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick", "doubleClickDuration", "tooltipDelay", "controlledSelection", "selectedIds"], outputs: ["datasourceChange", "selectedIdsChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "component", type: AXPlatformExplorerDetailComponent, selector: "axp-platform-explorer-detail", inputs: ["node"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2525
|
+
], viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout>\n <axp-layout-start-side\n class=\"axp-platform-explorer__start-side\"\n [axResizable]=\"!deviceService.isSmall()\"\n [minWidth]=\"moduleListMinWidth\"\n [maxWidth]=\"moduleListMaxWidth\"\n [width]=\"moduleListWidth()\"\n [defaultWidth]=\"moduleListDefaultWidth\"\n [dblClickAction]=\"'reset'\"\n (onResizingEnded)=\"onModuleListResized($event)\"\n (onResizingDblClick)=\"onModuleListResized($event)\"\n >\n <axp-layout-header>\n <axp-layout-title>\n {{ '@platform-dev-tools:module.menus.platform-explorer.title' | translate | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content class=\"axp-platform-explorer__tree-wrap\">\n <ax-search-box\n class=\"axp-platform-explorer__search\"\n look=\"fill\"\n [delayTime]=\"300\"\n [value]=\"search()\"\n [placeholder]=\"('@platform-dev-tools:module.messages.search-modules' | translate | async) ?? ''\"\n (onValueChanged)=\"onSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n <!-- ----- Loading catalog modules ----- -->\n @if (loading()) {\n <div class=\"axp-platform-explorer__loading\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- No modules in catalog ----- -->\n @else if (!hasCatalogModules()) {\n <axp-state-message\n icon=\"fa-light fa-cubes\"\n [title]=\"'@platform-dev-tools:module.messages.no-modules'\"\n [description]=\"'@platform-dev-tools:module.messages.no-modules-hint'\"\n />\n }\n <!-- ----- Module tree ----- -->\n @else {\n <ax-tree-view\n #tree\n [datasource]=\"datasource\"\n [selectMode]=\"'single'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"'none'\"\n look=\"default\"\n [nodeTemplate]=\"nodeTemplate\"\n (onNodeClick)=\"onNodeClick($event)\"\n />\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- ----- Entity layout tabs stay in the sticky page header ----- -->\n @if (entityTabs().length) {\n <axp-page-toolbar class=\"axp-platform-explorer__entity-toolbar\">\n <ax-tabs\n class=\"axp-platform-explorer__entity-tabs\"\n [look]=\"'with-line'\"\n [location]=\"'bottom'\"\n [fitParent]=\"false\"\n (onActiveTabChanged)=\"onEntityTabChanged($event)\"\n >\n @for (tab of entityTabs(); track tab.id) {\n <ax-tab-item\n [key]=\"tab.id\"\n [text]=\"\n ((tab.textKey | translate | async) ?? '') +\n (tab.extraText ? ' \u00B7 ' + ((tab.extraText | translate | async) ?? '') : '')\n \"\n [active]=\"activeEntitySection() === tab.id\"\n />\n }\n </ax-tabs>\n </axp-page-toolbar>\n }\n\n <axp-page-content class=\"axp-platform-explorer__page-content min-h-0 pt-0\">\n <!-- ----- Selected catalog node ----- -->\n @if (selectedNode(); as node) {\n <axp-platform-explorer-detail [node]=\"node\" />\n }\n <!-- ----- Empty selection ----- -->\n @else {\n <axp-state-message\n icon=\"fa-light fa-sitemap\"\n [title]=\"'@platform-dev-tools:module.messages.select-node'\"\n [description]=\"'@platform-dev-tools:module.messages.select-node-hint'\"\n />\n }\n </axp-page-content>\n</axp-page-layout>\n\n<ng-template #nodeTemplate let-node=\"node\">\n @let data = node['data'];\n @let treeNode = data?.treeNode;\n @let kind = treeNode?.kind;\n @let count = node['childrenCount'] ?? treeNode?.itemCount;\n <!-- ----- Manifest type group header ----- -->\n @if (kind === 'type-group') {\n <span\n class=\"axp-platform-explorer__node axp-platform-explorer__node--group\"\n [class.axp-platform-explorer__node--group-divided]=\"treeNode?.divided\"\n >\n <!--->\n <!-- ----- Divider after the previous type group ----- -->\n @if (treeNode?.divided) {\n <span class=\"axp-platform-explorer__group-rule\" aria-hidden=\"true\"></span>\n }\n <span class=\"axp-platform-explorer__group-title\">{{ node['title'] | translate | async }}</span>\n </span>\n }\n <!-- ----- Catalog node ----- -->\n @else {\n <span class=\"axp-platform-explorer__node\">\n @switch (kind) {\n @case ('module') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--module\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-cube'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('entities') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entities fa-light fa-table\" aria-hidden=\"true\"></i>\n }\n @case ('diagram') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--diagram fa-light fa-diagram-project\" aria-hidden=\"true\"></i>\n }\n @case ('entity') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entity\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-table'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('commands') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--commands fa-light fa-terminal\" aria-hidden=\"true\"></i>\n }\n @case ('command') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--command\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-play'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('queries') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--queries fa-light fa-database\" aria-hidden=\"true\"></i>\n }\n @case ('query') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--query\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-magnifying-glass'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('plugins') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--plugins fa-light fa-puzzle-piece\" aria-hidden=\"true\"></i>\n }\n @case ('plugin') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--plugin\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-plug'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('widgets') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--widgets fa-light fa-cubes\" aria-hidden=\"true\"></i>\n }\n @case ('widget') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--widget\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-cube'\"\n aria-hidden=\"true\"\n ></i>\n }\n @default {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--default fa-light fa-circle-dot\" aria-hidden=\"true\"></i>\n }\n }\n <span class=\"axp-platform-explorer__node-label\">{{ node['title'] | translate | async }}</span>\n <!--->\n <!-- ----- Child count badge when the folder has items ----- -->\n @if (count != null && count > 0) {\n <span class=\"axp-platform-explorer__node-badge\">{{ count }}</span>\n }\n </span>\n }\n</ng-template>\n", styles: ["@layer properties;.axp-platform-explorer axp-layout-container{overflow:hidden}.axp-platform-explorer__page-content{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden}axp-platform-explorer-detail,axp-platform-explorer-entity-detail{display:flex;height:100%;min-height:0px;flex:1;flex-direction:column;overflow:hidden}.axp-platform-explorer__tree-wrap{display:flex;min-height:0px;width:100%;min-width:0px;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);overflow-x:hidden;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 3);max-height:calc(100vh - 180px)}.axp-platform-explorer__start-side{position:relative;height:100%;flex-shrink:0;overflow:visible}.axp-platform-explorer #axp-drawer-start{overflow:visible}.axp-platform-explorer__search{flex-shrink:0}.axp-platform-explorer__loading{display:flex;flex:1;align-items:center;justify-content:center;padding:calc(var(--spacing, .25rem) * 6)}.axp-platform-explorer__node{display:flex;width:100%;min-width:0px;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__node--group{pointer-events:none;width:100%;min-width:0px;flex-direction:column;align-items:stretch;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__node--group-divided{margin-top:var(--spacing, .25rem);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__group-rule{display:block;width:100%;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgba(var(--ax-sys-color-light-surface))}.axp-platform-explorer__group-title{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__group-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group){pointer-events:none;cursor:default;background:transparent!important;min-height:0!important;padding-block:.25rem;padding-inline-start:0!important}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group) .ax-tree-view-node-content{padding-inline-start:0!important;margin-inline-start:0!important}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group) .ax-tree-view-expand-toggle{display:none!important;width:0!important;min-width:0!important;margin:0!important;padding:0!important}.axp-platform-explorer__node-icon{width:1em;flex-shrink:0;text-align:center}.axp-platform-explorer__node-icon--module{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__node-icon--diagram,.axp-platform-explorer__node-icon--entities,.axp-platform-explorer__node-icon--entity{color:rgba(var(--ax-sys-color-accent1-surface))}.axp-platform-explorer__node-icon--commands,.axp-platform-explorer__node-icon--command{color:rgba(var(--ax-sys-color-success-surface))}.axp-platform-explorer__node-icon--queries,.axp-platform-explorer__node-icon--query{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__node-icon--plugins,.axp-platform-explorer__node-icon--plugin{color:rgba(var(--ax-sys-color-warning-surface))}.axp-platform-explorer__node-icon--widgets,.axp-platform-explorer__node-icon--widget,.axp-platform-explorer__node-icon--default{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer__node-label{min-width:0px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-platform-explorer__node-badge{margin-left:auto;min-width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 1.5);text-align:center;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__entity-toolbar{width:100%}.axp-platform-explorer__entity-tabs{width:100%;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i2$1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i3$1.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i5$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "reorderable", "reorderDelay", "renderMode", "stacked", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged", "onTabsReordered"] }, { kind: "component", type: i5$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "alternate", "nodeTemplate", "idField", "titleField", "highlightText", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick", "doubleClickDuration", "tooltipDelay", "controlledSelection", "selectedIds"], outputs: ["datasourceChange", "selectedIdsChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "component", type: AXPlatformExplorerDetailComponent, selector: "axp-platform-explorer-detail", inputs: ["node"] }, { kind: "directive", type: AXResizableDirective, selector: "[axResizable]", inputs: ["axResizable", "handles", "minWidth", "maxWidth", "minHeight", "maxHeight", "dblClickAction", "width", "defaultWidth", "height", "defaultHeight", "lockAspectRatio"], outputs: ["axResizableChange", "handlesChange", "minWidthChange", "maxWidthChange", "minHeightChange", "maxHeightChange", "dblClickActionChange", "widthChange", "defaultWidthChange", "heightChange", "defaultHeightChange", "lockAspectRatioChange", "onResizingStarted", "onResizingEnded", "onResizingDblClick"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
842
2526
|
}
|
|
843
2527
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerPageComponent, decorators: [{
|
|
844
2528
|
type: Component,
|
|
845
|
-
args: [{ selector: 'axp-platform-explorer-page', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
2529
|
+
args: [{ selector: 'axp-platform-explorer-page', standalone: true, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'axp-platform-explorer' }, imports: [
|
|
846
2530
|
CommonModule,
|
|
847
2531
|
AXTranslationModule,
|
|
2532
|
+
AXLoadingModule,
|
|
2533
|
+
AXSearchBoxModule,
|
|
2534
|
+
AXDecoratorModule,
|
|
2535
|
+
AXTabsModule,
|
|
848
2536
|
AXPPageLayoutComponent,
|
|
849
2537
|
AXPThemeLayoutStartSideComponent,
|
|
850
2538
|
AXPThemeLayoutHeaderComponent,
|
|
851
2539
|
AXPThemeLayoutBlockComponent,
|
|
2540
|
+
AXPStateMessageComponent,
|
|
852
2541
|
AXTreeViewComponent,
|
|
853
2542
|
AXPlatformExplorerDetailComponent,
|
|
2543
|
+
AXResizableDirective,
|
|
854
2544
|
], providers: [
|
|
855
2545
|
PlatformExplorerDataService,
|
|
856
2546
|
{
|
|
857
2547
|
provide: AXPPageLayoutBase,
|
|
858
2548
|
useExisting: AXPlatformExplorerPageComponent,
|
|
859
2549
|
},
|
|
860
|
-
], template: "<axp-page-layout>\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{ '@platform-dev-tools:module.menus.platform-explorer.title' | translate | async\n }}</axp-layout-title>\n </axp-layout-header>\n <axp-layout-content class=\"axp-platform-explorer__tree-wrap\">\n @if (loading()) {\n <p class=\"axp-platform-explorer__loading\">Loading...</p>\n } @else if (moduleNodes().length === 0) {\n <p class=\"axp-platform-explorer__empty\">{{ '@platform-dev-tools:module.messages.no-modules' | translate | async }}\n </p>\n } @else {\n <ax-tree-view #tree [datasource]=\"datasource\" [selectMode]=\"'single'\" [showIcons]=\"false\"\n [showChildrenBadge]=\"true\" [dragBehavior]=\"'none'\" look=\"default\" [nodeTemplate]=\"nodeTemplate\"\n (onNodeClick)=\"onNodeClick($event)\" (onNodeToggle)=\"onNodeToggle($event)\" />\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <axp-page-content class=\"min-h-0 pt-0\">\n @if (selectedNode()) {\n <axp-platform-explorer-detail [node]=\"selectedNode()!\" />\n } @else {\n <p class=\"axp-platform-explorer__hint\">{{ '@platform-dev-tools:module.messages.select-node' | translate | async }}\n </p>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Node template: icon per kind (with color) + label (translated) + badge -->\n<ng-template #nodeTemplate let-node=\"node\">\n @let data = node['data'];\n @let treeNode = $safeNavigationMigration(data?.treeNode);\n @let kind = $safeNavigationMigration(treeNode?.kind);\n @let count = node['childrenCount'] ?? treeNode?.itemCount;\n <span class=\"axp-platform-explorer__node\">\n @switch (kind) {\n @case ('module') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--module fa-light fa-cube\"\n aria-hidden=\"true\"></i>\n }\n @case ('entities') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entities fa-light fa-table-list\"\n aria-hidden=\"true\"></i>\n }\n @case ('entity') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entity fa-light fa-table\"\n aria-hidden=\"true\"></i>\n }\n @case ('permissions') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--permissions fa-light fa-shield-halved\"\n aria-hidden=\"true\"></i>\n }\n @case ('features') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--features fa-light fa-sliders\"\n aria-hidden=\"true\"></i>\n }\n @default {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--default fa-light fa-circle-dot\"\n aria-hidden=\"true\"></i>\n }\n }\n <span class=\"axp-platform-explorer__node-label\">{{ node['title'] | translate | async }}</span>\n @if (count != null && count > 0) {\n <span class=\"axp-platform-explorer__node-badge\">{{ count }}</span>\n }\n </span>\n</ng-template>", styles: ["@layer properties;.axp-platform-explorer .axp-platform-explorer__tree-wrap{display:flex;min-height:0px;min-width:calc(var(--spacing, .25rem) * 64);flex-direction:column;overflow-x:auto;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 4);max-height:calc(100vh - 180px)}.axp-platform-explorer .axp-platform-explorer__loading,.axp-platform-explorer .axp-platform-explorer__empty{margin:0;padding:calc(var(--spacing, .25rem) * 4);color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__hint{padding:calc(var(--spacing, .25rem) * 6);color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer .axp-platform-explorer__node-icon{width:1em;flex-shrink:0}.axp-platform-explorer .axp-platform-explorer__node-icon--module{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--entities{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node-icon--entity{color:rgba(var(--ax-sys-color-accent1-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--permissions{color:rgba(var(--ax-sys-color-success-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--features{color:rgba(var(--ax-sys-color-warning-surface))}.axp-platform-explorer .axp-platform-explorer__node-icon--default{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer .axp-platform-explorer__node-label{min-width:0px;flex:1;white-space:nowrap}.axp-platform-explorer .axp-platform-explorer__node-badge{margin-left:auto;min-width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 1.5);text-align:center;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-font-weight: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
2550
|
+
], template: "<axp-page-layout>\n <axp-layout-start-side\n class=\"axp-platform-explorer__start-side\"\n [axResizable]=\"!deviceService.isSmall()\"\n [minWidth]=\"moduleListMinWidth\"\n [maxWidth]=\"moduleListMaxWidth\"\n [width]=\"moduleListWidth()\"\n [defaultWidth]=\"moduleListDefaultWidth\"\n [dblClickAction]=\"'reset'\"\n (onResizingEnded)=\"onModuleListResized($event)\"\n (onResizingDblClick)=\"onModuleListResized($event)\"\n >\n <axp-layout-header>\n <axp-layout-title>\n {{ '@platform-dev-tools:module.menus.platform-explorer.title' | translate | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content class=\"axp-platform-explorer__tree-wrap\">\n <ax-search-box\n class=\"axp-platform-explorer__search\"\n look=\"fill\"\n [delayTime]=\"300\"\n [value]=\"search()\"\n [placeholder]=\"('@platform-dev-tools:module.messages.search-modules' | translate | async) ?? ''\"\n (onValueChanged)=\"onSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n <!-- ----- Loading catalog modules ----- -->\n @if (loading()) {\n <div class=\"axp-platform-explorer__loading\">\n <ax-loading></ax-loading>\n </div>\n }\n <!-- ----- Catalog query failed ----- -->\n @else if (loadError()) {\n <axp-state-message\n icon=\"fa-light fa-triangle-exclamation\"\n [title]=\"'@platform-dev-tools:module.messages.load-error-title'\"\n [description]=\"'@platform-dev-tools:module.messages.load-error'\"\n />\n }\n <!-- ----- No modules in catalog ----- -->\n @else if (!hasCatalogModules()) {\n <axp-state-message\n icon=\"fa-light fa-cubes\"\n [title]=\"'@platform-dev-tools:module.messages.no-modules'\"\n [description]=\"'@platform-dev-tools:module.messages.no-modules-hint'\"\n />\n }\n <!-- ----- Module tree ----- -->\n @else {\n <ax-tree-view\n #tree\n [datasource]=\"datasource\"\n [selectMode]=\"'single'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"'none'\"\n look=\"default\"\n [nodeTemplate]=\"nodeTemplate\"\n (onNodeClick)=\"onNodeClick($event)\"\n />\n }\n </axp-layout-content>\n </axp-layout-start-side>\n\n <!-- ----- Entity layout tabs stay in the sticky page header ----- -->\n @if (entityTabs().length) {\n <axp-page-toolbar class=\"axp-platform-explorer__entity-toolbar\">\n <ax-tabs\n class=\"axp-platform-explorer__entity-tabs\"\n [look]=\"'with-line'\"\n [location]=\"'bottom'\"\n [fitParent]=\"false\"\n (onActiveTabChanged)=\"onEntityTabChanged($event)\"\n >\n @for (tab of entityTabs(); track tab.id) {\n <ax-tab-item\n [key]=\"tab.id\"\n [text]=\"\n ((tab.textKey | translate | async) ?? '') +\n (tab.extraText ? ' \u00B7 ' + ((tab.extraText | translate | async) ?? '') : '')\n \"\n [active]=\"activeEntitySection() === tab.id\"\n />\n }\n </ax-tabs>\n </axp-page-toolbar>\n }\n\n <axp-page-content class=\"axp-platform-explorer__page-content min-h-0 pt-0\">\n <!-- ----- Selected catalog node ----- -->\n @if (selectedNode(); as node) {\n <axp-platform-explorer-detail [node]=\"node\" />\n }\n <!-- ----- Empty selection ----- -->\n @else {\n <axp-state-message\n icon=\"fa-light fa-sitemap\"\n [title]=\"'@platform-dev-tools:module.messages.select-node'\"\n [description]=\"'@platform-dev-tools:module.messages.select-node-hint'\"\n />\n }\n </axp-page-content>\n</axp-page-layout>\n\n<ng-template #nodeTemplate let-node=\"node\">\n @let data = node['data'];\n @let treeNode = data?.treeNode;\n @let kind = treeNode?.kind;\n @let count = node['childrenCount'] ?? treeNode?.itemCount;\n <!-- ----- Manifest type group header ----- -->\n @if (kind === 'type-group') {\n <span\n class=\"axp-platform-explorer__node axp-platform-explorer__node--group\"\n [class.axp-platform-explorer__node--group-divided]=\"treeNode?.divided\"\n >\n <!--->\n <!-- ----- Divider after the previous type group ----- -->\n @if (treeNode?.divided) {\n <span class=\"axp-platform-explorer__group-rule\" aria-hidden=\"true\"></span>\n }\n <span class=\"axp-platform-explorer__group-title\">{{ node['title'] | translate | async }}</span>\n </span>\n }\n <!-- ----- Catalog node ----- -->\n @else {\n <span class=\"axp-platform-explorer__node\">\n @switch (kind) {\n @case ('module') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--module\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-cube'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('entities') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entities fa-light fa-table\" aria-hidden=\"true\"></i>\n }\n @case ('diagram') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--diagram fa-light fa-diagram-project\" aria-hidden=\"true\"></i>\n }\n @case ('entity') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--entity\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-table'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('commands') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--commands fa-light fa-terminal\" aria-hidden=\"true\"></i>\n }\n @case ('command') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--command\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-play'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('queries') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--queries fa-light fa-database\" aria-hidden=\"true\"></i>\n }\n @case ('query') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--query\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-magnifying-glass'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('plugins') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--plugins fa-light fa-puzzle-piece\" aria-hidden=\"true\"></i>\n }\n @case ('plugin') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--plugin\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-plug'\"\n aria-hidden=\"true\"\n ></i>\n }\n @case ('widgets') {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--widgets fa-light fa-cubes\" aria-hidden=\"true\"></i>\n }\n @case ('widget') {\n <i\n class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--widget\"\n [ngClass]=\"treeNode?.icon || 'fa-light fa-cube'\"\n aria-hidden=\"true\"\n ></i>\n }\n @default {\n <i class=\"axp-platform-explorer__node-icon axp-platform-explorer__node-icon--default fa-light fa-circle-dot\" aria-hidden=\"true\"></i>\n }\n }\n <span class=\"axp-platform-explorer__node-label\">{{ node['title'] | translate | async }}</span>\n <!--->\n <!-- ----- Child count badge when the folder has items ----- -->\n @if (count != null && count > 0) {\n <span class=\"axp-platform-explorer__node-badge\">{{ count }}</span>\n }\n </span>\n }\n</ng-template>\n", styles: ["@layer properties;.axp-platform-explorer axp-layout-container{overflow:hidden}.axp-platform-explorer__page-content{display:flex;min-height:0px;flex:1;flex-direction:column;overflow:hidden}axp-platform-explorer-detail,axp-platform-explorer-entity-detail{display:flex;height:100%;min-height:0px;flex:1;flex-direction:column;overflow:hidden}.axp-platform-explorer__tree-wrap{display:flex;min-height:0px;width:100%;min-width:0px;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2);overflow-x:hidden;overflow-y:auto;padding:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 3);max-height:calc(100vh - 180px)}.axp-platform-explorer__start-side{position:relative;height:100%;flex-shrink:0;overflow:visible}.axp-platform-explorer #axp-drawer-start{overflow:visible}.axp-platform-explorer__search{flex-shrink:0}.axp-platform-explorer__loading{display:flex;flex:1;align-items:center;justify-content:center;padding:calc(var(--spacing, .25rem) * 6)}.axp-platform-explorer__node{display:flex;width:100%;min-width:0px;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__node--group{pointer-events:none;width:100%;min-width:0px;flex-direction:column;align-items:stretch;gap:calc(var(--spacing, .25rem) * 1.5)}.axp-platform-explorer__node--group-divided{margin-top:var(--spacing, .25rem);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-platform-explorer__group-rule{display:block;width:100%;border-top-style:var(--tw-border-style);border-top-width:1px;border-color:rgba(var(--ax-sys-color-light-surface))}.axp-platform-explorer__group-title{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-platform-explorer__group-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group){pointer-events:none;cursor:default;background:transparent!important;min-height:0!important;padding-block:.25rem;padding-inline-start:0!important}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group) .ax-tree-view-node-content{padding-inline-start:0!important;margin-inline-start:0!important}.axp-platform-explorer__tree-wrap .ax-tree-view-node:has(.axp-platform-explorer__node--group) .ax-tree-view-expand-toggle{display:none!important;width:0!important;min-width:0!important;margin:0!important;padding:0!important}.axp-platform-explorer__node-icon{width:1em;flex-shrink:0;text-align:center}.axp-platform-explorer__node-icon--module{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__node-icon--diagram,.axp-platform-explorer__node-icon--entities,.axp-platform-explorer__node-icon--entity{color:rgba(var(--ax-sys-color-accent1-surface))}.axp-platform-explorer__node-icon--commands,.axp-platform-explorer__node-icon--command{color:rgba(var(--ax-sys-color-success-surface))}.axp-platform-explorer__node-icon--queries,.axp-platform-explorer__node-icon--query{color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__node-icon--plugins,.axp-platform-explorer__node-icon--plugin{color:rgba(var(--ax-sys-color-warning-surface))}.axp-platform-explorer__node-icon--widgets,.axp-platform-explorer__node-icon--widget,.axp-platform-explorer__node-icon--default{color:var(--color-neutral-500, oklch(55.6% 0 none))}.axp-platform-explorer__node-label{min-width:0px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-platform-explorer__node-badge{margin-left:auto;min-width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;border-radius:calc(infinity * 1px);padding-inline:calc(var(--spacing, .25rem) * 1.5);text-align:center;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}.axp-platform-explorer__entity-toolbar{width:100%}.axp-platform-explorer__entity-tabs{width:100%;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600)}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid;--tw-font-weight: initial;--tw-tracking: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
861
2551
|
}], ctorParameters: () => [], propDecorators: { tree: [{ type: i0.ViewChild, args: ['tree', { isSignal: true }] }] } });
|
|
862
2552
|
|
|
863
|
-
//#region
|
|
2553
|
+
//#region ----- Imports -----
|
|
864
2554
|
//#endregion
|
|
865
|
-
//#region
|
|
866
|
-
class
|
|
2555
|
+
//#region ----- Component -----
|
|
2556
|
+
class AXPlatformExplorerListDetailComponent {
|
|
867
2557
|
constructor() {
|
|
868
|
-
this.
|
|
869
|
-
...(ngDevMode ? [{ debugName: "
|
|
870
|
-
this.
|
|
871
|
-
...(ngDevMode ? [{ debugName: "
|
|
872
|
-
this.
|
|
873
|
-
this.
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
}
|
|
894
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerTreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
895
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerTreeNodeComponent, isStandalone: true, selector: "axp-platform-explorer-tree-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeSelect: "nodeSelect" }, ngImport: i0, template: `
|
|
896
|
-
<div class="axp-tree-node" [class.axp-tree-node--selected]="isSelected()">
|
|
897
|
-
<button
|
|
898
|
-
type="button"
|
|
899
|
-
class="axp-tree-node__toggler"
|
|
900
|
-
[class.axp-tree-node__toggler--open]="expanded()"
|
|
901
|
-
[attr.aria-expanded]="expanded()"
|
|
902
|
-
(click)="toggle()"
|
|
903
|
-
>
|
|
904
|
-
@if (hasChildren()) {
|
|
905
|
-
<span class="axp-tree-node__icon" aria-hidden="true">{{ expanded() ? '▼' : '▶' }}</span>
|
|
906
|
-
} @else {
|
|
907
|
-
<span class="axp-tree-node__icon axp-tree-node__icon--empty"></span>
|
|
908
|
-
}
|
|
909
|
-
</button>
|
|
910
|
-
<button
|
|
911
|
-
type="button"
|
|
912
|
-
class="axp-tree-node__label"
|
|
913
|
-
(click)="select()"
|
|
914
|
-
>
|
|
915
|
-
{{ node().label }}
|
|
916
|
-
@if (childrenLength() > 0) {
|
|
917
|
-
<span class="axp-tree-node__badge">({{ childrenLength() }})</span>
|
|
2558
|
+
this.moduleName = input.required(/* @ts-ignore */
|
|
2559
|
+
...(ngDevMode ? [{ debugName: "moduleName" }] : /* istanbul ignore next */ []));
|
|
2560
|
+
this.kind = input.required(/* @ts-ignore */
|
|
2561
|
+
...(ngDevMode ? [{ debugName: "kind" }] : /* istanbul ignore next */ []));
|
|
2562
|
+
this.dataService = inject(PlatformExplorerDataService);
|
|
2563
|
+
this.dataSource = new AXDataSource({
|
|
2564
|
+
key: 'name',
|
|
2565
|
+
pageSize: 20,
|
|
2566
|
+
load: async (e) => {
|
|
2567
|
+
const rows = await this.loadRows();
|
|
2568
|
+
const skip = e?.skip ?? 0;
|
|
2569
|
+
const take = e?.take ?? 20;
|
|
2570
|
+
return { items: rows.slice(skip, skip + take), total: rows.length };
|
|
2571
|
+
},
|
|
2572
|
+
});
|
|
2573
|
+
effect(() => {
|
|
2574
|
+
this.moduleName();
|
|
2575
|
+
this.kind();
|
|
2576
|
+
this.dataSource.refresh();
|
|
2577
|
+
});
|
|
2578
|
+
}
|
|
2579
|
+
async loadRows() {
|
|
2580
|
+
const catalog = await this.dataService.getModule(this.moduleName());
|
|
2581
|
+
if (!catalog) {
|
|
2582
|
+
return [];
|
|
918
2583
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
2584
|
+
switch (this.kind()) {
|
|
2585
|
+
case 'entities':
|
|
2586
|
+
return catalog.entities.map((item) => ({
|
|
2587
|
+
name: item.name,
|
|
2588
|
+
title: item.title ?? item.name,
|
|
2589
|
+
module: item.module,
|
|
2590
|
+
}));
|
|
2591
|
+
case 'commands':
|
|
2592
|
+
return catalog.commands;
|
|
2593
|
+
case 'queries':
|
|
2594
|
+
return catalog.queries;
|
|
2595
|
+
case 'plugins':
|
|
2596
|
+
return catalog.plugins;
|
|
2597
|
+
case 'widgets':
|
|
2598
|
+
return catalog.widgets;
|
|
2599
|
+
default:
|
|
2600
|
+
return [];
|
|
929
2601
|
}
|
|
930
|
-
</div>
|
|
931
2602
|
}
|
|
932
|
-
|
|
2603
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerListDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2604
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPlatformExplorerListDetailComponent, isStandalone: true, selector: "axp-platform-explorer-list-detail", inputs: { moduleName: { classPropertyName: "moduleName", publicName: "moduleName", isSignal: true, isRequired: true, transformFunction: null }, kind: { classPropertyName: "kind", publicName: "kind", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "flex flex-col flex-1 min-h-0" }, ngImport: i0, template: `
|
|
2605
|
+
<div class="flex flex-1 min-h-0 p-3 overflow-auto">
|
|
2606
|
+
<ax-data-table
|
|
2607
|
+
class="flex-1 border border-lightest rounded-md overflow-hidden"
|
|
2608
|
+
[paging]="true"
|
|
2609
|
+
[dataSource]="dataSource"
|
|
2610
|
+
>
|
|
2611
|
+
<ax-text-column [dataField]="'name'" [caption]="'@platform-dev-tools:module.terms.name' | translate | async" [width]="'280px'" [allowResizing]="true"></ax-text-column>
|
|
2612
|
+
<ax-text-column [dataField]="'title'" [caption]="'@platform-dev-tools:module.terms.title' | translate | async" [cellTemplate]="titleTpl" [width]="'280px'" [allowResizing]="true"></ax-text-column>
|
|
2613
|
+
<ax-text-column [dataField]="'description'" [caption]="'@platform-dev-tools:module.terms.description' | translate | async" [cellTemplate]="descTpl" [allowResizing]="true"></ax-text-column>
|
|
2614
|
+
</ax-data-table>
|
|
2615
|
+
</div>
|
|
2616
|
+
<ng-template #titleTpl let-item>
|
|
2617
|
+
@if (item.data?.title) {
|
|
2618
|
+
{{ item.data.title | translate | async }}
|
|
2619
|
+
}
|
|
2620
|
+
@else {
|
|
2621
|
+
–
|
|
2622
|
+
}
|
|
2623
|
+
</ng-template>
|
|
2624
|
+
<ng-template #descTpl let-item>
|
|
2625
|
+
@if (item.data?.description) {
|
|
2626
|
+
{{ item.data.description | translate | async }}
|
|
2627
|
+
}
|
|
2628
|
+
@else {
|
|
2629
|
+
–
|
|
2630
|
+
}
|
|
2631
|
+
</ng-template>
|
|
2632
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i1$1.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "hasChildrenField", "rowDetailsTemplate", "rowCssClass", "cellCssClass", "highlightText", "look", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i1$1.AXDataTableTextColumnComponent, selector: "ax-text-column", inputs: ["width", "caption", "allowSorting", "allowResizing", "fixed", "hasTitle", "customExpandIcon", "customCollapseIcon", "dataField", "expandHandler", "wrapText", "translate", "cellTemplate", "footerTemplate", "headerTemplate", "format", "formatOptions"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
933
2633
|
}
|
|
934
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type:
|
|
2634
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPlatformExplorerListDetailComponent, decorators: [{
|
|
935
2635
|
type: Component,
|
|
936
|
-
args: [{
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
</button>
|
|
951
|
-
<button
|
|
952
|
-
type="button"
|
|
953
|
-
class="axp-tree-node__label"
|
|
954
|
-
(click)="select()"
|
|
2636
|
+
args: [{
|
|
2637
|
+
selector: 'axp-platform-explorer-list-detail',
|
|
2638
|
+
standalone: true,
|
|
2639
|
+
encapsulation: ViewEncapsulation.None,
|
|
2640
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2641
|
+
host: { class: 'flex flex-col flex-1 min-h-0' },
|
|
2642
|
+
imports: [CommonModule, AXDataTableModule, AXTranslationModule],
|
|
2643
|
+
template: `
|
|
2644
|
+
<div class="flex flex-1 min-h-0 p-3 overflow-auto">
|
|
2645
|
+
<ax-data-table
|
|
2646
|
+
class="flex-1 border border-lightest rounded-md overflow-hidden"
|
|
2647
|
+
[paging]="true"
|
|
2648
|
+
[dataSource]="dataSource"
|
|
955
2649
|
>
|
|
956
|
-
|
|
957
|
-
@
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
</button>
|
|
2650
|
+
<ax-text-column [dataField]="'name'" [caption]="'@platform-dev-tools:module.terms.name' | translate | async" [width]="'280px'" [allowResizing]="true"></ax-text-column>
|
|
2651
|
+
<ax-text-column [dataField]="'title'" [caption]="'@platform-dev-tools:module.terms.title' | translate | async" [cellTemplate]="titleTpl" [width]="'280px'" [allowResizing]="true"></ax-text-column>
|
|
2652
|
+
<ax-text-column [dataField]="'description'" [caption]="'@platform-dev-tools:module.terms.description' | translate | async" [cellTemplate]="descTpl" [allowResizing]="true"></ax-text-column>
|
|
2653
|
+
</ax-data-table>
|
|
961
2654
|
</div>
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
2655
|
+
<ng-template #titleTpl let-item>
|
|
2656
|
+
@if (item.data?.title) {
|
|
2657
|
+
{{ item.data.title | translate | async }}
|
|
2658
|
+
}
|
|
2659
|
+
@else {
|
|
2660
|
+
–
|
|
2661
|
+
}
|
|
2662
|
+
</ng-template>
|
|
2663
|
+
<ng-template #descTpl let-item>
|
|
2664
|
+
@if (item.data?.description) {
|
|
2665
|
+
{{ item.data.description | translate | async }}
|
|
2666
|
+
}
|
|
2667
|
+
@else {
|
|
2668
|
+
–
|
|
2669
|
+
}
|
|
2670
|
+
</ng-template>
|
|
2671
|
+
`,
|
|
2672
|
+
}]
|
|
2673
|
+
}], ctorParameters: () => [], propDecorators: { moduleName: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleName", required: true }] }], kind: [{ type: i0.Input, args: [{ isSignal: true, alias: "kind", required: true }] }] } });
|
|
975
2674
|
|
|
976
2675
|
//#region ---- Imports ----
|
|
977
2676
|
//#endregion
|
|
@@ -999,11 +2698,6 @@ class AXMPlatformDevToolsModule {
|
|
|
999
2698
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMPlatformDevToolsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1000
2699
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMPlatformDevToolsModule }); }
|
|
1001
2700
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMPlatformDevToolsModule, providers: [
|
|
1002
|
-
{
|
|
1003
|
-
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
1004
|
-
useValue: PlatformDevToolsManifest,
|
|
1005
|
-
multi: true,
|
|
1006
|
-
},
|
|
1007
2701
|
{
|
|
1008
2702
|
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
1009
2703
|
useClass: AXMPermissionDefinitionProvider,
|
|
@@ -1029,11 +2723,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1029
2723
|
exports: [],
|
|
1030
2724
|
declarations: [],
|
|
1031
2725
|
providers: [
|
|
1032
|
-
{
|
|
1033
|
-
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
1034
|
-
useValue: PlatformDevToolsManifest,
|
|
1035
|
-
multi: true,
|
|
1036
|
-
},
|
|
1037
2726
|
{
|
|
1038
2727
|
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
1039
2728
|
useClass: AXMPermissionDefinitionProvider,
|
|
@@ -1058,5 +2747,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1058
2747
|
* Generated bundle index. Do not edit.
|
|
1059
2748
|
*/
|
|
1060
2749
|
|
|
1061
|
-
export { AXMPermissionDefinitionProvider, AXMPlatformDevToolsModule, AXPlatformExplorerDetailComponent, AXPlatformExplorerEntityDetailComponent,
|
|
2750
|
+
export { AXMPermissionDefinitionProvider, AXMPlatformDevToolsModule, AXPlatformExplorerCatalogDetailComponent, AXPlatformExplorerDetailComponent, AXPlatformExplorerEntitiesGraphComponent, AXPlatformExplorerEntityDetailComponent, AXPlatformExplorerListDetailComponent, AXPlatformExplorerModuleDetailComponent, AXPlatformExplorerPageComponent, PlatformExplorerDataService };
|
|
1062
2751
|
//# sourceMappingURL=acorex-platform-module-platform-dev-tools-client.mjs.map
|