biz-a-cli 2.3.80-15224 → 2.3.80-15227
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/bin/hubEvent.js
CHANGED
|
@@ -298,6 +298,7 @@ const EngineRegistry = {
|
|
|
298
298
|
"bpm/workflowRT": () => import("../engine/bpm/workflow-runtime.js"),
|
|
299
299
|
"domain/system": () => import("../engine/domain/system.js"),
|
|
300
300
|
"domain/appConfig": () => import("../engine/domain/appConfig.js"),
|
|
301
|
+
"domain/applicationConfig": () => import("../engine/domain/applicationConfig.js"),
|
|
301
302
|
};
|
|
302
303
|
|
|
303
304
|
const handleCliCommand = async (data, cb, argv) => {
|
|
@@ -2175,7 +2175,7 @@ const syncTable = async (table, ctx) => {
|
|
|
2175
2175
|
return executeSqlStatements(syncPlan.statements, tableDbIndex, ctx.config, ctx);
|
|
2176
2176
|
};
|
|
2177
2177
|
|
|
2178
|
-
const resolveConfigFromPayload = (payload = {}, argv = {}) => {
|
|
2178
|
+
export const resolveConfigFromPayload = (payload = {}, argv = {}) => {
|
|
2179
2179
|
const resolvedDbIndex = toNonNegativeInteger(payload.dbIndex) ?? toNonNegativeInteger(argv.dbindex) ?? 2;
|
|
2180
2180
|
return {
|
|
2181
2181
|
dbindex: resolvedDbIndex,
|
|
@@ -2189,12 +2189,12 @@ const resolveConfigFromPayload = (payload = {}, argv = {}) => {
|
|
|
2189
2189
|
};
|
|
2190
2190
|
};
|
|
2191
2191
|
|
|
2192
|
-
const buildPublishStatusConfigKey = (domainName, domainVersion) => ({
|
|
2192
|
+
export const buildPublishStatusConfigKey = (domainName, domainVersion) => ({
|
|
2193
2193
|
name: `${domainName}__PUBLISH_STATUS`,
|
|
2194
2194
|
version: domainVersion,
|
|
2195
2195
|
});
|
|
2196
2196
|
|
|
2197
|
-
const writePublishStatus = async (name, version, statusPayload, config) => {
|
|
2197
|
+
export const writePublishStatus = async (name, version, statusPayload, config) => {
|
|
2198
2198
|
const upsertSql = getUpsertBlock(name, version, JSON.stringify(statusPayload));
|
|
2199
2199
|
await executeBlock(upsertSql, config);
|
|
2200
2200
|
};
|
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
import { queryData } from "../../db/db.js";
|
|
2
|
+
import { publishApp } from "./system.js";
|
|
3
|
+
import {
|
|
4
|
+
getConfigByNameVersionParameters,
|
|
5
|
+
resolveConfigFromPayload,
|
|
6
|
+
buildPublishStatusConfigKey,
|
|
7
|
+
writePublishStatus,
|
|
8
|
+
} from "./appConfig.js";
|
|
9
|
+
|
|
10
|
+
export const parseConfigData = (rawConfig) => {
|
|
11
|
+
if (rawConfig == null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (typeof rawConfig === "object") {
|
|
15
|
+
return rawConfig;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const rawText = String(rawConfig).trim();
|
|
19
|
+
if (!rawText) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(rawText);
|
|
25
|
+
} catch {
|
|
26
|
+
try {
|
|
27
|
+
return Function(`${rawText}; return (typeof get === 'function') ? get() : null;`)();
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const normalizeMenuNode = (menu) => {
|
|
35
|
+
const caption = typeof menu?.caption === "string" ? menu.caption : typeof menu?.label === "string" ? menu.label : "";
|
|
36
|
+
const rawRoute = typeof menu?.route === "string" ? menu.route.trim().toLowerCase() : "";
|
|
37
|
+
const entryPoint = typeof menu?.entryPoint === "string" && menu.entryPoint.trim().length > 0 ? menu.entryPoint.trim() : null;
|
|
38
|
+
|
|
39
|
+
const inferredLink =
|
|
40
|
+
rawRoute.endsWith("/form") || entryPoint
|
|
41
|
+
? ["./form", entryPoint ?? null, null]
|
|
42
|
+
: rawRoute.endsWith("/list")
|
|
43
|
+
? typeof menu?.id === "string" && menu.id.trim().length > 0
|
|
44
|
+
? ["./list", menu.id.trim()]
|
|
45
|
+
: ["./list"]
|
|
46
|
+
: [];
|
|
47
|
+
|
|
48
|
+
const sourceChildren = Array.isArray(menu?.subMenu) ? menu.subMenu : Array.isArray(menu?.menus) ? menu.menus : [];
|
|
49
|
+
const normalizedChildren = sourceChildren
|
|
50
|
+
.map((child) => normalizeMenuNode(child))
|
|
51
|
+
.filter(
|
|
52
|
+
(child) =>
|
|
53
|
+
String(child?.caption ?? "").trim().length > 0 ||
|
|
54
|
+
(Array.isArray(child?.link) && child.link.length > 0) ||
|
|
55
|
+
(Array.isArray(child?.subMenu) && child.subMenu.length > 0),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
menuName: typeof menu?.menuName === "string" ? menu.menuName : "",
|
|
60
|
+
caption,
|
|
61
|
+
link: Array.isArray(menu?.link) ? menu.link : inferredLink,
|
|
62
|
+
subMenu: normalizedChildren,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const buildMenuStructureFromApplicationConfig = (parsedApplicationConfig) => {
|
|
67
|
+
const sourceMenus = Array.isArray(parsedApplicationConfig?.navigation?.menus) ? parsedApplicationConfig.navigation.menus : [];
|
|
68
|
+
|
|
69
|
+
const normalizedMenus = sourceMenus
|
|
70
|
+
.map((menu) => normalizeMenuNode(menu))
|
|
71
|
+
.filter(
|
|
72
|
+
(menu) =>
|
|
73
|
+
String(menu?.caption ?? "").trim().length > 0 ||
|
|
74
|
+
(Array.isArray(menu?.link) && menu.link.length > 0) ||
|
|
75
|
+
(Array.isArray(menu?.subMenu) && menu.subMenu.length > 0),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const nonHomeMenus = normalizedMenus.filter(
|
|
79
|
+
(menu) => !(menu?.caption === "Home" || (Array.isArray(menu?.link) && menu.link[0] === "./main")),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return [{ menuName: "", caption: "Home", link: ["./main"], subMenu: [] }].concat(nonHomeMenus);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const normalizeTemplateFileName = (rawName) => {
|
|
86
|
+
const normalized = String(rawName ?? "")
|
|
87
|
+
.trim()
|
|
88
|
+
.toLowerCase()
|
|
89
|
+
.replace(/\s+/g, "");
|
|
90
|
+
return normalized.endsWith(".js") ? normalized : `${normalized}.js`;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const collectFormTargets = (menuNode, inheritedDomainKey = null) => {
|
|
94
|
+
const targets = [];
|
|
95
|
+
const currentDomainKey =
|
|
96
|
+
typeof menuNode?.domain === "string" && menuNode.domain.trim().length > 0 ? menuNode.domain.trim() : inheritedDomainKey;
|
|
97
|
+
const explicitEntryPoint =
|
|
98
|
+
typeof menuNode?.entryPoint === "string" && menuNode.entryPoint.trim().length > 0 ? menuNode.entryPoint.trim() : null;
|
|
99
|
+
const menuLink = Array.isArray(menuNode?.link) ? menuNode.link : [];
|
|
100
|
+
const normalizedLinkTarget = String(menuLink?.[0] ?? "").trim().toLowerCase();
|
|
101
|
+
const linkedTemplateType =
|
|
102
|
+
normalizedLinkTarget === "./list" ? "list" : ["./form", "./main"].includes(normalizedLinkTarget) ? "form" : null;
|
|
103
|
+
const fallbackLinkedEntryPoint = normalizedLinkTarget === "./main" ? "main" : null;
|
|
104
|
+
const linkedEntryPoint = linkedTemplateType
|
|
105
|
+
? typeof menuLink?.[1] === "string" && menuLink[1].trim().length > 0
|
|
106
|
+
? menuLink[1].trim()
|
|
107
|
+
: fallbackLinkedEntryPoint
|
|
108
|
+
: null;
|
|
109
|
+
const resolvedEntryPoint = linkedEntryPoint ?? explicitEntryPoint;
|
|
110
|
+
if (resolvedEntryPoint) {
|
|
111
|
+
targets.push({
|
|
112
|
+
entryPointName: resolvedEntryPoint,
|
|
113
|
+
domainKey: currentDomainKey,
|
|
114
|
+
templateType: linkedTemplateType ?? "form",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const children = Array.isArray(menuNode?.menus) ? menuNode.menus : Array.isArray(menuNode?.subMenu) ? menuNode.subMenu : [];
|
|
119
|
+
for (const child of children) {
|
|
120
|
+
targets.push(...collectFormTargets(child, currentDomainKey));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return targets;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const resolveDomainKeyByReference = (domainReference, domainMap) => {
|
|
127
|
+
const rawReference = String(domainReference ?? "").trim();
|
|
128
|
+
if (!rawReference) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const domainKeys = Object.keys(domainMap ?? {});
|
|
132
|
+
if (domainKeys.length === 0) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (Object.prototype.hasOwnProperty.call(domainMap, rawReference)) {
|
|
137
|
+
return rawReference;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const normalizedReference = rawReference.toLowerCase();
|
|
141
|
+
const caseInsensitiveKeyMatch =
|
|
142
|
+
domainKeys.find((key) => String(key ?? "").trim().toLowerCase() === normalizedReference) ?? null;
|
|
143
|
+
if (caseInsensitiveKeyMatch) {
|
|
144
|
+
return caseInsensitiveKeyMatch;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const key of domainKeys) {
|
|
148
|
+
const domainDef = domainMap?.[key];
|
|
149
|
+
const source = String(domainDef?.source ?? "").trim();
|
|
150
|
+
const sourceName = String(source.split("@")[0] ?? "").trim();
|
|
151
|
+
const alias = String(domainDef?.alias ?? "").trim();
|
|
152
|
+
if (source && source.toLowerCase() === normalizedReference) {
|
|
153
|
+
return key;
|
|
154
|
+
}
|
|
155
|
+
if (sourceName && sourceName.toLowerCase() === normalizedReference) {
|
|
156
|
+
return key;
|
|
157
|
+
}
|
|
158
|
+
if (alias && alias.toLowerCase() === normalizedReference) {
|
|
159
|
+
return key;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const resolveTemplateTargets = (parsedDomainConfig, parsedApplicationConfig) => {
|
|
167
|
+
const sourceMenus = Array.isArray(parsedApplicationConfig?.navigation?.menus) ? parsedApplicationConfig.navigation.menus : [];
|
|
168
|
+
const resolvedTargets = [];
|
|
169
|
+
const seenFileNames = new Set();
|
|
170
|
+
|
|
171
|
+
for (const menuNode of sourceMenus) {
|
|
172
|
+
const menuTargets = collectFormTargets(menuNode);
|
|
173
|
+
for (const menuTarget of menuTargets) {
|
|
174
|
+
const entryPointName = String(menuTarget.entryPointName ?? "").trim();
|
|
175
|
+
if (!entryPointName) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const fileName = normalizeTemplateFileName(entryPointName);
|
|
179
|
+
if (seenFileNames.has(fileName)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
seenFileNames.add(fileName);
|
|
183
|
+
resolvedTargets.push({
|
|
184
|
+
fileName,
|
|
185
|
+
entryPointName,
|
|
186
|
+
domainKey: menuTarget.domainKey ?? null,
|
|
187
|
+
templateType: menuTarget.templateType ?? "form",
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const structures = parsedDomainConfig?.ui?.structures;
|
|
193
|
+
const entryPoints = parsedDomainConfig?.ui?.entryPoints;
|
|
194
|
+
const structureKeys =
|
|
195
|
+
structures && typeof structures === "object" ? Object.keys(structures).filter((key) => String(key ?? "").trim().length > 0) : [];
|
|
196
|
+
const entryPointKeys =
|
|
197
|
+
entryPoints && typeof entryPoints === "object" ? Object.keys(entryPoints).filter((key) => String(key ?? "").trim().length > 0) : [];
|
|
198
|
+
for (const entryPointName of entryPointKeys) {
|
|
199
|
+
const fileName = normalizeTemplateFileName(entryPointName);
|
|
200
|
+
if (seenFileNames.has(fileName)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const resolvedStructureRef = String(entryPoints?.[entryPointName]?.structureRef ?? "").trim() || entryPointName;
|
|
204
|
+
const resolvedStructure = structures?.[resolvedStructureRef];
|
|
205
|
+
seenFileNames.add(fileName);
|
|
206
|
+
resolvedTargets.push({
|
|
207
|
+
fileName,
|
|
208
|
+
entryPointName,
|
|
209
|
+
domainKey: null,
|
|
210
|
+
templateType: String(resolvedStructure?.type ?? "").trim().toLowerCase() === "list" ? "list" : "form",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (resolvedTargets.length > 0) {
|
|
214
|
+
return resolvedTargets;
|
|
215
|
+
}
|
|
216
|
+
const entryPointName =
|
|
217
|
+
entryPointKeys.length > 0 ? String(entryPointKeys[0]) : structureKeys.length > 0 ? String(structureKeys[0]) : "appForm";
|
|
218
|
+
const resolvedStructureRef = String(entryPoints?.[entryPointName]?.structureRef ?? "").trim() || entryPointName;
|
|
219
|
+
const resolvedStructure = structures?.[resolvedStructureRef];
|
|
220
|
+
return [
|
|
221
|
+
{
|
|
222
|
+
fileName: normalizeTemplateFileName(entryPointName),
|
|
223
|
+
entryPointName,
|
|
224
|
+
domainKey: null,
|
|
225
|
+
templateType: String(resolvedStructure?.type ?? "").trim().toLowerCase() === "list" ? "list" : "form",
|
|
226
|
+
},
|
|
227
|
+
];
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const buildTemplateDomainConfigResolverSnippet = () => {
|
|
231
|
+
return `const ensureDomainConfig = (onResolved) => {
|
|
232
|
+
const callback = typeof onResolved === "function" ? onResolved : function () {};
|
|
233
|
+
const configuredSource = String("__DOMAIN_SOURCE__").trim();
|
|
234
|
+
const domainCacheKey = configuredSource || "__default__";
|
|
235
|
+
if (!this._resolvedDomainConfigBySource || typeof this._resolvedDomainConfigBySource !== "object" || Array.isArray(this._resolvedDomainConfigBySource)) {
|
|
236
|
+
this._resolvedDomainConfigBySource = {};
|
|
237
|
+
}
|
|
238
|
+
if (!this._pendingDomainConfigCallbacksBySource || typeof this._pendingDomainConfigCallbacksBySource !== "object" || Array.isArray(this._pendingDomainConfigCallbacksBySource)) {
|
|
239
|
+
this._pendingDomainConfigCallbacksBySource = {};
|
|
240
|
+
}
|
|
241
|
+
if (!this._isResolvingDomainConfigBySource || typeof this._isResolvingDomainConfigBySource !== "object" || Array.isArray(this._isResolvingDomainConfigBySource)) {
|
|
242
|
+
this._isResolvingDomainConfigBySource = {};
|
|
243
|
+
}
|
|
244
|
+
const cachedDomainConfig = this._resolvedDomainConfigBySource[domainCacheKey];
|
|
245
|
+
if (cachedDomainConfig) {
|
|
246
|
+
this.domainConfig = cachedDomainConfig;
|
|
247
|
+
callback(this.domainConfig);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (!Array.isArray(this._pendingDomainConfigCallbacksBySource[domainCacheKey])) {
|
|
251
|
+
this._pendingDomainConfigCallbacksBySource[domainCacheKey] = [];
|
|
252
|
+
}
|
|
253
|
+
this._pendingDomainConfigCallbacksBySource[domainCacheKey].push(callback);
|
|
254
|
+
if (this._isResolvingDomainConfigBySource[domainCacheKey]) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
this._isResolvingDomainConfigBySource[domainCacheKey] = true;
|
|
258
|
+
const completeResolve = (resolvedConfig) => {
|
|
259
|
+
if (resolvedConfig) {
|
|
260
|
+
this._resolvedDomainConfigBySource[domainCacheKey] = resolvedConfig;
|
|
261
|
+
this.domainConfig = resolvedConfig;
|
|
262
|
+
}
|
|
263
|
+
const callbackConfig = resolvedConfig || this.domainConfig;
|
|
264
|
+
const queuedCallbacks = Array.isArray(this._pendingDomainConfigCallbacksBySource[domainCacheKey]) ? this._pendingDomainConfigCallbacksBySource[domainCacheKey].slice() : [];
|
|
265
|
+
delete this._pendingDomainConfigCallbacksBySource[domainCacheKey];
|
|
266
|
+
this._isResolvingDomainConfigBySource[domainCacheKey] = false;
|
|
267
|
+
for (let index = 0; index < queuedCallbacks.length; index += 1) {
|
|
268
|
+
try {
|
|
269
|
+
queuedCallbacks[index](callbackConfig);
|
|
270
|
+
} catch {}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
const parseConfigData = (rawConfig) => {
|
|
274
|
+
if (rawConfig == null) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
if (typeof rawConfig === "object") {
|
|
278
|
+
if (rawConfig.metadata && rawConfig.model && rawConfig.ui) {
|
|
279
|
+
return rawConfig;
|
|
280
|
+
}
|
|
281
|
+
if (rawConfig.data != null) {
|
|
282
|
+
return parseConfigData(rawConfig.data);
|
|
283
|
+
}
|
|
284
|
+
return rawConfig;
|
|
285
|
+
}
|
|
286
|
+
const rawText = String(rawConfig).trim();
|
|
287
|
+
if (!rawText) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
return JSON.parse(rawText);
|
|
292
|
+
} catch {
|
|
293
|
+
try {
|
|
294
|
+
return Function(rawText + "; return (typeof get === 'function') ? get() : null;")();
|
|
295
|
+
} catch {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const apiConfig = this._configApi != null ? this._configApi : this.config && this.config.api ? this.config.api : null;
|
|
301
|
+
this._configApi = apiConfig;
|
|
302
|
+
const queryDomainConfig = (domainName, domainVersion) => {
|
|
303
|
+
if (!domainName || !domainVersion) {
|
|
304
|
+
completeResolve(this.domainConfig);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const domainQuery = {
|
|
308
|
+
start: 0,
|
|
309
|
+
length: 1,
|
|
310
|
+
order: [],
|
|
311
|
+
filter: [
|
|
312
|
+
{ junction: "", column: "NAME", operator: "=", value1: "'" + domainName.replace(/'/g, "''") + "'" },
|
|
313
|
+
{ junction: "AND", column: "VERSION", operator: "=", value1: "'" + domainVersion.replace(/'/g, "''") + "'" },
|
|
314
|
+
],
|
|
315
|
+
columns: [
|
|
316
|
+
{ data: "SYS$CONFIG.ID", key: "id" },
|
|
317
|
+
{ data: "SYS$CONFIG.NAME", key: "name" },
|
|
318
|
+
{ data: "SYS$CONFIG.VERSION", key: "version" },
|
|
319
|
+
{ data: "SYS$CONFIG.DATA", key: "data" },
|
|
320
|
+
],
|
|
321
|
+
};
|
|
322
|
+
this.dataService.queryData(domainQuery, apiConfig, true, true).subscribe({
|
|
323
|
+
next: (domainRows) => {
|
|
324
|
+
const domainData = domainRows && domainRows[0] ? domainRows[0].data : null;
|
|
325
|
+
const domainConfig = parseConfigData(domainData);
|
|
326
|
+
completeResolve(domainConfig || this.domainConfig);
|
|
327
|
+
},
|
|
328
|
+
error: (error) => {
|
|
329
|
+
console.log("[AppConfig] Failed to query domain config:", error);
|
|
330
|
+
completeResolve(this.domainConfig);
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
if (configuredSource) {
|
|
335
|
+
const sourceParts = configuredSource.split("@");
|
|
336
|
+
const domainName = String(sourceParts[0] || "").trim();
|
|
337
|
+
const domainVersion = String(sourceParts[1] || "").trim();
|
|
338
|
+
queryDomainConfig(domainName, domainVersion);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const applicationQuery = {
|
|
342
|
+
start: 0,
|
|
343
|
+
length: 1,
|
|
344
|
+
order: [],
|
|
345
|
+
filter: [{ junction: "", column: "NAME", operator: "=", value1: "'APPLICATION_CONFIG'" }],
|
|
346
|
+
columns: [
|
|
347
|
+
{ data: "SYS$CONFIG.ID", key: "id" },
|
|
348
|
+
{ data: "SYS$CONFIG.NAME", key: "name" },
|
|
349
|
+
{ data: "SYS$CONFIG.VERSION", key: "version" },
|
|
350
|
+
{ data: "SYS$CONFIG.DATA", key: "data" },
|
|
351
|
+
],
|
|
352
|
+
};
|
|
353
|
+
this.dataService.queryData(applicationQuery, apiConfig, true, true).subscribe({
|
|
354
|
+
next: (applicationRows) => {
|
|
355
|
+
const applicationData = applicationRows && applicationRows[0] ? applicationRows[0].data : null;
|
|
356
|
+
const appConfig = parseConfigData(applicationData);
|
|
357
|
+
const domainDef = appConfig && appConfig.domains && appConfig.domains.salesOrderDomain ? appConfig.domains.salesOrderDomain : null;
|
|
358
|
+
const source = String(domainDef && domainDef.source ? domainDef.source : "").trim();
|
|
359
|
+
const sourceParts = source.split("@");
|
|
360
|
+
const domainName = String(sourceParts[0] || "").trim();
|
|
361
|
+
const domainVersion = String(sourceParts[1] || "").trim();
|
|
362
|
+
queryDomainConfig(domainName, domainVersion);
|
|
363
|
+
},
|
|
364
|
+
error: (error) => {
|
|
365
|
+
console.log("[AppConfig] Failed to query application config:", error);
|
|
366
|
+
completeResolve(this.domainConfig);
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
this._ensureDomainConfig = ensureDomainConfig;`;
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
export const buildHardcodedTemplateContent = (
|
|
374
|
+
entryPointName = "loginForm",
|
|
375
|
+
domainKey = null,
|
|
376
|
+
templateType = "form",
|
|
377
|
+
domainSource = null,
|
|
378
|
+
) => {
|
|
379
|
+
const sharedDomainConfigResolverScript = buildTemplateDomainConfigResolverSnippet();
|
|
380
|
+
const formTemplateContent = `get = function () {
|
|
381
|
+
return {
|
|
382
|
+
model: {},
|
|
383
|
+
tableName: "",
|
|
384
|
+
fields: [],
|
|
385
|
+
functions: {
|
|
386
|
+
beforeLoadData: function (id) {
|
|
387
|
+
${sharedDomainConfigResolverScript}
|
|
388
|
+
return new Promise((resolve) => {
|
|
389
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
390
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
391
|
+
console.log('Template Result :', this.domainConfig);
|
|
392
|
+
this.domainService.doBeforeLoadDataEvent({ config: this.domainConfig, entryPointName: "__ENTRY_POINT_NAME__", runtimeHost: this, id: String(id) });
|
|
393
|
+
resolve();
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
},
|
|
397
|
+
afterLoadData: function (id) {
|
|
398
|
+
const ensureDomainConfig =
|
|
399
|
+
typeof this._ensureDomainConfig === "function"
|
|
400
|
+
? this._ensureDomainConfig
|
|
401
|
+
: (onResolved) => {
|
|
402
|
+
const callback = typeof onResolved === "function" ? onResolved : function () {};
|
|
403
|
+
callback(this.domainConfig);
|
|
404
|
+
};
|
|
405
|
+
return new Promise((resolve) => {
|
|
406
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
407
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
408
|
+
this.domainService.doAfterLoadDataEvent({ config: this.domainConfig, entryPointName: "__ENTRY_POINT_NAME__", runtimeHost: this, id: String(id) });
|
|
409
|
+
resolve();
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
onInit: function (id) {
|
|
414
|
+
const ensureDomainConfig =
|
|
415
|
+
typeof this._ensureDomainConfig === "function"
|
|
416
|
+
? this._ensureDomainConfig
|
|
417
|
+
: (onResolved) => {
|
|
418
|
+
const callback = typeof onResolved === "function" ? onResolved : function () {};
|
|
419
|
+
callback(this.domainConfig);
|
|
420
|
+
};
|
|
421
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
422
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
423
|
+
if (!this.domainConfig) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const entryPointName = "__ENTRY_POINT_NAME__";
|
|
427
|
+
const uiProfile = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(max-width: 767px)").matches ? "mobile" : "desktop";
|
|
428
|
+
const result = this.domainService.domainInit({ config: this.domainConfig, entryPointName, runtimeHost: this, uiProfile, id });
|
|
429
|
+
console.log('Domain Init Result :', result);
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
onDestroy: function () {
|
|
433
|
+
this.domainService.domainDestroy(this);
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
};`;
|
|
438
|
+
const listTemplateContent = `get = function () {
|
|
439
|
+
return {
|
|
440
|
+
caption: "",
|
|
441
|
+
columns: [],
|
|
442
|
+
filter: [],
|
|
443
|
+
buttons: [],
|
|
444
|
+
distinct: false,
|
|
445
|
+
functions: {
|
|
446
|
+
beforeLoadData: function () {
|
|
447
|
+
${sharedDomainConfigResolverScript}
|
|
448
|
+
return new Promise((resolve) => {
|
|
449
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
450
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
451
|
+
console.log('Template Result :', this.domainConfig);
|
|
452
|
+
this.domainService.doBeforeLoadDataEvent({
|
|
453
|
+
config: this.domainConfig,
|
|
454
|
+
entryPointName: "__ENTRY_POINT_NAME__",
|
|
455
|
+
runtimeHost: this,
|
|
456
|
+
id: this.id,
|
|
457
|
+
ctx: this.contex,
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
if (this._listDomainInitialized !== true) {
|
|
461
|
+
const rendered = this.domainService.domainInit({
|
|
462
|
+
config: this.domainConfig,
|
|
463
|
+
entryPointName: "__ENTRY_POINT_NAME__",
|
|
464
|
+
runtimeHost: this,
|
|
465
|
+
uiProfile: "desktop",
|
|
466
|
+
});
|
|
467
|
+
console.log('Domain Init Result :', rendered);
|
|
468
|
+
|
|
469
|
+
this.caption = rendered.caption || "";
|
|
470
|
+
this.columns = rendered.columns || [];
|
|
471
|
+
this.buttons = rendered.buttons || [];
|
|
472
|
+
this.filter = rendered.filter || [];
|
|
473
|
+
this.distinct = !!rendered.distinct;
|
|
474
|
+
this.functions = Object.assign(this.functions || {}, rendered.functions || {});
|
|
475
|
+
if (this.helper && typeof this.helper.bindFunctionInObj === "function") {
|
|
476
|
+
this.helper.bindFunctionInObj(this.functions, this);
|
|
477
|
+
}
|
|
478
|
+
this._listDomainInitialized = true;
|
|
479
|
+
}
|
|
480
|
+
resolve();
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
},
|
|
484
|
+
onPipe: function () {
|
|
485
|
+
const ensureDomainConfig =
|
|
486
|
+
typeof this._ensureDomainConfig === "function"
|
|
487
|
+
? this._ensureDomainConfig
|
|
488
|
+
: (onResolved) => {
|
|
489
|
+
const callback = typeof onResolved === "function" ? onResolved : function () {};
|
|
490
|
+
callback(this.domainConfig);
|
|
491
|
+
};
|
|
492
|
+
const rows = Array.prototype.slice.call(arguments);
|
|
493
|
+
let result = rows;
|
|
494
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
495
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
496
|
+
const uiProfile = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(max-width: 767px)").matches ? "mobile" : "desktop";
|
|
497
|
+
result = this.domainService.domainPipe({
|
|
498
|
+
config: this.domainConfig,
|
|
499
|
+
entryPointName: "__ENTRY_POINT_NAME__",
|
|
500
|
+
runtimeHost: this,
|
|
501
|
+
uiProfile,
|
|
502
|
+
rows,
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
return result;
|
|
506
|
+
},
|
|
507
|
+
afterLoadData: function () {
|
|
508
|
+
const ensureDomainConfig =
|
|
509
|
+
typeof this._ensureDomainConfig === "function"
|
|
510
|
+
? this._ensureDomainConfig
|
|
511
|
+
: (onResolved) => {
|
|
512
|
+
const callback = typeof onResolved === "function" ? onResolved : function () {};
|
|
513
|
+
callback(this.domainConfig);
|
|
514
|
+
};
|
|
515
|
+
return new Promise((resolve) => {
|
|
516
|
+
ensureDomainConfig((resolvedConfig) => {
|
|
517
|
+
this.domainConfig = resolvedConfig || this.domainConfig;
|
|
518
|
+
this.domainService.doAfterLoadDataEvent({
|
|
519
|
+
config: this.domainConfig,
|
|
520
|
+
entryPointName: "__ENTRY_POINT_NAME__",
|
|
521
|
+
runtimeHost: this,
|
|
522
|
+
id: this.id,
|
|
523
|
+
ctx: this.contex,
|
|
524
|
+
});
|
|
525
|
+
resolve();
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
};`;
|
|
532
|
+
const templateContent = templateType === "list" ? listTemplateContent : formTemplateContent;
|
|
533
|
+
|
|
534
|
+
const safeEntryPointName = String(entryPointName ?? "").trim() || "loginForm";
|
|
535
|
+
const safeDomainKey = typeof domainKey === "string" && domainKey.trim().length > 0 ? domainKey.trim() : "";
|
|
536
|
+
const safeDomainSource = typeof domainSource === "string" && domainSource.trim().length > 0 ? domainSource.trim() : "";
|
|
537
|
+
const domainResolverExpression = `(() => { const domains = appConfig && appConfig.domains && typeof appConfig.domains === 'object' ? appConfig.domains : null; if (!domains) { return null; } const preferredDomainKey = ${JSON.stringify(safeDomainKey)}; if (preferredDomainKey && domains[preferredDomainKey]) { return domains[preferredDomainKey]; } if (domains.salesOrderDomain) { return domains.salesOrderDomain; } const domainKeys = Object.keys(domains); return domainKeys.length > 0 ? domains[domainKeys[0]] : null; })()`;
|
|
538
|
+
const resolvedTemplateContent = templateContent
|
|
539
|
+
.replace(/"__ENTRY_POINT_NAME__"/g, JSON.stringify(safeEntryPointName))
|
|
540
|
+
.replace(/"__DOMAIN_SOURCE__"/g, JSON.stringify(safeDomainSource))
|
|
541
|
+
.replace(
|
|
542
|
+
"appConfig && appConfig.domains && appConfig.domains.salesOrderDomain ? appConfig.domains.salesOrderDomain : null",
|
|
543
|
+
domainResolverExpression,
|
|
544
|
+
);
|
|
545
|
+
const sanitizedTemplateContent = resolvedTemplateContent.replace(/\n\t+/g, " ");
|
|
546
|
+
return JSON.parse(JSON.stringify(sanitizedTemplateContent));
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
export const buildPublishBodyFromConfigs = (parsedApplicationConfig, parsedDomainConfig, configuredDomainName) => {
|
|
550
|
+
const safeApplicationConfig = parsedApplicationConfig ?? {};
|
|
551
|
+
const safeDomainConfig = parsedDomainConfig ?? {};
|
|
552
|
+
|
|
553
|
+
const menuStructure = buildMenuStructureFromApplicationConfig(safeApplicationConfig);
|
|
554
|
+
const menuContent = JSON.stringify(menuStructure);
|
|
555
|
+
|
|
556
|
+
const templateTargets = resolveTemplateTargets(safeDomainConfig, safeApplicationConfig);
|
|
557
|
+
const domainMap =
|
|
558
|
+
safeApplicationConfig?.domains && typeof safeApplicationConfig.domains === "object" ? safeApplicationConfig.domains : {};
|
|
559
|
+
const domainKeys = Object.keys(domainMap).filter((key) => String(key ?? "").trim().length > 0);
|
|
560
|
+
const safeConfiguredDomainName = String(configuredDomainName ?? "").trim();
|
|
561
|
+
const configuredDomainKey = safeConfiguredDomainName
|
|
562
|
+
? (resolveDomainKeyByReference(safeConfiguredDomainName, domainMap) ??
|
|
563
|
+
domainKeys.find((key) => {
|
|
564
|
+
const source = String(domainMap?.[key]?.source ?? "").trim();
|
|
565
|
+
const sourceName = String(source.split("@")[0] ?? "").trim();
|
|
566
|
+
return sourceName === safeConfiguredDomainName;
|
|
567
|
+
}) ??
|
|
568
|
+
null)
|
|
569
|
+
: null;
|
|
570
|
+
const primaryDomainKey = domainKeys.find((key) => key === "salesOrderDomain") ?? (domainKeys.length > 0 ? domainKeys[0] : null);
|
|
571
|
+
const unresolvedDomainKeys = configuredDomainKey ? domainKeys.filter((key) => key !== configuredDomainKey) : domainKeys;
|
|
572
|
+
const configuredEntryPointNames = new Set(
|
|
573
|
+
[...Object.keys(safeDomainConfig?.ui?.entryPoints ?? {}), ...Object.keys(safeDomainConfig?.ui?.structures ?? {})].filter(
|
|
574
|
+
(name) => String(name ?? "").trim().length > 0,
|
|
575
|
+
),
|
|
576
|
+
);
|
|
577
|
+
let unresolvedTargetIndex = 0;
|
|
578
|
+
const templateFiles = templateTargets.map((target, targetIndex) => {
|
|
579
|
+
const explicitDomainReference = String(target.domainKey ?? "").trim();
|
|
580
|
+
let resolvedDomainKey = explicitDomainReference.length > 0 ? resolveDomainKeyByReference(explicitDomainReference, domainMap) : null;
|
|
581
|
+
if (explicitDomainReference.length > 0 && !resolvedDomainKey) {
|
|
582
|
+
throw new Error(`Cannot resolve menu domain "${explicitDomainReference}" for entry point "${target.entryPointName}".`);
|
|
583
|
+
}
|
|
584
|
+
if (!resolvedDomainKey) {
|
|
585
|
+
const isConfiguredEntryPoint = configuredEntryPointNames.has(target.entryPointName);
|
|
586
|
+
if (isConfiguredEntryPoint && configuredDomainKey) {
|
|
587
|
+
resolvedDomainKey = configuredDomainKey;
|
|
588
|
+
} else if (configuredDomainKey) {
|
|
589
|
+
resolvedDomainKey =
|
|
590
|
+
unresolvedDomainKeys.length > 0
|
|
591
|
+
? unresolvedDomainKeys[Math.min(unresolvedTargetIndex, unresolvedDomainKeys.length - 1)]
|
|
592
|
+
: configuredDomainKey;
|
|
593
|
+
unresolvedTargetIndex += 1;
|
|
594
|
+
} else {
|
|
595
|
+
resolvedDomainKey =
|
|
596
|
+
configuredEntryPointNames.has(target.entryPointName) && primaryDomainKey
|
|
597
|
+
? primaryDomainKey
|
|
598
|
+
: domainKeys.length > 0
|
|
599
|
+
? domainKeys[Math.min(targetIndex, domainKeys.length - 1)]
|
|
600
|
+
: null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const resolvedDomainSource =
|
|
604
|
+
resolvedDomainKey && domainMap && typeof domainMap === "object" ? String(domainMap?.[resolvedDomainKey]?.source ?? "").trim() : "";
|
|
605
|
+
return {
|
|
606
|
+
name: target.fileName,
|
|
607
|
+
content: buildHardcodedTemplateContent(target.entryPointName, resolvedDomainKey, target.templateType ?? "form", resolvedDomainSource),
|
|
608
|
+
};
|
|
609
|
+
});
|
|
610
|
+
const fileList = [{ name: "menu.json", content: menuContent }, ...templateFiles];
|
|
611
|
+
|
|
612
|
+
return { verbose: false, fileList };
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
export const publishApplicationConfig = async (payload = {}, argv = {}) => {
|
|
616
|
+
const applicationConfigName = String(payload?.applicationConfigName ?? "APPLICATION_CONFIG").trim() || "APPLICATION_CONFIG";
|
|
617
|
+
const applicationConfigVersion = String(payload?.applicationConfigVersion ?? "").trim();
|
|
618
|
+
if (!applicationConfigVersion) {
|
|
619
|
+
throw new Error("payload.applicationConfigVersion is required.");
|
|
620
|
+
}
|
|
621
|
+
const config = resolveConfigFromPayload(payload, argv);
|
|
622
|
+
|
|
623
|
+
const appRows = await queryData(getConfigByNameVersionParameters(applicationConfigName, applicationConfigVersion), config);
|
|
624
|
+
const appRow = appRows?.[0];
|
|
625
|
+
if (!appRow?.data) {
|
|
626
|
+
throw new Error(`SYS$CONFIG record ${applicationConfigName}@${applicationConfigVersion} was not found.`);
|
|
627
|
+
}
|
|
628
|
+
const parsedApplicationConfig = parseConfigData(appRow.data) ?? {};
|
|
629
|
+
|
|
630
|
+
const domainConfigName = String(payload?.domainConfigName ?? "").trim();
|
|
631
|
+
const domainConfigVersion = String(payload?.domainConfigVersion ?? "").trim();
|
|
632
|
+
let parsedDomainConfig = {};
|
|
633
|
+
if (domainConfigName && domainConfigVersion) {
|
|
634
|
+
const domainRows = await queryData(getConfigByNameVersionParameters(domainConfigName, domainConfigVersion), config);
|
|
635
|
+
const domainRow = domainRows?.[0];
|
|
636
|
+
if (domainRow?.data) {
|
|
637
|
+
parsedDomainConfig = parseConfigData(domainRow.data) ?? {};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const publishBody = buildPublishBodyFromConfigs(parsedApplicationConfig, parsedDomainConfig, domainConfigName);
|
|
642
|
+
|
|
643
|
+
const response = await publishApp(
|
|
644
|
+
{
|
|
645
|
+
domainId: payload?.domainId ?? payload?.subdomain ?? undefined,
|
|
646
|
+
data: publishBody,
|
|
647
|
+
},
|
|
648
|
+
argv,
|
|
649
|
+
);
|
|
650
|
+
if (!response || response.success !== true) {
|
|
651
|
+
throw new Error(response?.error ? String(response.error) : "Application Config publish failed without an error message from the server.");
|
|
652
|
+
}
|
|
653
|
+
return response;
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
export const publishApplicationConfigAsync = async (payload = {}, argv = {}) => {
|
|
657
|
+
const applicationConfigName = String(payload?.applicationConfigName ?? "APPLICATION_CONFIG").trim() || "APPLICATION_CONFIG";
|
|
658
|
+
const applicationConfigVersion = String(payload?.applicationConfigVersion ?? "").trim();
|
|
659
|
+
if (!applicationConfigVersion) {
|
|
660
|
+
return { success: false, error: "payload.applicationConfigVersion is required." };
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const config = resolveConfigFromPayload(payload, argv);
|
|
664
|
+
const { name, version } = buildPublishStatusConfigKey(applicationConfigName, applicationConfigVersion);
|
|
665
|
+
const startedAt = new Date().toISOString();
|
|
666
|
+
|
|
667
|
+
await writePublishStatus(name, version, { status: "IN_PROGRESS", applicationConfigName, applicationConfigVersion, startedAt }, config);
|
|
668
|
+
|
|
669
|
+
publishApplicationConfig(payload, argv)
|
|
670
|
+
.then((result) =>
|
|
671
|
+
writePublishStatus(
|
|
672
|
+
name,
|
|
673
|
+
version,
|
|
674
|
+
{
|
|
675
|
+
success: true,
|
|
676
|
+
status: "SUCCESS",
|
|
677
|
+
applicationConfigName,
|
|
678
|
+
applicationConfigVersion,
|
|
679
|
+
startedAt,
|
|
680
|
+
finishedAt: new Date().toISOString(),
|
|
681
|
+
result,
|
|
682
|
+
},
|
|
683
|
+
config,
|
|
684
|
+
),
|
|
685
|
+
)
|
|
686
|
+
.catch((error) =>
|
|
687
|
+
writePublishStatus(
|
|
688
|
+
name,
|
|
689
|
+
version,
|
|
690
|
+
{
|
|
691
|
+
success: false,
|
|
692
|
+
status: "FAILED",
|
|
693
|
+
applicationConfigName,
|
|
694
|
+
applicationConfigVersion,
|
|
695
|
+
startedAt,
|
|
696
|
+
finishedAt: new Date().toISOString(),
|
|
697
|
+
error: error?.message ?? String(error),
|
|
698
|
+
},
|
|
699
|
+
config,
|
|
700
|
+
),
|
|
701
|
+
)
|
|
702
|
+
.catch((error) => {
|
|
703
|
+
console.error(`[ApplicationConfig Publish] Failed to record publish status for ${applicationConfigName}@${applicationConfigVersion}:`, error);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
return { success: true, status: "IN_PROGRESS", applicationConfigName, applicationConfigVersion, startedAt };
|
|
707
|
+
};
|