@pb33f/cowboy-components 0.2.1 → 0.2.2
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/components/model-renderer/rendered-node.css.d.ts +2 -0
- package/dist/components/model-renderer/rendered-node.css.js +96 -0
- package/dist/components/model-renderer/rendered-node.d.ts +8 -0
- package/dist/components/model-renderer/rendered-node.js +117 -0
- package/dist/components/model-renderer/rendered-property.css.d.ts +2 -0
- package/dist/components/model-renderer/rendered-property.css.js +118 -0
- package/dist/components/model-renderer/rendered-property.d.ts +14 -0
- package/dist/components/model-renderer/rendered-property.js +204 -0
- package/dist/components/model-tree/tree-item.d.ts +10 -0
- package/dist/components/model-tree/tree-item.js +37 -0
- package/dist/components/model-tree/tree.css.d.ts +2 -0
- package/dist/components/model-tree/tree.css.js +20 -0
- package/dist/components/model-tree/tree.d.ts +16 -0
- package/dist/components/model-tree/tree.js +103 -0
- package/dist/components/the-doctor/the-doctor.d.ts +2 -1
- package/dist/components/the-doctor/the-doctor.js +32 -13
- package/dist/components/visualizer/explorer.d.ts +52 -0
- package/dist/components/visualizer/explorer.js +296 -0
- package/dist/components/visualizer/node.d.ts +11 -0
- package/dist/components/visualizer/node.js +27 -0
- package/dist/components/visualizer/operation.css.d.ts +2 -0
- package/dist/components/visualizer/operation.css.js +53 -0
- package/dist/components/visualizer/operation.d.ts +12 -0
- package/dist/components/visualizer/operation.js +52 -0
- package/dist/components/visualizer/visualizer.css.d.ts +2 -0
- package/dist/components/visualizer/visualizer.css.js +157 -0
- package/dist/components/visualizer/visualizer.d.ts +60 -0
- package/dist/components/visualizer/visualizer.js +137 -0
- package/dist/cowboy-components.d.ts +1 -0
- package/dist/cowboy-components.js +2 -0
- package/dist/cowboy-components.umd.cjs +948 -322
- package/dist/css/pb33f-theme.css +1 -1
- package/dist/events/doctor.d.ts +5 -0
- package/dist/events/doctor.js +2 -0
- package/dist/model/graph.d.ts +6 -0
- package/dist/model/graph.js +1 -0
- package/dist/services/model-service.d.ts +5 -0
- package/dist/services/model-service.js +30 -0
- package/dist/style.css +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import '@shoelace-style/shoelace/dist/components/tree/tree.js';
|
|
8
|
+
import '@shoelace-style/shoelace/dist/components/tree-item/tree-item.js';
|
|
9
|
+
import { customElement, property } from "lit/decorators.js";
|
|
10
|
+
import { html, LitElement } from "lit";
|
|
11
|
+
import treeCss from "./tree.css.js";
|
|
12
|
+
import { ModelTreeNodeClicked } from "../../events/doctor";
|
|
13
|
+
let ModelTree = class ModelTree extends LitElement {
|
|
14
|
+
nodeClicked(nodeHashId) {
|
|
15
|
+
this.dispatchEvent(new CustomEvent(ModelTreeNodeClicked, {
|
|
16
|
+
bubbles: true,
|
|
17
|
+
composed: true,
|
|
18
|
+
detail: {
|
|
19
|
+
nodeHashId: nodeHashId
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
explorerClicked(nodeHashId) {
|
|
24
|
+
const treeItems = this.renderRoot.querySelectorAll(`sl-tree-item`);
|
|
25
|
+
let selected = null;
|
|
26
|
+
for (let i = 0; i < treeItems.length; i++) {
|
|
27
|
+
const item = treeItems[i];
|
|
28
|
+
item.selected = item.id === `model-${nodeHashId}`;
|
|
29
|
+
item.expanded = true;
|
|
30
|
+
if (item.selected) {
|
|
31
|
+
selected = item;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (selected) {
|
|
35
|
+
requestAnimationFrame(() => {
|
|
36
|
+
selected?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
collapse(evt, node) {
|
|
41
|
+
evt.stopPropagation();
|
|
42
|
+
node.treeExpanded = false;
|
|
43
|
+
}
|
|
44
|
+
expanded(evt, node) {
|
|
45
|
+
evt.stopPropagation();
|
|
46
|
+
node.treeExpanded = true;
|
|
47
|
+
}
|
|
48
|
+
buildTree(node, depth) {
|
|
49
|
+
let results = [];
|
|
50
|
+
if (node.nodes && node.nodes.length > 0) {
|
|
51
|
+
for (let i = 0; i < node.nodes.length; i++) {
|
|
52
|
+
depth++;
|
|
53
|
+
results.push(this.buildTree(node.nodes[i], depth));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let expanded = node.treeExpanded;
|
|
57
|
+
if (depth < 2) {
|
|
58
|
+
expanded = true;
|
|
59
|
+
}
|
|
60
|
+
return html `
|
|
61
|
+
<sl-tree-item id="model-${node.idHash}" ?expanded="${expanded}"
|
|
62
|
+
@sl-expand="${(evt) => {
|
|
63
|
+
this.expanded(evt, node);
|
|
64
|
+
}}"
|
|
65
|
+
@sl-collapse="${(evt) => {
|
|
66
|
+
this.collapse(evt, node);
|
|
67
|
+
}}">
|
|
68
|
+
<sl-icon name="plus-square" slot="expand-icon"></sl-icon>
|
|
69
|
+
<sl-icon name="dash-square" slot="collapse-icon"></sl-icon>
|
|
70
|
+
<span >${node.label}</span>
|
|
71
|
+
${results}
|
|
72
|
+
</sl-tree-item>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
nodesSelected(treeItems) {
|
|
76
|
+
for (let i = 0; i < treeItems.length; i++) {
|
|
77
|
+
this.nodeClicked(treeItems[i].id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
render() {
|
|
81
|
+
if (!this.node) {
|
|
82
|
+
return html ``;
|
|
83
|
+
}
|
|
84
|
+
return html `
|
|
85
|
+
<sl-tree @sl-selection-change="${(evt) => {
|
|
86
|
+
{
|
|
87
|
+
const selected = evt.detail.selection;
|
|
88
|
+
this.nodesSelected(selected);
|
|
89
|
+
}
|
|
90
|
+
}}">
|
|
91
|
+
${this.buildTree(this.node, 0)}
|
|
92
|
+
</sl-tree>
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
ModelTree.styles = [treeCss];
|
|
97
|
+
__decorate([
|
|
98
|
+
property()
|
|
99
|
+
], ModelTree.prototype, "node", void 0);
|
|
100
|
+
ModelTree = __decorate([
|
|
101
|
+
customElement("pb33f-model-tree")
|
|
102
|
+
], ModelTree);
|
|
103
|
+
export { ModelTree };
|
|
@@ -7,7 +7,7 @@ import '@shoelace-style/shoelace/dist/components/dialog/dialog.js';
|
|
|
7
7
|
import '@shoelace-style/shoelace/dist/components/alert/alert.js';
|
|
8
8
|
import '@shoelace-style/shoelace/dist/components/badge/badge.js';
|
|
9
9
|
import { LitElement } from "lit";
|
|
10
|
-
import { AddToastEvent, EditorUpdatedEvent, ProblemRuleFilterChangedEvent, RulesetSavedEvent, RuleClickedEvent } from "../../events/doctor.js";
|
|
10
|
+
import { AddToastEvent, EditorUpdatedEvent, ProblemRuleFilterChangedEvent, RulesetSavedEvent, RuleClickedEvent, NodeClickedEvent } from "../../events/doctor.js";
|
|
11
11
|
import { ProblemDrawerEvent } from "../problem-list/details-drawer.js";
|
|
12
12
|
import { SlDialog, SlIcon, SlRadioGroup, SlTab, SlTabGroup } from "@shoelace-style/shoelace";
|
|
13
13
|
import { AttentionBox } from "../attention-box/attention-box.js";
|
|
@@ -87,6 +87,7 @@ export declare class TheDoctor extends LitElement {
|
|
|
87
87
|
private selectedEditorTab;
|
|
88
88
|
private sidebarClosed;
|
|
89
89
|
constructor(doctorEndpoint?: string);
|
|
90
|
+
modelTreeNodeClicked(evt: CustomEvent<NodeClickedEvent>): void;
|
|
90
91
|
exportRuleset(): void;
|
|
91
92
|
addToastEvent(event: CustomEvent<AddToastEvent>): void;
|
|
92
93
|
sendToast(toast: Toast): void;
|
|
@@ -38,6 +38,7 @@ import dialogCss from "../../css/dialog.css.js";
|
|
|
38
38
|
import buttonCss from "../../css/button.css.js";
|
|
39
39
|
import radioGroupsCss from "../../css/radiogroups.css.js";
|
|
40
40
|
import { MarkerSeverity } from "monaco-editor";
|
|
41
|
+
import { ModelService } from "../../services/model-service";
|
|
41
42
|
export const DoctorDocumentBag = "pb33f-doctor-editor";
|
|
42
43
|
export const HowToFixBag = "pb33f-doctor-howtofix";
|
|
43
44
|
export const FunctionDocumentationBag = "pb33f-doctor-funcdocs";
|
|
@@ -112,6 +113,8 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
112
113
|
this.addEventListener(RuleClicked, this.ruleClicked);
|
|
113
114
|
// @ts-ignore
|
|
114
115
|
this.addEventListener(BuiltInRulesetChanged, this.builtInRulesetSelected);
|
|
116
|
+
// @ts-ignore
|
|
117
|
+
//this.addEventListener(ModelTreeNodeClicked, this.modelTreeNodeClicked)
|
|
115
118
|
// hijack navigation buttons.
|
|
116
119
|
window.addEventListener('popstate', (e) => {
|
|
117
120
|
const state = e.state;
|
|
@@ -128,6 +131,10 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
128
131
|
});
|
|
129
132
|
//history.pushState({view: ActiveView.Overview}, "", ActiveView.Overview);
|
|
130
133
|
}
|
|
134
|
+
modelTreeNodeClicked(evt) {
|
|
135
|
+
// TODO: this is a placeholder for now
|
|
136
|
+
console.log(evt);
|
|
137
|
+
}
|
|
131
138
|
exportRuleset() {
|
|
132
139
|
this.exportRulesetDialog.show();
|
|
133
140
|
}
|
|
@@ -283,6 +290,13 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
283
290
|
});
|
|
284
291
|
}
|
|
285
292
|
}
|
|
293
|
+
// update visualization
|
|
294
|
+
// TODO: this is a placeholder for now
|
|
295
|
+
// ModelService.createGraph(value).then((result) => {
|
|
296
|
+
// this.vis
|
|
297
|
+
//
|
|
298
|
+
//
|
|
299
|
+
// })
|
|
286
300
|
}).catch((e) => {
|
|
287
301
|
console.error("statistics service is down", e);
|
|
288
302
|
this.platformUnavailable(e);
|
|
@@ -307,6 +321,8 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
307
321
|
}
|
|
308
322
|
platformUnavailable(error) {
|
|
309
323
|
if (!this.unavailable) {
|
|
324
|
+
this.loadingOverlay.hide();
|
|
325
|
+
this.activitySpinner.hide();
|
|
310
326
|
this.errorBanner.errorTitle = "The doctor is out.";
|
|
311
327
|
if (!error) {
|
|
312
328
|
this.errorBanner.errorMessage = "The clinic is <strong>closed!</strong> " +
|
|
@@ -373,6 +389,7 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
373
389
|
LintingService.doctorEndpoint = this.doctorEndpoint;
|
|
374
390
|
FeedbackService.doctorEndpoint = this.doctorEndpoint;
|
|
375
391
|
RulesetService.doctorEndpoint = this.doctorEndpoint;
|
|
392
|
+
ModelService.doctorEndpoint = this.doctorEndpoint;
|
|
376
393
|
this.docBag = this.bagManager.getBag(DoctorDocumentBag);
|
|
377
394
|
if (this.docBag) {
|
|
378
395
|
const doc = this.docBag.get(DefaultDocument);
|
|
@@ -461,6 +478,7 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
461
478
|
this.sessionRulesetMapBag = this.bagManager.getBag(SessionRulesetMapBag);
|
|
462
479
|
// fire off all network requests, then configure the ruleset management.
|
|
463
480
|
Promise.all(promises).then(() => {
|
|
481
|
+
this.loadingOverlay.hide();
|
|
464
482
|
// configure rule management
|
|
465
483
|
this.manageRuleset.defaultRuleset = this.defaultRuleset;
|
|
466
484
|
this.manageRuleset.owaspRuleset = this.OWASPRuleset;
|
|
@@ -473,17 +491,18 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
473
491
|
else {
|
|
474
492
|
this.manageRuleset.rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
|
|
475
493
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
this.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
494
|
+
setTimeout(() => {
|
|
495
|
+
this.manageRuleset.buildRulesets();
|
|
496
|
+
if (this.CustomRuleset && this.CustomRuleset.rules.size > 0) {
|
|
497
|
+
this.manageRuleset.customRuleset = this.CustomRuleset;
|
|
498
|
+
}
|
|
499
|
+
this.fetchSessionRulesetAsYaml().then((result) => {
|
|
500
|
+
this.rulesetEditor?.setValue(result, true);
|
|
501
|
+
this.fetchRulesetMap();
|
|
502
|
+
}).catch((e) => {
|
|
503
|
+
this.platformUnavailable(e);
|
|
504
|
+
});
|
|
505
|
+
}, 50);
|
|
487
506
|
});
|
|
488
507
|
// refresh state for how to fix.
|
|
489
508
|
this.fetchDocs();
|
|
@@ -537,12 +556,12 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
537
556
|
}
|
|
538
557
|
}
|
|
539
558
|
async fetchSessionRulesetAsYaml() {
|
|
540
|
-
return new Promise(async (resolve) => {
|
|
559
|
+
return new Promise(async (resolve, reject) => {
|
|
541
560
|
RulesetService.getSessionRulesetAsYAML().then((result) => {
|
|
542
561
|
resolve(result);
|
|
543
562
|
}).catch((e) => {
|
|
544
563
|
console.error("cannot fetch session ruleset: ", e.title);
|
|
545
|
-
|
|
564
|
+
reject(e);
|
|
546
565
|
});
|
|
547
566
|
});
|
|
548
567
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import { Direction, Edge, Node } from "./visualizer";
|
|
3
|
+
import { NodeComponent } from "./node";
|
|
4
|
+
export declare class ExplorerComponent extends LitElement {
|
|
5
|
+
static styles: import("lit").CSSResult[];
|
|
6
|
+
svgItem: SVGSVGElement;
|
|
7
|
+
svgGroup: SVGSVGElement;
|
|
8
|
+
ready: boolean;
|
|
9
|
+
elk: any;
|
|
10
|
+
graph: any;
|
|
11
|
+
nodes: Node[];
|
|
12
|
+
models: Node[];
|
|
13
|
+
edges: Edge[];
|
|
14
|
+
direction: Direction;
|
|
15
|
+
nodeComponents: NodeComponent[];
|
|
16
|
+
scale: number;
|
|
17
|
+
private grabbed;
|
|
18
|
+
nodeMap: Map<string, Node>;
|
|
19
|
+
private startX;
|
|
20
|
+
private startY;
|
|
21
|
+
private translateX;
|
|
22
|
+
private translateY;
|
|
23
|
+
constructor();
|
|
24
|
+
mouseMove(evt: MouseEvent): void;
|
|
25
|
+
mouseDown(evt: MouseEvent): void;
|
|
26
|
+
mouseUp(): void;
|
|
27
|
+
onWheel(evt: MouseEvent): void;
|
|
28
|
+
buildLayout(): void;
|
|
29
|
+
buildGraph(): any;
|
|
30
|
+
readyGo(): void;
|
|
31
|
+
reset(): void;
|
|
32
|
+
zoomIn(): void;
|
|
33
|
+
zoomOut(): void;
|
|
34
|
+
generateOptions(): {
|
|
35
|
+
'spacing.nodeNodeBetweenLayers': number;
|
|
36
|
+
'spacing.nodeNode': number;
|
|
37
|
+
'elk.nodeLabels.placement': string;
|
|
38
|
+
'elk.algorithm': string;
|
|
39
|
+
'elk.direction': Direction;
|
|
40
|
+
'org.eclipse.elk.edgeRouting': string;
|
|
41
|
+
'elk.layered.unnecessaryBendpoints': string;
|
|
42
|
+
'elk.layered.spacing.edgeNodeBetweenLayers': number;
|
|
43
|
+
'org.eclipse.elk.layered.nodePlacement.bk.fixedAlignment': string;
|
|
44
|
+
'org.eclipse.elk.layered.cycleBreaking.strategy': string;
|
|
45
|
+
'nodePlacement.strategy': string;
|
|
46
|
+
'org.eclipse.elk.spacing.edgeLabel': string;
|
|
47
|
+
'org.eclipse.elk.spacing.edgeNode': string;
|
|
48
|
+
'org.eclipse.elk.layered.edgeLabels.sideSelection': string;
|
|
49
|
+
'org.eclipse.elk.spacing.portPort': string;
|
|
50
|
+
};
|
|
51
|
+
render(): import("lit-html").TemplateResult<1> | import("lit-html").TemplateResult<2>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { customElement, query, state } from "lit/decorators.js";
|
|
8
|
+
import { html, LitElement, svg } from "lit";
|
|
9
|
+
import visualizerCss from "./visualizer.css";
|
|
10
|
+
import { Direction } from "./visualizer";
|
|
11
|
+
import { NodeComponent } from "./node";
|
|
12
|
+
import { OperationGraphNode } from "./operation";
|
|
13
|
+
import { curveBundle, line } from "d3-shape";
|
|
14
|
+
import ELK from "elkjs/lib/elk.bundled";
|
|
15
|
+
let ExplorerComponent = class ExplorerComponent extends LitElement {
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.nodeComponents = [];
|
|
19
|
+
this.scale = 1;
|
|
20
|
+
this.translateX = 0;
|
|
21
|
+
this.translateY = 0;
|
|
22
|
+
this.elk = new ELK();
|
|
23
|
+
this.ready = false;
|
|
24
|
+
this.direction = Direction.RIGHT;
|
|
25
|
+
this.nodeMap = new Map();
|
|
26
|
+
const targets = new Map();
|
|
27
|
+
}
|
|
28
|
+
mouseMove(evt) {
|
|
29
|
+
if (this.grabbed) {
|
|
30
|
+
this.translateX = evt.clientX - this.startX;
|
|
31
|
+
this.translateY = evt.clientY - this.startY;
|
|
32
|
+
this.svgGroup.style.transform = `scale(${this.scale}) translate(${this.translateX / this.scale}px, ${this.translateY / this.scale}px)`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
mouseDown(evt) {
|
|
36
|
+
this.grabbed = true;
|
|
37
|
+
this.startX = evt.clientX - this.translateX;
|
|
38
|
+
this.startY = evt.clientY - this.translateY;
|
|
39
|
+
}
|
|
40
|
+
mouseUp() {
|
|
41
|
+
this.grabbed = false;
|
|
42
|
+
}
|
|
43
|
+
onWheel(evt) {
|
|
44
|
+
evt.preventDefault();
|
|
45
|
+
//@ts-ignore
|
|
46
|
+
const delta = evt.deltaY || evt.deltaX;
|
|
47
|
+
const scaleStep = Math.abs(delta) < 50
|
|
48
|
+
? 0.05 // touchpad pitch
|
|
49
|
+
: 0.25; // mouse wheel
|
|
50
|
+
const scaleDelta = delta < 0 ? scaleStep : -scaleStep;
|
|
51
|
+
const nextScale = this.scale + scaleDelta; // 'scale' is prev scale
|
|
52
|
+
// calc fixedPoint
|
|
53
|
+
const fixedPoint = { x: evt.clientX, y: evt.clientY };
|
|
54
|
+
this.scale = nextScale;
|
|
55
|
+
if (nextScale < 0.25) {
|
|
56
|
+
this.scale = 0.25;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// if (nextScale > 5) {
|
|
60
|
+
// this.scale = 5;
|
|
61
|
+
// return
|
|
62
|
+
// }
|
|
63
|
+
const mouseX = evt.clientX;
|
|
64
|
+
const mouseY = evt.clientY;
|
|
65
|
+
const svgRect = this.svgItem.getBoundingClientRect();
|
|
66
|
+
const offsetX = mouseX - svgRect.left;
|
|
67
|
+
const offsetY = mouseY - svgRect.top;
|
|
68
|
+
this.svgGroup.style.transformOrigin = `${offsetX}px ${offsetY}px`;
|
|
69
|
+
this.svgGroup.style.transform = `scale(${nextScale}) translate(${this.translateX / this.scale}px, ${this.translateY / this.scale}px)`;
|
|
70
|
+
}
|
|
71
|
+
buildLayout() {
|
|
72
|
+
this.elk.layout(this.graph, {
|
|
73
|
+
layoutOptions: {
|
|
74
|
+
'algorithm': 'layered'
|
|
75
|
+
},
|
|
76
|
+
logging: true,
|
|
77
|
+
measureExecutionTime: true
|
|
78
|
+
}).then(this.readyGo.bind(this));
|
|
79
|
+
}
|
|
80
|
+
buildGraph() {
|
|
81
|
+
const graph = {
|
|
82
|
+
id: "root",
|
|
83
|
+
layoutOptions: this.generateOptions(),
|
|
84
|
+
children: this.nodes,
|
|
85
|
+
edges: this.edges
|
|
86
|
+
};
|
|
87
|
+
this.graph = graph;
|
|
88
|
+
// build node map
|
|
89
|
+
this.nodeMap.clear();
|
|
90
|
+
this.nodes.forEach((node) => {
|
|
91
|
+
this.nodeMap.set(node.nodePath, node);
|
|
92
|
+
});
|
|
93
|
+
this.buildLayout();
|
|
94
|
+
return graph;
|
|
95
|
+
}
|
|
96
|
+
readyGo() {
|
|
97
|
+
this.ready = true;
|
|
98
|
+
this.requestUpdate();
|
|
99
|
+
}
|
|
100
|
+
reset() {
|
|
101
|
+
this.scale = 1;
|
|
102
|
+
this.translateX = 0;
|
|
103
|
+
this.translateY = 0;
|
|
104
|
+
this.svgGroup.style.transform = `scale(${this.scale}) translate(${this.translateX}px, ${this.translateY}px)`;
|
|
105
|
+
}
|
|
106
|
+
zoomIn() {
|
|
107
|
+
const nextScale = this.scale + 0.25; // 'scale' is prev scale
|
|
108
|
+
this.scale = nextScale;
|
|
109
|
+
this.svgGroup.style.transform = `scale(${nextScale}) translate(${this.translateX / this.scale}px, ${this.translateY / this.scale}px)`;
|
|
110
|
+
}
|
|
111
|
+
zoomOut() {
|
|
112
|
+
const nextScale = this.scale - 0.25; // 'scale' is prev scale
|
|
113
|
+
this.scale = nextScale;
|
|
114
|
+
this.svgGroup.style.transform = `scale(${nextScale}) translate(${this.translateX / this.scale}px, ${this.translateY / this.scale}px)`;
|
|
115
|
+
}
|
|
116
|
+
generateOptions() {
|
|
117
|
+
return {
|
|
118
|
+
'spacing.nodeNodeBetweenLayers': 40,
|
|
119
|
+
'spacing.nodeNode': 40,
|
|
120
|
+
'elk.nodeLabels.placement': 'INSIDE V_CENTER H_RIGHT',
|
|
121
|
+
'elk.algorithm': 'org.eclipse.elk.layered',
|
|
122
|
+
'elk.direction': this.direction,
|
|
123
|
+
'org.eclipse.elk.edgeRouting': 'ORTHOGONAL',
|
|
124
|
+
'elk.layered.unnecessaryBendpoints': 'true',
|
|
125
|
+
'elk.layered.spacing.edgeNodeBetweenLayers': 30,
|
|
126
|
+
'org.eclipse.elk.layered.nodePlacement.bk.fixedAlignment': 'BALANCED',
|
|
127
|
+
'org.eclipse.elk.layered.cycleBreaking.strategy': 'DEPTH_FIRST',
|
|
128
|
+
'nodePlacement.strategy': 'BRANDES_KOEPF',
|
|
129
|
+
'org.eclipse.elk.spacing.edgeLabel': '0',
|
|
130
|
+
'org.eclipse.elk.spacing.edgeNode': '24',
|
|
131
|
+
'org.eclipse.elk.layered.edgeLabels.sideSelection': 'ALWAYS_UP',
|
|
132
|
+
'org.eclipse.elk.spacing.portPort': '10',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
render() {
|
|
136
|
+
if (!this.ready) {
|
|
137
|
+
return html ``;
|
|
138
|
+
}
|
|
139
|
+
const nodes = this.graph.children?.map((child) => {
|
|
140
|
+
const nc = new NodeComponent();
|
|
141
|
+
nc.id = child.idHash;
|
|
142
|
+
if (child.x && child.y) {
|
|
143
|
+
nc.x = child.x;
|
|
144
|
+
nc.y = child.y;
|
|
145
|
+
}
|
|
146
|
+
nc.width = child.width;
|
|
147
|
+
nc.height = child.height;
|
|
148
|
+
// if (child.expanded) {
|
|
149
|
+
// nc.visible = child.expanded;
|
|
150
|
+
// } else {
|
|
151
|
+
//debugger
|
|
152
|
+
let expanded = false;
|
|
153
|
+
// check if any of the edges have a target of this node, and then check
|
|
154
|
+
// if any of the source nodes are expanded
|
|
155
|
+
this.edges?.forEach((edge) => {
|
|
156
|
+
if (edge.targets.includes(child.id)) {
|
|
157
|
+
edge.sources.forEach((source) => {
|
|
158
|
+
const node = this.nodes.find((n) => n.id === source);
|
|
159
|
+
if (node?.expanded) {
|
|
160
|
+
expanded = true;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
nc.visible = expanded;
|
|
166
|
+
// }
|
|
167
|
+
const op = new OperationGraphNode();
|
|
168
|
+
op.height = child.height - 2;
|
|
169
|
+
op.width = child.width - 2;
|
|
170
|
+
op.id = child.idHash;
|
|
171
|
+
op.label = child.label;
|
|
172
|
+
if (child.active) {
|
|
173
|
+
op.active = child.active;
|
|
174
|
+
nc.active = child.active;
|
|
175
|
+
}
|
|
176
|
+
nc.body = op;
|
|
177
|
+
this.nodeComponents.push(nc);
|
|
178
|
+
return nc.render();
|
|
179
|
+
});
|
|
180
|
+
const edges = this.graph.edges?.map((edge) => {
|
|
181
|
+
let x = 0;
|
|
182
|
+
const sections = edge.sections?.map((section) => {
|
|
183
|
+
// check if any of the targets for the edge are visible, if not, don't render the edge
|
|
184
|
+
let visible = false;
|
|
185
|
+
edge.targets.forEach((target) => {
|
|
186
|
+
const node = this.nodes.find((n) => n.id === target);
|
|
187
|
+
if (node?.expanded) {
|
|
188
|
+
visible = true;
|
|
189
|
+
}
|
|
190
|
+
this.nodeComponents.forEach((nc) => {
|
|
191
|
+
if (nc.visible && nc.id === target) {
|
|
192
|
+
console.log(nc.id);
|
|
193
|
+
visible = true;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
// if (!visible) {
|
|
198
|
+
// return svg``
|
|
199
|
+
// }
|
|
200
|
+
const points = section ? [section.startPoint, ...(section.bendPoints || []), section.endPoint] : [];
|
|
201
|
+
let pathFn = line().x((d) => d.x).y((d) => d.y);
|
|
202
|
+
pathFn = pathFn.curve(curveBundle.beta(1));
|
|
203
|
+
const lines = svg `
|
|
204
|
+
<path id="edge-${edge.id}-${x}"
|
|
205
|
+
d="${pathFn(points)}"
|
|
206
|
+
class="edge ${edge.ref.length > 0 ? 'ref' : ''} ${edge.poly && edge.poly != '' ? edge.poly : ''}"
|
|
207
|
+
marker-end="url(#${edge.ref.length > 0 ? edge.poly ? 'arrow-poly' : 'arrow-ref' : 'arrow'})"/>`;
|
|
208
|
+
x++;
|
|
209
|
+
return lines;
|
|
210
|
+
});
|
|
211
|
+
return sections;
|
|
212
|
+
});
|
|
213
|
+
let base = 600;
|
|
214
|
+
let offset = 0;
|
|
215
|
+
this.graph.children.forEach(() => {
|
|
216
|
+
base += 5;
|
|
217
|
+
offset += 20;
|
|
218
|
+
});
|
|
219
|
+
if (offset > 900) {
|
|
220
|
+
offset = 900;
|
|
221
|
+
}
|
|
222
|
+
return svg `
|
|
223
|
+
<svg width="100%" height="100%" viewBox="${offset} 80 ${base} ${base}"
|
|
224
|
+
@wheel="${this.onWheel}"
|
|
225
|
+
@mousedown="${this.mouseDown}"
|
|
226
|
+
@mouseup="${this.mouseUp}"
|
|
227
|
+
@mousemove="${this.mouseMove}"
|
|
228
|
+
@mouseout="${this.mouseUp}"
|
|
229
|
+
>
|
|
230
|
+
<defs>
|
|
231
|
+
<filter id="glow">
|
|
232
|
+
<!-- First, apply a Gaussian blur -->
|
|
233
|
+
<feGaussianBlur stdDeviation="4.5" result="coloredBlur"/>
|
|
234
|
+
<!-- Then, apply a merge filter to add the blur effect back with the original graphic -->
|
|
235
|
+
<feMerge>
|
|
236
|
+
<feMergeNode in="coloredBlur"/>
|
|
237
|
+
<feMergeNode in="SourceGraphic"/>
|
|
238
|
+
</feMerge>
|
|
239
|
+
</filter>
|
|
240
|
+
<marker
|
|
241
|
+
id="arrow"
|
|
242
|
+
viewBox="0 0 12 12"
|
|
243
|
+
refX="8"
|
|
244
|
+
refY="5"
|
|
245
|
+
markerWidth="5"
|
|
246
|
+
markerHeight="5"
|
|
247
|
+
fill="var(--secondary-color)"
|
|
248
|
+
orient="auto-start-reverse">
|
|
249
|
+
<path d="M 0 0 L 10 5 L 0 10 z" class="glow"/>
|
|
250
|
+
</marker>
|
|
251
|
+
<marker
|
|
252
|
+
id="arrow-ref"
|
|
253
|
+
viewBox="0 0 12 12"
|
|
254
|
+
refX="8"
|
|
255
|
+
refY="5"
|
|
256
|
+
markerWidth="5"
|
|
257
|
+
markerHeight="5"
|
|
258
|
+
fill="var(--terminal-text)"
|
|
259
|
+
orient="auto-start-reverse">
|
|
260
|
+
<path d="M 0 0 L 10 5 L 0 10 z" class="glow"/>
|
|
261
|
+
</marker>
|
|
262
|
+
<marker
|
|
263
|
+
id="arrow-poly"
|
|
264
|
+
viewBox="0 0 12 12"
|
|
265
|
+
refX="8"
|
|
266
|
+
refY="5"
|
|
267
|
+
markerWidth="5"
|
|
268
|
+
markerHeight="5"
|
|
269
|
+
fill="var(--terminal-yellow)"
|
|
270
|
+
orient="auto-start-reverse">
|
|
271
|
+
<path d="M 0 0 L 10 5 L 0 10 z" class="glow"/>
|
|
272
|
+
</marker>
|
|
273
|
+
|
|
274
|
+
</defs>
|
|
275
|
+
<g id="#svgGroup">
|
|
276
|
+
${nodes}
|
|
277
|
+
${edges}
|
|
278
|
+
</g>
|
|
279
|
+
</svg>
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
ExplorerComponent.styles = [visualizerCss];
|
|
284
|
+
__decorate([
|
|
285
|
+
query('svg')
|
|
286
|
+
], ExplorerComponent.prototype, "svgItem", void 0);
|
|
287
|
+
__decorate([
|
|
288
|
+
query('svg > g')
|
|
289
|
+
], ExplorerComponent.prototype, "svgGroup", void 0);
|
|
290
|
+
__decorate([
|
|
291
|
+
state()
|
|
292
|
+
], ExplorerComponent.prototype, "ready", void 0);
|
|
293
|
+
ExplorerComponent = __decorate([
|
|
294
|
+
customElement('pb33f-explorer')
|
|
295
|
+
], ExplorerComponent);
|
|
296
|
+
export { ExplorerComponent };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { svg } from "lit";
|
|
2
|
+
export class NodeComponent {
|
|
3
|
+
render() {
|
|
4
|
+
// if (!this.visible) {
|
|
5
|
+
// return svg``;
|
|
6
|
+
// }
|
|
7
|
+
let body = "";
|
|
8
|
+
if (this.body) {
|
|
9
|
+
body = this.body;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
body = "Object Node";
|
|
13
|
+
}
|
|
14
|
+
// <!--<text x="${this.x + 6}" y="${this.y + 26}" class="text">${body}</text> -->
|
|
15
|
+
return svg `
|
|
16
|
+
<rect id="node-${this.id}" x="${this.x}" y="${this.y}" width="${this.width}" height="${this.height}" class="node"/>
|
|
17
|
+
|
|
18
|
+
<foreignObject x="${this.x}" y="${this.y}" width="${this.width}" height="${this.height + 20}" class="fo">
|
|
19
|
+
<div xmlns="http://www.w3.org/1999/xhtml" class="node-body" style="height: ${this.height}px; width: ${this.width}px;">
|
|
20
|
+
${body}
|
|
21
|
+
</div>
|
|
22
|
+
</foreignObject>
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export default css `
|
|
3
|
+
|
|
4
|
+
.operation-node {
|
|
5
|
+
border: 1px solid var(--primary-color);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.operation-node:hover {
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
border: 1px solid var(--secondary-color);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.operation-node:active {
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
border: 1px solid var(--warn-color);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.active {
|
|
19
|
+
border: 2px solid var(--error-color);
|
|
20
|
+
animation: pulse-animation 2.5s infinite
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.operation-node.active:hover {
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
border: 2px solid var(--error-color);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes pulse-animation {
|
|
29
|
+
0% {
|
|
30
|
+
box-shadow: 0 0 0 0 var(--error-color);
|
|
31
|
+
}
|
|
32
|
+
100% {
|
|
33
|
+
box-shadow: 0 0 30px 30px rgb(0, 0, 0, 0);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@keyframes dashdraw {
|
|
38
|
+
0% {
|
|
39
|
+
stroke-dashoffset: 10;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.active-icon {
|
|
44
|
+
position: absolute;
|
|
45
|
+
right: calc(50% - 10px);
|
|
46
|
+
bottom: -8px;
|
|
47
|
+
font-size: 1.5rem;
|
|
48
|
+
color: var(--error-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
`;
|