@memberjunction/core-actions 2.107.0 → 2.109.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom/ai/find-best-action.action.d.ts +53 -0
- package/dist/custom/ai/find-best-action.action.d.ts.map +1 -0
- package/dist/custom/ai/find-best-action.action.js +211 -0
- package/dist/custom/ai/find-best-action.action.js.map +1 -0
- package/dist/custom/ai/find-best-agent.action.d.ts +53 -0
- package/dist/custom/ai/find-best-agent.action.d.ts.map +1 -0
- package/dist/custom/ai/find-best-agent.action.js +194 -0
- package/dist/custom/ai/find-best-agent.action.js.map +1 -0
- package/dist/custom/ai/summarize-content.action.d.ts +3 -3
- package/dist/custom/ai/summarize-content.action.d.ts.map +1 -1
- package/dist/custom/ai/summarize-content.action.js +51 -143
- package/dist/custom/ai/summarize-content.action.js.map +1 -1
- package/dist/custom/code-execution/execute-code.action.d.ts +61 -0
- package/dist/custom/code-execution/execute-code.action.d.ts.map +1 -0
- package/dist/custom/code-execution/execute-code.action.js +172 -0
- package/dist/custom/code-execution/execute-code.action.js.map +1 -0
- package/dist/custom/data/csv-parser.action.js +1 -1
- package/dist/custom/data/csv-parser.action.js.map +1 -1
- package/dist/custom/data/execute-research-query.action.d.ts +36 -18
- package/dist/custom/data/execute-research-query.action.d.ts.map +1 -1
- package/dist/custom/data/execute-research-query.action.js +221 -114
- package/dist/custom/data/execute-research-query.action.js.map +1 -1
- package/dist/custom/data/explore-database-schema.action.d.ts +4 -0
- package/dist/custom/data/explore-database-schema.action.d.ts.map +1 -1
- package/dist/custom/data/explore-database-schema.action.js +101 -8
- package/dist/custom/data/explore-database-schema.action.js.map +1 -1
- package/dist/custom/data/get-entity-details.action.d.ts +63 -0
- package/dist/custom/data/get-entity-details.action.d.ts.map +1 -0
- package/dist/custom/data/get-entity-details.action.js +284 -0
- package/dist/custom/data/get-entity-details.action.js.map +1 -0
- package/dist/custom/data/get-entity-list.action.d.ts +57 -0
- package/dist/custom/data/get-entity-list.action.d.ts.map +1 -0
- package/dist/custom/data/get-entity-list.action.js +177 -0
- package/dist/custom/data/get-entity-list.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-chart.action.d.ts +97 -0
- package/dist/custom/visualization/create-svg-chart.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-chart.action.js +326 -0
- package/dist/custom/visualization/create-svg-chart.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-diagram.action.d.ts +151 -0
- package/dist/custom/visualization/create-svg-diagram.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-diagram.action.js +764 -0
- package/dist/custom/visualization/create-svg-diagram.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-infographic.action.d.ts +72 -0
- package/dist/custom/visualization/create-svg-infographic.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-infographic.action.js +343 -0
- package/dist/custom/visualization/create-svg-infographic.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-network.action.d.ts +106 -0
- package/dist/custom/visualization/create-svg-network.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-network.action.js +687 -0
- package/dist/custom/visualization/create-svg-network.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-sketch-diagram.action.d.ts +97 -0
- package/dist/custom/visualization/create-svg-sketch-diagram.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-sketch-diagram.action.js +730 -0
- package/dist/custom/visualization/create-svg-sketch-diagram.action.js.map +1 -0
- package/dist/custom/visualization/create-svg-word-cloud.action.d.ts +94 -0
- package/dist/custom/visualization/create-svg-word-cloud.action.d.ts.map +1 -0
- package/dist/custom/visualization/create-svg-word-cloud.action.js +497 -0
- package/dist/custom/visualization/create-svg-word-cloud.action.js.map +1 -0
- package/dist/custom/visualization/shared/svg-theming.d.ts +91 -0
- package/dist/custom/visualization/shared/svg-theming.d.ts.map +1 -0
- package/dist/custom/visualization/shared/svg-theming.js +235 -0
- package/dist/custom/visualization/shared/svg-theming.js.map +1 -0
- package/dist/custom/visualization/shared/svg-types.d.ts +354 -0
- package/dist/custom/visualization/shared/svg-types.d.ts.map +1 -0
- package/dist/custom/visualization/shared/svg-types.js +11 -0
- package/dist/custom/visualization/shared/svg-types.js.map +1 -0
- package/dist/custom/visualization/shared/svg-utils.d.ts +166 -0
- package/dist/custom/visualization/shared/svg-utils.d.ts.map +1 -0
- package/dist/custom/visualization/shared/svg-utils.js +555 -0
- package/dist/custom/visualization/shared/svg-utils.js.map +1 -0
- package/dist/custom/web/google-custom-search.action.d.ts +6 -1
- package/dist/custom/web/google-custom-search.action.d.ts.map +1 -1
- package/dist/custom/web/google-custom-search.action.js +78 -10
- package/dist/custom/web/google-custom-search.action.js.map +1 -1
- package/dist/custom/web/web-page-content.action.d.ts +24 -0
- package/dist/custom/web/web-page-content.action.d.ts.map +1 -1
- package/dist/custom/web/web-page-content.action.js +90 -9
- package/dist/custom/web/web-page-content.action.js.map +1 -1
- package/dist/generated/action_subclasses.d.ts +4 -4
- package/dist/generated/action_subclasses.js +13 -13
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/package.json +30 -12
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
25
|
+
if (mod && mod.__esModule) return mod;
|
|
26
|
+
var result = {};
|
|
27
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
28
|
+
__setModuleDefault(result, mod);
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.LoadCreateSVGNetworkAction = exports.CreateSVGNetworkAction = void 0;
|
|
33
|
+
const actions_1 = require("@memberjunction/actions");
|
|
34
|
+
const global_1 = require("@memberjunction/global");
|
|
35
|
+
const d3Force = __importStar(require("d3-force"));
|
|
36
|
+
const d3Hierarchy = __importStar(require("d3-hierarchy"));
|
|
37
|
+
const svg_utils_1 = require("./shared/svg-utils");
|
|
38
|
+
const svg_theming_1 = require("./shared/svg-theming");
|
|
39
|
+
/**
|
|
40
|
+
* Action that generates SVG network graphs including force-directed layouts, decision trees, and radial networks.
|
|
41
|
+
*
|
|
42
|
+
* This action provides server-side SVG generation for network visualizations, designed for
|
|
43
|
+
* AI agents and workflows to create publication-quality graphs from structured data.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Force-directed network example
|
|
48
|
+
* await runAction({
|
|
49
|
+
* ActionName: 'Create SVG Network',
|
|
50
|
+
* Params: [
|
|
51
|
+
* { Name: 'NetworkType', Value: 'force' },
|
|
52
|
+
* { Name: 'Nodes', Value: JSON.stringify([
|
|
53
|
+
* { id: '1', label: 'Node A', group: 'A' },
|
|
54
|
+
* { id: '2', label: 'Node B', group: 'B' },
|
|
55
|
+
* { id: '3', label: 'Node C', group: 'A' }
|
|
56
|
+
* ]) },
|
|
57
|
+
* { Name: 'Edges', Value: JSON.stringify([
|
|
58
|
+
* { source: '1', target: '2', weight: 1, directed: true },
|
|
59
|
+
* { source: '2', target: '3', weight: 0.5 }
|
|
60
|
+
* ]) },
|
|
61
|
+
* { Name: 'ShowLabels', Value: 'true' },
|
|
62
|
+
* { Name: 'ShowLegend', Value: 'true' }
|
|
63
|
+
* ]
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // Decision tree example
|
|
67
|
+
* await runAction({
|
|
68
|
+
* ActionName: 'Create SVG Network',
|
|
69
|
+
* Params: [
|
|
70
|
+
* { Name: 'NetworkType', Value: 'tree' },
|
|
71
|
+
* { Name: 'Nodes', Value: JSON.stringify({
|
|
72
|
+
* id: 'root',
|
|
73
|
+
* label: 'Decision',
|
|
74
|
+
* children: [
|
|
75
|
+
* { id: '1', label: 'Option A', value: 0.6 },
|
|
76
|
+
* { id: '2', label: 'Option B', value: 0.4 }
|
|
77
|
+
* ]
|
|
78
|
+
* }) }
|
|
79
|
+
* ]
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
let CreateSVGNetworkAction = class CreateSVGNetworkAction extends actions_1.BaseAction {
|
|
84
|
+
/**
|
|
85
|
+
* Generates an SVG network graph from the provided data and configuration
|
|
86
|
+
*
|
|
87
|
+
* @param params - The action parameters containing:
|
|
88
|
+
* - NetworkType: Type of network ('force' | 'tree' | 'radial')
|
|
89
|
+
* - Nodes: JSON array or object of nodes
|
|
90
|
+
* - Edges: JSON array of edges (for force and radial)
|
|
91
|
+
* - Physics: Physics parameters (charge, linkDistance, iterations)
|
|
92
|
+
* - ShowLabels: Show node labels (default: true)
|
|
93
|
+
* - ShowLegend: Show group legend (default: false)
|
|
94
|
+
* - NodeShape: Shape for tree nodes ('rect' | 'circle' | 'pill')
|
|
95
|
+
* - Width: Width in pixels (optional, default: 800)
|
|
96
|
+
* - Height: Height in pixels (optional, default: 600)
|
|
97
|
+
* - Title: Network title (optional)
|
|
98
|
+
* - Palette: Color palette name (optional)
|
|
99
|
+
* - Seed: Random seed for deterministic layouts (optional)
|
|
100
|
+
*
|
|
101
|
+
* @returns A promise resolving to an SVGActionResult
|
|
102
|
+
*/
|
|
103
|
+
async InternalRunAction(params) {
|
|
104
|
+
try {
|
|
105
|
+
const networkTypeParam = this.getParamValue(params, 'NetworkType');
|
|
106
|
+
if (!networkTypeParam) {
|
|
107
|
+
return {
|
|
108
|
+
Success: false,
|
|
109
|
+
Message: 'NetworkType parameter is required. Must be "force", "tree", or "radial"',
|
|
110
|
+
ResultCode: 'MISSING_PARAMETERS',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const networkType = this.ensureString(networkTypeParam, 'NetworkType').toLowerCase();
|
|
114
|
+
if (!['force', 'tree', 'radial'].includes(networkType)) {
|
|
115
|
+
return {
|
|
116
|
+
Success: false,
|
|
117
|
+
Message: 'NetworkType must be "force", "tree", or "radial"',
|
|
118
|
+
ResultCode: 'INVALID_NETWORK_TYPE',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Parse common parameters
|
|
122
|
+
const width = parseInt(this.ensureString(this.getParamValue(params, 'Width') || '800', 'Width'));
|
|
123
|
+
const height = parseInt(this.ensureString(this.getParamValue(params, 'Height') || '600', 'Height'));
|
|
124
|
+
const title = this.ensureString(this.getParamValue(params, 'Title') || '', 'Title');
|
|
125
|
+
const paletteName = this.ensureString(this.getParamValue(params, 'Palette') || 'mjDefault', 'Palette');
|
|
126
|
+
const seed = parseInt(this.ensureString(this.getParamValue(params, 'Seed') || String(Date.now()), 'Seed'));
|
|
127
|
+
const showLabelsParam = this.getParamValue(params, 'ShowLabels');
|
|
128
|
+
const showLabels = showLabelsParam ? this.ensureString(showLabelsParam, 'ShowLabels').toLowerCase() !== 'false' : true;
|
|
129
|
+
const showLegendParam = this.getParamValue(params, 'ShowLegend');
|
|
130
|
+
const showLegend = showLegendParam ? this.ensureString(showLegendParam, 'ShowLegend').toLowerCase() === 'true' : false;
|
|
131
|
+
// Parse interactivity parameters
|
|
132
|
+
const enableTooltipsParam = this.getParamValue(params, 'EnableTooltips');
|
|
133
|
+
const enableTooltips = enableTooltipsParam ? this.ensureString(enableTooltipsParam, 'EnableTooltips').toLowerCase() === 'true' : false;
|
|
134
|
+
const enablePanZoomParam = this.getParamValue(params, 'EnablePanZoom');
|
|
135
|
+
const enablePanZoom = enablePanZoomParam ? this.ensureString(enablePanZoomParam, 'EnablePanZoom').toLowerCase() === 'true' : false;
|
|
136
|
+
const showZoomControlsParam = this.getParamValue(params, 'ShowZoomControls');
|
|
137
|
+
const showZoomControls = showZoomControlsParam ? this.ensureString(showZoomControlsParam, 'ShowZoomControls').toLowerCase() === 'true' : false;
|
|
138
|
+
const wrapWithContainerParam = this.getParamValue(params, 'WrapWithContainer');
|
|
139
|
+
const wrapWithContainer = wrapWithContainerParam ? this.ensureString(wrapWithContainerParam, 'WrapWithContainer').toLowerCase() === 'true' : false;
|
|
140
|
+
const maxContainerWidth = parseInt(this.ensureString(this.getParamValue(params, 'MaxContainerWidth') || '1200', 'MaxContainerWidth'));
|
|
141
|
+
const maxContainerHeight = parseInt(this.ensureString(this.getParamValue(params, 'MaxContainerHeight') || '800', 'MaxContainerHeight'));
|
|
142
|
+
// Create branding configuration
|
|
143
|
+
const branding = {
|
|
144
|
+
palette: { type: 'named', name: paletteName },
|
|
145
|
+
};
|
|
146
|
+
// Create viewBox configuration
|
|
147
|
+
const viewBox = {
|
|
148
|
+
width,
|
|
149
|
+
height,
|
|
150
|
+
padding: 40,
|
|
151
|
+
};
|
|
152
|
+
// Generate network based on type
|
|
153
|
+
let svg;
|
|
154
|
+
const warnings = [];
|
|
155
|
+
switch (networkType) {
|
|
156
|
+
case 'force':
|
|
157
|
+
svg = await this.renderForceNetwork(params, viewBox, branding, title, seed, showLabels, showLegend, enableTooltips, enablePanZoom, showZoomControls, warnings);
|
|
158
|
+
break;
|
|
159
|
+
case 'tree':
|
|
160
|
+
svg = await this.renderDecisionTree(params, viewBox, branding, title, showLabels, enableTooltips, enablePanZoom, showZoomControls);
|
|
161
|
+
break;
|
|
162
|
+
case 'radial':
|
|
163
|
+
svg = await this.renderRadialNetwork(params, viewBox, branding, title, seed, showLabels, enableTooltips, enablePanZoom, showZoomControls, warnings);
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
return {
|
|
167
|
+
Success: false,
|
|
168
|
+
Message: `Unsupported network type: ${networkType}`,
|
|
169
|
+
ResultCode: 'INVALID_NETWORK_TYPE',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Apply scroll container wrapping if requested
|
|
173
|
+
if (wrapWithContainer) {
|
|
174
|
+
svg = svg_utils_1.SVGUtils.wrapWithScrollContainer(svg, maxContainerWidth, maxContainerHeight);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
Success: true,
|
|
178
|
+
ResultCode: 'SUCCESS',
|
|
179
|
+
Message: svg,
|
|
180
|
+
svg,
|
|
181
|
+
width,
|
|
182
|
+
height,
|
|
183
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return {
|
|
188
|
+
Success: false,
|
|
189
|
+
Message: `Failed to generate network: ${error instanceof Error ? error.message : String(error)}`,
|
|
190
|
+
ResultCode: 'NETWORK_GENERATION_FAILED',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Renders a force-directed network using d3-force
|
|
196
|
+
*/
|
|
197
|
+
async renderForceNetwork(params, viewBox, branding, title, seed, showLabels, showLegend, enableTooltips, enablePanZoom, showZoomControls, warnings) {
|
|
198
|
+
// Parse nodes and edges
|
|
199
|
+
const nodesParam = this.getParamValue(params, 'Nodes');
|
|
200
|
+
const edgesParam = this.getParamValue(params, 'Edges');
|
|
201
|
+
if (!nodesParam) {
|
|
202
|
+
throw new Error('Nodes parameter is required for force networks');
|
|
203
|
+
}
|
|
204
|
+
const nodes = this.parseJSON(nodesParam, 'Nodes');
|
|
205
|
+
const edges = edgesParam ? this.parseJSON(edgesParam, 'Edges') : [];
|
|
206
|
+
// Parse physics parameters
|
|
207
|
+
const physicsParam = this.getParamValue(params, 'Physics');
|
|
208
|
+
const physics = physicsParam ? this.parseJSON(physicsParam, 'Physics') : {};
|
|
209
|
+
const charge = physics.charge || -300;
|
|
210
|
+
const linkDistance = physics.linkDistance || 100;
|
|
211
|
+
const iterations = physics.iterations || 300;
|
|
212
|
+
// Warn if graph is too large
|
|
213
|
+
if (nodes.length > 500) {
|
|
214
|
+
warnings.push(`Large graph with ${nodes.length} nodes may have performance issues`);
|
|
215
|
+
}
|
|
216
|
+
// Create seeded random generator
|
|
217
|
+
const random = svg_utils_1.SVGUtils.seededRandom(seed);
|
|
218
|
+
// Initialize node positions randomly
|
|
219
|
+
const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
|
|
220
|
+
const simNodes = nodes.map((n) => ({
|
|
221
|
+
...n,
|
|
222
|
+
x: vb.x + random() * vb.contentWidth,
|
|
223
|
+
y: vb.y + random() * vb.contentHeight,
|
|
224
|
+
vx: 0,
|
|
225
|
+
vy: 0,
|
|
226
|
+
}));
|
|
227
|
+
// Create force simulation
|
|
228
|
+
const simulation = d3Force
|
|
229
|
+
.forceSimulation(simNodes)
|
|
230
|
+
.force('link', d3Force
|
|
231
|
+
.forceLink(edges)
|
|
232
|
+
.id((d) => d.id)
|
|
233
|
+
.distance(linkDistance))
|
|
234
|
+
.force('charge', d3Force.forceManyBody().strength(charge))
|
|
235
|
+
.force('center', d3Force.forceCenter(vb.x + vb.contentWidth / 2, vb.y + vb.contentHeight / 2))
|
|
236
|
+
.force('collide', d3Force.forceCollide(20))
|
|
237
|
+
.stop();
|
|
238
|
+
// Run simulation headless
|
|
239
|
+
for (let i = 0; i < iterations; i++) {
|
|
240
|
+
simulation.tick();
|
|
241
|
+
}
|
|
242
|
+
// Create SVG
|
|
243
|
+
const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'force-network');
|
|
244
|
+
const svg = doc.querySelector('svg');
|
|
245
|
+
// Add accessibility
|
|
246
|
+
if (title) {
|
|
247
|
+
svg_utils_1.SVGUtils.addA11y(svg, {
|
|
248
|
+
title,
|
|
249
|
+
ariaRole: 'img',
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
// Add styles
|
|
253
|
+
const css = (0, svg_theming_1.generateCSS)(branding);
|
|
254
|
+
svg_utils_1.SVGUtils.addStyles(svg, css);
|
|
255
|
+
// Get palette
|
|
256
|
+
const palette = (0, svg_theming_1.getPalette)(branding.palette);
|
|
257
|
+
const ns = svg.namespaceURI;
|
|
258
|
+
// Build group-to-color mapping
|
|
259
|
+
const groups = [...new Set(nodes.map((n) => n.group).filter((g) => g != null))];
|
|
260
|
+
const groupColorMap = new Map(groups.map((g, i) => [g, (0, svg_theming_1.getColorForIndex)(i, branding.palette)]));
|
|
261
|
+
// Wrap content in pan/zoom container if needed
|
|
262
|
+
const contentContainer = doc.createElementNS(ns, 'g');
|
|
263
|
+
contentContainer.setAttribute('id', enablePanZoom ? 'pan-zoom-container' : 'content-container');
|
|
264
|
+
svg.appendChild(contentContainer);
|
|
265
|
+
// Render edges
|
|
266
|
+
const edgesGroup = doc.createElementNS(ns, 'g');
|
|
267
|
+
edgesGroup.setAttribute('id', 'edges');
|
|
268
|
+
contentContainer.appendChild(edgesGroup);
|
|
269
|
+
for (const edge of edges) {
|
|
270
|
+
const sourceSim = simNodes.find((n) => n.id === edge.source.id || n.id === edge.source);
|
|
271
|
+
const targetSim = simNodes.find((n) => n.id === edge.target.id || n.id === edge.target);
|
|
272
|
+
if (!sourceSim || !targetSim)
|
|
273
|
+
continue;
|
|
274
|
+
const line = doc.createElementNS(ns, 'line');
|
|
275
|
+
line.setAttribute('x1', String(sourceSim.x));
|
|
276
|
+
line.setAttribute('y1', String(sourceSim.y));
|
|
277
|
+
line.setAttribute('x2', String(targetSim.x));
|
|
278
|
+
line.setAttribute('y2', String(targetSim.y));
|
|
279
|
+
line.setAttribute('stroke', palette.foreground);
|
|
280
|
+
line.setAttribute('stroke-width', String((edge.weight || 1) * 2));
|
|
281
|
+
line.setAttribute('opacity', '0.6');
|
|
282
|
+
if (edge.directed) {
|
|
283
|
+
const markerId = svg_utils_1.SVGUtils.addArrowMarker(svg, 'arrow-force', palette.foreground);
|
|
284
|
+
line.setAttribute('marker-end', markerId);
|
|
285
|
+
}
|
|
286
|
+
edgesGroup.appendChild(line);
|
|
287
|
+
}
|
|
288
|
+
// Render nodes
|
|
289
|
+
const nodesGroup = doc.createElementNS(ns, 'g');
|
|
290
|
+
nodesGroup.setAttribute('id', 'nodes');
|
|
291
|
+
contentContainer.appendChild(nodesGroup);
|
|
292
|
+
for (const node of simNodes) {
|
|
293
|
+
const g = doc.createElementNS(ns, 'g');
|
|
294
|
+
g.setAttribute('transform', `translate(${node.x}, ${node.y})`);
|
|
295
|
+
g.setAttribute('data-node-id', node.id);
|
|
296
|
+
// Add tooltip data if enabled
|
|
297
|
+
if (enableTooltips) {
|
|
298
|
+
const tooltipText = `${node.label || node.id}${node.group ? ' (' + node.group + ')' : ''}`;
|
|
299
|
+
g.setAttribute('data-tooltip', tooltipText);
|
|
300
|
+
}
|
|
301
|
+
const radius = node.size || 10;
|
|
302
|
+
const color = node.group ? groupColorMap.get(node.group) || palette.categorical[0] : palette.categorical[0];
|
|
303
|
+
const circle = doc.createElementNS(ns, 'circle');
|
|
304
|
+
circle.setAttribute('r', String(radius));
|
|
305
|
+
circle.setAttribute('fill', color);
|
|
306
|
+
circle.setAttribute('stroke', '#FFF');
|
|
307
|
+
circle.setAttribute('stroke-width', '2');
|
|
308
|
+
circle.setAttribute('class', 'node-circle');
|
|
309
|
+
g.appendChild(circle);
|
|
310
|
+
if (showLabels && node.label) {
|
|
311
|
+
const text = doc.createElementNS(ns, 'text');
|
|
312
|
+
text.setAttribute('y', String(radius + 15));
|
|
313
|
+
text.setAttribute('text-anchor', 'middle');
|
|
314
|
+
text.setAttribute('font-size', '11');
|
|
315
|
+
text.setAttribute('fill', palette.foreground);
|
|
316
|
+
text.textContent = node.label;
|
|
317
|
+
g.appendChild(text);
|
|
318
|
+
}
|
|
319
|
+
nodesGroup.appendChild(g);
|
|
320
|
+
}
|
|
321
|
+
// Add legend if requested
|
|
322
|
+
if (showLegend && groups.length > 0) {
|
|
323
|
+
this.addLegend(doc, svg, groups, groupColorMap, vb, (0, svg_theming_1.getFontSpec)(branding.font));
|
|
324
|
+
}
|
|
325
|
+
// Add title if present
|
|
326
|
+
if (title) {
|
|
327
|
+
this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
|
|
328
|
+
}
|
|
329
|
+
// Add interactivity features
|
|
330
|
+
if (enableTooltips) {
|
|
331
|
+
svg_utils_1.SVGUtils.addTooltipSupport(svg, doc);
|
|
332
|
+
}
|
|
333
|
+
if (enablePanZoom) {
|
|
334
|
+
const panZoomScript = doc.createElementNS(ns, 'script');
|
|
335
|
+
panZoomScript.setAttribute('type', 'text/javascript');
|
|
336
|
+
panZoomScript.textContent = svg_utils_1.SVGUtils.generatePanZoomScript('pan-zoom-container', 0.5, 3, showZoomControls).replace(/<script[^>]*>|<\/script>/gi, '');
|
|
337
|
+
svg.appendChild(panZoomScript);
|
|
338
|
+
}
|
|
339
|
+
// Sanitize and return
|
|
340
|
+
return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Renders a decision tree using d3-hierarchy
|
|
344
|
+
*/
|
|
345
|
+
async renderDecisionTree(params, viewBox, branding, title, showLabels, enableTooltips, enablePanZoom, showZoomControls) {
|
|
346
|
+
// Parse tree
|
|
347
|
+
const nodesParam = this.getParamValue(params, 'Nodes');
|
|
348
|
+
if (!nodesParam) {
|
|
349
|
+
throw new Error('Nodes parameter is required for decision trees');
|
|
350
|
+
}
|
|
351
|
+
const rootNode = this.parseJSON(nodesParam, 'Nodes');
|
|
352
|
+
const nodeShapeParam = this.getParamValue(params, 'NodeShape');
|
|
353
|
+
const nodeShape = (nodeShapeParam ? this.ensureString(nodeShapeParam, 'NodeShape') : 'rect');
|
|
354
|
+
// Create hierarchy
|
|
355
|
+
const hierarchy = d3Hierarchy.hierarchy(rootNode);
|
|
356
|
+
// Create tree layout
|
|
357
|
+
const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
|
|
358
|
+
const treeLayout = d3Hierarchy.tree().size([vb.contentWidth, vb.contentHeight]);
|
|
359
|
+
// Calculate layout
|
|
360
|
+
const treeData = treeLayout(hierarchy);
|
|
361
|
+
// Create SVG
|
|
362
|
+
const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'decision-tree');
|
|
363
|
+
const svg = doc.querySelector('svg');
|
|
364
|
+
// Add accessibility
|
|
365
|
+
if (title) {
|
|
366
|
+
svg_utils_1.SVGUtils.addA11y(svg, {
|
|
367
|
+
title,
|
|
368
|
+
ariaRole: 'img',
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
// Add styles
|
|
372
|
+
const css = (0, svg_theming_1.generateCSS)(branding);
|
|
373
|
+
svg_utils_1.SVGUtils.addStyles(svg, css);
|
|
374
|
+
// Get palette
|
|
375
|
+
const palette = (0, svg_theming_1.getPalette)(branding.palette);
|
|
376
|
+
const ns = svg.namespaceURI;
|
|
377
|
+
// Create container group with offset for padding
|
|
378
|
+
const container = doc.createElementNS(ns, 'g');
|
|
379
|
+
container.setAttribute('transform', `translate(${vb.x}, ${vb.y})`);
|
|
380
|
+
svg.appendChild(container);
|
|
381
|
+
// Render links
|
|
382
|
+
treeData.links().forEach((link) => {
|
|
383
|
+
const path = doc.createElementNS(ns, 'path');
|
|
384
|
+
// Diagonal path
|
|
385
|
+
const d = `M ${link.source.x},${link.source.y}
|
|
386
|
+
C ${link.source.x},${(link.source.y + link.target.y) / 2}
|
|
387
|
+
${link.target.x},${(link.source.y + link.target.y) / 2}
|
|
388
|
+
${link.target.x},${link.target.y}`;
|
|
389
|
+
path.setAttribute('d', d);
|
|
390
|
+
path.setAttribute('fill', 'none');
|
|
391
|
+
path.setAttribute('stroke', palette.foreground);
|
|
392
|
+
path.setAttribute('stroke-width', '2');
|
|
393
|
+
path.setAttribute('opacity', '0.6');
|
|
394
|
+
container.appendChild(path);
|
|
395
|
+
});
|
|
396
|
+
// Render nodes
|
|
397
|
+
treeData.descendants().forEach((node) => {
|
|
398
|
+
const g = doc.createElementNS(ns, 'g');
|
|
399
|
+
g.setAttribute('transform', `translate(${node.x}, ${node.y})`);
|
|
400
|
+
const colorIndex = node.depth % palette.categorical.length;
|
|
401
|
+
const fillColor = palette.categorical[colorIndex];
|
|
402
|
+
// Render shape based on nodeShape
|
|
403
|
+
switch (nodeShape) {
|
|
404
|
+
case 'circle':
|
|
405
|
+
const circle = doc.createElementNS(ns, 'circle');
|
|
406
|
+
circle.setAttribute('r', '25');
|
|
407
|
+
circle.setAttribute('fill', fillColor);
|
|
408
|
+
circle.setAttribute('stroke', '#333');
|
|
409
|
+
circle.setAttribute('stroke-width', '2');
|
|
410
|
+
g.appendChild(circle);
|
|
411
|
+
break;
|
|
412
|
+
case 'pill':
|
|
413
|
+
const pill = doc.createElementNS(ns, 'path');
|
|
414
|
+
pill.setAttribute('d', svg_utils_1.SVGUtils.roundedRectPath(-40, -20, 80, 40, 20));
|
|
415
|
+
pill.setAttribute('fill', fillColor);
|
|
416
|
+
pill.setAttribute('stroke', '#333');
|
|
417
|
+
pill.setAttribute('stroke-width', '2');
|
|
418
|
+
g.appendChild(pill);
|
|
419
|
+
break;
|
|
420
|
+
default: // rect
|
|
421
|
+
const rect = doc.createElementNS(ns, 'rect');
|
|
422
|
+
rect.setAttribute('x', '-30');
|
|
423
|
+
rect.setAttribute('y', '-20');
|
|
424
|
+
rect.setAttribute('width', '60');
|
|
425
|
+
rect.setAttribute('height', '40');
|
|
426
|
+
rect.setAttribute('fill', fillColor);
|
|
427
|
+
rect.setAttribute('stroke', '#333');
|
|
428
|
+
rect.setAttribute('stroke-width', '2');
|
|
429
|
+
rect.setAttribute('rx', '5');
|
|
430
|
+
g.appendChild(rect);
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
// Add label
|
|
434
|
+
if (showLabels) {
|
|
435
|
+
const labelText = doc.createElementNS(ns, 'text');
|
|
436
|
+
labelText.setAttribute('y', node.data.value != null ? '-5' : '0');
|
|
437
|
+
labelText.setAttribute('text-anchor', 'middle');
|
|
438
|
+
labelText.setAttribute('dominant-baseline', 'middle');
|
|
439
|
+
labelText.setAttribute('font-size', '11');
|
|
440
|
+
labelText.setAttribute('font-weight', 'bold');
|
|
441
|
+
labelText.setAttribute('fill', '#FFF');
|
|
442
|
+
labelText.textContent = node.data.label;
|
|
443
|
+
g.appendChild(labelText);
|
|
444
|
+
// Add value if present
|
|
445
|
+
if (node.data.value != null) {
|
|
446
|
+
const valueText = doc.createElementNS(ns, 'text');
|
|
447
|
+
valueText.setAttribute('y', '8');
|
|
448
|
+
valueText.setAttribute('text-anchor', 'middle');
|
|
449
|
+
valueText.setAttribute('font-size', '9');
|
|
450
|
+
valueText.setAttribute('fill', '#FFF');
|
|
451
|
+
valueText.setAttribute('opacity', '0.9');
|
|
452
|
+
valueText.textContent = String(node.data.value);
|
|
453
|
+
g.appendChild(valueText);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
container.appendChild(g);
|
|
457
|
+
});
|
|
458
|
+
// Add title if present
|
|
459
|
+
if (title) {
|
|
460
|
+
this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
|
|
461
|
+
}
|
|
462
|
+
// Sanitize and return
|
|
463
|
+
return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Renders a radial network using d3-force with radial constraint
|
|
467
|
+
*/
|
|
468
|
+
async renderRadialNetwork(params, viewBox, branding, title, seed, showLabels, enableTooltips, enablePanZoom, showZoomControls, warnings) {
|
|
469
|
+
// Parse nodes and edges
|
|
470
|
+
const nodesParam = this.getParamValue(params, 'Nodes');
|
|
471
|
+
const edgesParam = this.getParamValue(params, 'Edges');
|
|
472
|
+
if (!nodesParam) {
|
|
473
|
+
throw new Error('Nodes parameter is required for radial networks');
|
|
474
|
+
}
|
|
475
|
+
const nodes = this.parseJSON(nodesParam, 'Nodes');
|
|
476
|
+
const edges = edgesParam ? this.parseJSON(edgesParam, 'Edges') : [];
|
|
477
|
+
// Identify central node (first node or node with most connections)
|
|
478
|
+
const degreeMap = new Map();
|
|
479
|
+
for (const edge of edges) {
|
|
480
|
+
degreeMap.set(edge.source, (degreeMap.get(edge.source) || 0) + 1);
|
|
481
|
+
degreeMap.set(edge.target, (degreeMap.get(edge.target) || 0) + 1);
|
|
482
|
+
}
|
|
483
|
+
const centralNodeId = nodes.length > 0 ? [...degreeMap.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || nodes[0].id : nodes[0].id;
|
|
484
|
+
// Create seeded random generator
|
|
485
|
+
const random = svg_utils_1.SVGUtils.seededRandom(seed);
|
|
486
|
+
// Initialize node positions
|
|
487
|
+
const vb = svg_utils_1.SVGUtils.calculateViewBox(viewBox);
|
|
488
|
+
const centerX = vb.x + vb.contentWidth / 2;
|
|
489
|
+
const centerY = vb.y + vb.contentHeight / 2;
|
|
490
|
+
const simNodes = nodes.map((n, i) => ({
|
|
491
|
+
...n,
|
|
492
|
+
x: centerX + (random() - 0.5) * 100,
|
|
493
|
+
y: centerY + (random() - 0.5) * 100,
|
|
494
|
+
vx: 0,
|
|
495
|
+
vy: 0,
|
|
496
|
+
isCentral: n.id === centralNodeId,
|
|
497
|
+
}));
|
|
498
|
+
// Create force simulation with radial force
|
|
499
|
+
const simulation = d3Force
|
|
500
|
+
.forceSimulation(simNodes)
|
|
501
|
+
.force('link', d3Force
|
|
502
|
+
.forceLink(edges)
|
|
503
|
+
.id((d) => d.id)
|
|
504
|
+
.distance(80))
|
|
505
|
+
.force('charge', d3Force.forceManyBody().strength(-200))
|
|
506
|
+
.force('radial', d3Force.forceRadial((d) => (d.isCentral ? 0 : 150), centerX, centerY))
|
|
507
|
+
.force('collide', d3Force.forceCollide(25))
|
|
508
|
+
.stop();
|
|
509
|
+
// Run simulation headless
|
|
510
|
+
for (let i = 0; i < 300; i++) {
|
|
511
|
+
simulation.tick();
|
|
512
|
+
}
|
|
513
|
+
// Create SVG (reuse force network rendering logic)
|
|
514
|
+
const doc = svg_utils_1.SVGUtils.createSVG(viewBox.width, viewBox.height, 'radial-network');
|
|
515
|
+
const svg = doc.querySelector('svg');
|
|
516
|
+
// Add accessibility
|
|
517
|
+
if (title) {
|
|
518
|
+
svg_utils_1.SVGUtils.addA11y(svg, {
|
|
519
|
+
title,
|
|
520
|
+
ariaRole: 'img',
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
// Add styles
|
|
524
|
+
const css = (0, svg_theming_1.generateCSS)(branding);
|
|
525
|
+
svg_utils_1.SVGUtils.addStyles(svg, css);
|
|
526
|
+
// Get palette
|
|
527
|
+
const palette = (0, svg_theming_1.getPalette)(branding.palette);
|
|
528
|
+
const ns = svg.namespaceURI;
|
|
529
|
+
// Render edges
|
|
530
|
+
const edgesGroup = doc.createElementNS(ns, 'g');
|
|
531
|
+
edgesGroup.setAttribute('id', 'edges');
|
|
532
|
+
svg.appendChild(edgesGroup);
|
|
533
|
+
for (const edge of edges) {
|
|
534
|
+
const sourceSim = simNodes.find((n) => n.id === edge.source.id || n.id === edge.source);
|
|
535
|
+
const targetSim = simNodes.find((n) => n.id === edge.target.id || n.id === edge.target);
|
|
536
|
+
if (!sourceSim || !targetSim)
|
|
537
|
+
continue;
|
|
538
|
+
const line = doc.createElementNS(ns, 'line');
|
|
539
|
+
line.setAttribute('x1', String(sourceSim.x));
|
|
540
|
+
line.setAttribute('y1', String(sourceSim.y));
|
|
541
|
+
line.setAttribute('x2', String(targetSim.x));
|
|
542
|
+
line.setAttribute('y2', String(targetSim.y));
|
|
543
|
+
line.setAttribute('stroke', palette.foreground);
|
|
544
|
+
line.setAttribute('stroke-width', '2');
|
|
545
|
+
line.setAttribute('opacity', '0.4');
|
|
546
|
+
edgesGroup.appendChild(line);
|
|
547
|
+
}
|
|
548
|
+
// Render nodes
|
|
549
|
+
const nodesGroup = doc.createElementNS(ns, 'g');
|
|
550
|
+
nodesGroup.setAttribute('id', 'nodes');
|
|
551
|
+
svg.appendChild(nodesGroup);
|
|
552
|
+
for (const node of simNodes) {
|
|
553
|
+
const g = doc.createElementNS(ns, 'g');
|
|
554
|
+
g.setAttribute('transform', `translate(${node.x}, ${node.y})`);
|
|
555
|
+
const radius = node.isCentral ? 20 : node.size || 12;
|
|
556
|
+
const color = node.isCentral ? palette.categorical[4] : palette.categorical[0];
|
|
557
|
+
const circle = doc.createElementNS(ns, 'circle');
|
|
558
|
+
circle.setAttribute('r', String(radius));
|
|
559
|
+
circle.setAttribute('fill', color);
|
|
560
|
+
circle.setAttribute('stroke', '#FFF');
|
|
561
|
+
circle.setAttribute('stroke-width', node.isCentral ? '3' : '2');
|
|
562
|
+
g.appendChild(circle);
|
|
563
|
+
if (showLabels && node.label) {
|
|
564
|
+
const text = doc.createElementNS(ns, 'text');
|
|
565
|
+
text.setAttribute('y', String(radius + 15));
|
|
566
|
+
text.setAttribute('text-anchor', 'middle');
|
|
567
|
+
text.setAttribute('font-size', node.isCentral ? '12' : '10');
|
|
568
|
+
text.setAttribute('font-weight', node.isCentral ? 'bold' : 'normal');
|
|
569
|
+
text.setAttribute('fill', palette.foreground);
|
|
570
|
+
text.textContent = node.label;
|
|
571
|
+
g.appendChild(text);
|
|
572
|
+
}
|
|
573
|
+
nodesGroup.appendChild(g);
|
|
574
|
+
}
|
|
575
|
+
// Add title if present
|
|
576
|
+
if (title) {
|
|
577
|
+
this.addTitle(doc, svg, title, vb.width, (0, svg_theming_1.getFontSpec)(branding.font));
|
|
578
|
+
}
|
|
579
|
+
// Sanitize and return
|
|
580
|
+
return svg_utils_1.SVGUtils.sanitizeSVG(svg.outerHTML);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Adds a legend to the SVG
|
|
584
|
+
*/
|
|
585
|
+
addLegend(doc, svg, groups, groupColorMap, vb, font) {
|
|
586
|
+
const ns = svg.namespaceURI;
|
|
587
|
+
const legendGroup = doc.createElementNS(ns, 'g');
|
|
588
|
+
legendGroup.setAttribute('id', 'legend');
|
|
589
|
+
legendGroup.setAttribute('transform', `translate(${vb.width - 150}, 50)`);
|
|
590
|
+
groups.forEach((group, i) => {
|
|
591
|
+
const g = doc.createElementNS(ns, 'g');
|
|
592
|
+
g.setAttribute('transform', `translate(0, ${i * 25})`);
|
|
593
|
+
const circle = doc.createElementNS(ns, 'circle');
|
|
594
|
+
circle.setAttribute('cx', '10');
|
|
595
|
+
circle.setAttribute('cy', '10');
|
|
596
|
+
circle.setAttribute('r', '8');
|
|
597
|
+
circle.setAttribute('fill', groupColorMap.get(group));
|
|
598
|
+
circle.setAttribute('stroke', '#333');
|
|
599
|
+
g.appendChild(circle);
|
|
600
|
+
const text = doc.createElementNS(ns, 'text');
|
|
601
|
+
text.setAttribute('x', '25');
|
|
602
|
+
text.setAttribute('y', '15');
|
|
603
|
+
text.setAttribute('font-size', String(font.size - 2));
|
|
604
|
+
text.textContent = group;
|
|
605
|
+
g.appendChild(text);
|
|
606
|
+
legendGroup.appendChild(g);
|
|
607
|
+
});
|
|
608
|
+
svg.appendChild(legendGroup);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Adds a title to the SVG
|
|
612
|
+
*/
|
|
613
|
+
addTitle(doc, svg, title, width, font) {
|
|
614
|
+
const ns = svg.namespaceURI;
|
|
615
|
+
const text = doc.createElementNS(ns, 'text');
|
|
616
|
+
text.setAttribute('x', String(width / 2));
|
|
617
|
+
text.setAttribute('y', '25');
|
|
618
|
+
text.setAttribute('text-anchor', 'middle');
|
|
619
|
+
text.setAttribute('font-family', font.family);
|
|
620
|
+
text.setAttribute('font-size', String(font.size + 4));
|
|
621
|
+
text.setAttribute('font-weight', 'bold');
|
|
622
|
+
text.textContent = title;
|
|
623
|
+
svg.appendChild(text);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Helper to safely parse JSON that might already be an object
|
|
627
|
+
*/
|
|
628
|
+
parseJSON(value, paramName) {
|
|
629
|
+
// If it's already an object/array, return it
|
|
630
|
+
if (typeof value === 'object' && value !== null) {
|
|
631
|
+
return value;
|
|
632
|
+
}
|
|
633
|
+
// If it's a string, parse it
|
|
634
|
+
if (typeof value === 'string') {
|
|
635
|
+
try {
|
|
636
|
+
return JSON.parse(value);
|
|
637
|
+
}
|
|
638
|
+
catch (error) {
|
|
639
|
+
throw new Error(`Parameter '${paramName}' contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
// For other types, error
|
|
643
|
+
throw new Error(`Parameter '${paramName}' must be a JSON string or object. Received ${typeof value}.`);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Helper to ensure a parameter value is a string, with type conversion and validation
|
|
647
|
+
*/
|
|
648
|
+
ensureString(value, paramName) {
|
|
649
|
+
if (value == null) {
|
|
650
|
+
return '';
|
|
651
|
+
}
|
|
652
|
+
if (typeof value === 'string') {
|
|
653
|
+
return value;
|
|
654
|
+
}
|
|
655
|
+
// Convert numbers and booleans to strings
|
|
656
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
657
|
+
return String(value);
|
|
658
|
+
}
|
|
659
|
+
// For objects/arrays, reject with descriptive error
|
|
660
|
+
throw new Error(`Parameter '${paramName}' must be a string, number, or boolean. ` +
|
|
661
|
+
`Received ${typeof value}. If providing JSON data, ensure it's passed as a string.`);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Helper to get parameter value by name (case-insensitive)
|
|
665
|
+
*/
|
|
666
|
+
getParamValue(params, paramName) {
|
|
667
|
+
const param = params.Params.find((p) => p.Name.trim().toLowerCase() === paramName.toLowerCase());
|
|
668
|
+
if (param?.Value && typeof param.Value === 'string') {
|
|
669
|
+
return param?.Value?.trim() || null;
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
return param?.Value || null;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
exports.CreateSVGNetworkAction = CreateSVGNetworkAction;
|
|
677
|
+
exports.CreateSVGNetworkAction = CreateSVGNetworkAction = __decorate([
|
|
678
|
+
(0, global_1.RegisterClass)(actions_1.BaseAction, '__CreateSVGNetwork')
|
|
679
|
+
], CreateSVGNetworkAction);
|
|
680
|
+
/**
|
|
681
|
+
* Loader function to ensure the CreateSVGNetworkAction class is included in the bundle.
|
|
682
|
+
*/
|
|
683
|
+
function LoadCreateSVGNetworkAction() {
|
|
684
|
+
// this function is a stub that is used to force the bundler to include the above class in the final bundle and not tree shake them out
|
|
685
|
+
}
|
|
686
|
+
exports.LoadCreateSVGNetworkAction = LoadCreateSVGNetworkAction;
|
|
687
|
+
//# sourceMappingURL=create-svg-network.action.js.map
|