@pb33f/cowboy-components 0.7.5 → 0.7.6
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/auth/login-button.d.ts +2 -0
- package/dist/components/auth/login-button.js +15 -3
- package/dist/components/auth/login-panel.js +1 -1
- package/dist/components/auth/oauth-login.d.ts +1 -0
- package/dist/components/auth/oauth-login.js +11 -5
- package/dist/components/editor/editor-breadcrumb.css.js +1 -1
- package/dist/components/model-renderer/rendered-node.d.ts +2 -0
- package/dist/components/model-renderer/rendered-node.js +18 -0
- package/dist/components/model-renderer/responses.d.ts +11 -0
- package/dist/components/model-renderer/responses.js +46 -0
- package/dist/components/model-tree/tree.js +1 -1
- package/dist/components/rodeo/rodeo.js +1 -1
- package/dist/components/the-doctor/the-doctor.css.js +1 -1
- package/dist/components/the-doctor/the-doctor.d.ts +112 -120
- package/dist/components/the-doctor/the-doctor.js +134 -1735
- package/dist/components/the-doctor/upload-archive.d.ts +1 -0
- package/dist/components/the-doctor/upload-archive.js +29 -12
- package/dist/controllers/auth-controller.d.ts +25 -0
- package/dist/controllers/auth-controller.js +154 -0
- package/dist/controllers/broker-controller.d.ts +22 -0
- package/dist/controllers/broker-controller.js +107 -0
- package/dist/controllers/diagnostic-controller.d.ts +6 -0
- package/dist/controllers/diagnostic-controller.js +262 -0
- package/dist/controllers/docs-controller.d.ts +8 -0
- package/dist/controllers/docs-controller.js +143 -0
- package/dist/controllers/model-controller.d.ts +8 -0
- package/dist/controllers/model-controller.js +87 -0
- package/dist/controllers/node-clicker-controller.d.ts +11 -0
- package/dist/controllers/node-clicker-controller.js +362 -0
- package/dist/controllers/problem-controller.d.ts +7 -0
- package/dist/controllers/problem-controller.js +46 -0
- package/dist/controllers/rolodex-controller.d.ts +10 -0
- package/dist/controllers/rolodex-controller.js +126 -0
- package/dist/controllers/rule-controller.d.ts +19 -0
- package/dist/controllers/rule-controller.js +264 -0
- package/dist/controllers/spec-controller.d.ts +8 -0
- package/dist/controllers/spec-controller.js +78 -0
- package/dist/controllers/state-controller.d.ts +9 -0
- package/dist/controllers/state-controller.js +279 -0
- package/dist/cowboy-components.umd.cjs +1152 -1121
- package/dist/css/shared.css.js +5 -0
- package/dist/events/doctor.d.ts +10 -0
- package/dist/events/doctor.js +2 -0
- package/dist/model/api-response.d.ts +7 -0
- package/dist/model/api-response.js +2 -0
- package/dist/services/auth-service.d.ts +1 -0
- package/dist/services/auth-service.js +28 -0
- package/dist/services/linting-service.js +11 -2
- package/dist/services/model-service.d.ts +2 -1
- package/dist/services/model-service.js +31 -5
- package/package.json +1 -1
- package/dist/controllers/auth.d.ts +0 -20
- package/dist/controllers/auth.js +0 -101
|
@@ -16,12 +16,11 @@ import '@shoelace-style/shoelace/dist/components/avatar/avatar.js';
|
|
|
16
16
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
17
17
|
import { html, LitElement } from "lit";
|
|
18
18
|
import { SpecEditor } from "../editor/editor.js";
|
|
19
|
-
import { ActiveView, AddToast, ArchiveURLRequested, BuiltInRulesetChanged, CustomRulesetEnabled, DocumentReferenceClicked, EditorClicked, EditorUpdated, ExplorerEqualizerChanged, ExplorerEqualizerFiltered, ExplorerNodeClicked, ExportRuleset, LoadRenderedNodeIntoInspector, ModelTreeNodeClicked, NodeReferenceClicked, NukeWorkspaceEvent, OpenProblemDrawer, OpenSettings, ProblemClicked,
|
|
20
|
-
import { ProblemDetailsDrawer
|
|
19
|
+
import { ActiveView, AddToast, ArchiveURLRequested, BuiltInRulesetChanged, CustomRulesetEnabled, DocumentReferenceClicked, EditorClicked, EditorUpdated, ExplorerEqualizerChanged, ExplorerEqualizerFiltered, ExplorerNodeClicked, ExportRuleset, LoadRenderedNodeIntoInspector, ModelTreeNodeClicked, NodeReferenceClicked, NukeWorkspaceEvent, OpenProblemDrawer, OpenSettings, ProblemClicked, RolodexRootFileSelected, RolodexTreeNodeClicked, RuleClicked, RulesetSaved, RuleViolationClicked, StartSessionFailed, } from "../../events/doctor.js";
|
|
20
|
+
import { ProblemDetailsDrawer } from "../problem-list/details-drawer.js";
|
|
21
21
|
import { CreateBagManager } from "@pb33f/saddlebag";
|
|
22
22
|
import { LintingService } from "../../services/linting-service.js";
|
|
23
23
|
import { ProblemList } from "../problem-list/problem-list.js";
|
|
24
|
-
import { Problem } from "../../model/problem.js";
|
|
25
24
|
import { ProblemsOverview } from "../problems-overview/problems-overview.js";
|
|
26
25
|
import { ErrorBanner } from "../error-banner/error-banner.js";
|
|
27
26
|
import { StatusBar } from "./status-bar.js";
|
|
@@ -38,29 +37,35 @@ import { ToastType } from "../../model/toast.js";
|
|
|
38
37
|
import dialogCss from "../../css/dialog.css.js";
|
|
39
38
|
import buttonCss from "../../css/button.css.js";
|
|
40
39
|
import radioGroupsCss from "../../css/radiogroups.css.js";
|
|
41
|
-
import { MarkerSeverity } from "monaco-editor";
|
|
42
40
|
import { ModelService } from "../../services/model-service.js";
|
|
43
|
-
import { SearchNodeTreeForPath } from "../../model/graph.js";
|
|
44
41
|
import { ModelTree } from "../model-tree/tree.js";
|
|
45
42
|
import { ExplorerComponent } from "../visualizer/explorer.js";
|
|
46
43
|
import { RenderedNodeComponent } from "../model-renderer/rendered-node.js";
|
|
47
44
|
import tabsCss from "../../css/tabs.css.js";
|
|
48
45
|
import { CreateBus } from "@pb33f/ranch";
|
|
49
|
-
import { Command, CreditStreamChannel, DoctorServiceChannel, isBrokerResponse, QueuePrefix, SpecStreamChannel } from "../../model/channels.js";
|
|
50
46
|
import formsCss from "../../css/forms.css.js";
|
|
51
47
|
import spinnerCss from "../../css/spinner.css.js";
|
|
52
48
|
import { UploadArchiveComponent } from "./upload-archive.js";
|
|
53
|
-
import { NodeType } from "../../model/node_type.js";
|
|
54
49
|
import tooltipCss from "../../css/tooltip.css.js";
|
|
55
50
|
import { NukeWorkspaceComponent } from "./nuke-workspace.js";
|
|
56
51
|
import { CreditTicker } from "../credit-ticker/credit-ticker.js";
|
|
57
|
-
import { AuthController } from "../../controllers/auth
|
|
52
|
+
import { AuthController } from "../../controllers/auth-controller";
|
|
58
53
|
import { AuthService } from "../../services/auth-service.js";
|
|
59
54
|
import { TimeVortex } from "../time-vortex/time-vortex.js";
|
|
60
55
|
import { TimelineService } from "../../services/timeline-service.js";
|
|
61
56
|
import { DoctorSettings } from "./settings.js";
|
|
62
57
|
import panelsCss from "../../css/panels.css.js";
|
|
63
|
-
import nukeCss from "../../css/nuke.css";
|
|
58
|
+
import nukeCss from "../../css/nuke.css.js";
|
|
59
|
+
import { NodeClickerController } from '../../controllers/node-clicker-controller.js';
|
|
60
|
+
import { BrokerController } from '../../controllers/broker-controller.js';
|
|
61
|
+
import { RolodexController } from '../../controllers/rolodex-controller.js';
|
|
62
|
+
import { SpecController } from '../../controllers/spec-controller.js';
|
|
63
|
+
import { RuleController } from '../../controllers/rule-controller.js';
|
|
64
|
+
import { ProblemController } from '../../controllers/problem-controller.js';
|
|
65
|
+
import { DocsController } from '../../controllers/docs-controller.js';
|
|
66
|
+
import { ModelController } from '../../controllers/model-controller.js';
|
|
67
|
+
import { DiagnosticController } from '../../controllers/diagnostic-controller.js';
|
|
68
|
+
import { StateController } from '../../controllers/state-controller.js';
|
|
64
69
|
export const GraphBag = "pb33f-doctor-graph";
|
|
65
70
|
export const PanelStateBag = "pb33f-doctor-panel-state";
|
|
66
71
|
export const RolodexResponseBag = "pb33f-doctor-rolodex-response";
|
|
@@ -91,10 +96,9 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
91
96
|
this.debounceTime = 1000;
|
|
92
97
|
this.debounceTimeRuleset = 900;
|
|
93
98
|
this.bounceId = 0;
|
|
94
|
-
this.
|
|
99
|
+
this.firstRun = true;
|
|
95
100
|
// rolodex divider state (because it may not exist)
|
|
96
101
|
this.rolodexDividerPosition = 40;
|
|
97
|
-
this._firstRun = true;
|
|
98
102
|
// extract the doctor endpoint from session storage.
|
|
99
103
|
const sessionEndpoint = sessionStorage.getItem(DoctorEndpoint);
|
|
100
104
|
if (sessionEndpoint) {
|
|
@@ -110,21 +114,23 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
110
114
|
AuthService.doctorEndpoint = this.doctorEndpoint;
|
|
111
115
|
TimelineService.doctorEndpoint = this.doctorEndpoint;
|
|
112
116
|
this.timeVortex = new TimeVortex();
|
|
113
|
-
//this.authController = new AuthController(this)
|
|
114
117
|
// bus it up
|
|
115
118
|
this.bus = CreateBus();
|
|
116
|
-
this.doctorServiceChannel = this.bus.createChannel(DoctorServiceChannel);
|
|
117
|
-
this.specStreamChannel = this.bus.createChannel(SpecStreamChannel);
|
|
118
|
-
this.creditStreamChannel = this.bus.createChannel(CreditStreamChannel);
|
|
119
|
-
this.bus.mapChannelToBrokerDestination(QueuePrefix + DoctorServiceChannel, DoctorServiceChannel);
|
|
120
|
-
// this.bus.mapChannelToBrokerDestination(QueuePrefix + SpecStreamChannel, SpecStreamChannel);
|
|
121
|
-
// this.bus.mapChannelToBrokerDestination(QueuePrefix + CreditStreamChannel, CreditStreamChannel);
|
|
122
|
-
this.doctorChannelSubscription = this.doctorServiceChannel.subscribe(this.doctorServiceHandler());
|
|
123
|
-
// this.specChannelSubscription = this.specStreamChannel.subscribe(this.specStreamHandler());
|
|
124
|
-
// this.creditChannelSubscription = this.creditStreamChannel.subscribe(this.creditStreamHandler());
|
|
125
|
-
// create a stateful bag manager
|
|
126
119
|
this.bagManager = CreateBagManager(true);
|
|
127
|
-
this.
|
|
120
|
+
this.graphBag = this.bagManager.getBag(GraphBag);
|
|
121
|
+
this.docBag = this.bagManager.getBag(DoctorDocumentBag);
|
|
122
|
+
this.rolodexResponseBag = this.bagManager.getBag(RolodexResponseBag);
|
|
123
|
+
this.rolodexFilesBag = this.bagManager.getBag(RolodexFilesBag);
|
|
124
|
+
this.rolodexStateBag = this.bagManager.getBag(RolodexStateBag);
|
|
125
|
+
this.referenceMapBag = this.bagManager.getBag(ReferenceMapBag);
|
|
126
|
+
this.docExpirationBag = this.bagManager.getBag(DocumentationExpirationBag);
|
|
127
|
+
this.panelStateBag = this.bagManager.getBag(PanelStateBag);
|
|
128
|
+
this.settingsBag = this.bagManager.getBag(SettingsBag);
|
|
129
|
+
// create a stateful bag manager
|
|
130
|
+
this.modelController = new ModelController(this);
|
|
131
|
+
this.stateController = new StateController(this);
|
|
132
|
+
// boot state.
|
|
133
|
+
this.bagManager.loadStatefulBags().then(this.stateController.loadState.bind(this.stateController));
|
|
128
134
|
this.editor = new SpecEditor();
|
|
129
135
|
this.uploadArchive = new UploadArchiveComponent();
|
|
130
136
|
this.nukeWorkspace = new NukeWorkspaceComponent();
|
|
@@ -141,6 +147,15 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
141
147
|
this.manageRuleset = new ManageRuleset();
|
|
142
148
|
this.toastManager = new ToastManager();
|
|
143
149
|
this.creditTicker = new CreditTicker();
|
|
150
|
+
// roll the controllers!
|
|
151
|
+
this.nodeClickerController = new NodeClickerController(this);
|
|
152
|
+
this.brokerController = new BrokerController(this);
|
|
153
|
+
this.rolodexController = new RolodexController(this);
|
|
154
|
+
this.specController = new SpecController(this);
|
|
155
|
+
this.ruleController = new RuleController(this);
|
|
156
|
+
this.problemController = new ProblemController(this);
|
|
157
|
+
this.docsController = new DocsController(this);
|
|
158
|
+
this.diagnosticController = new DiagnosticController(this);
|
|
144
159
|
this.settingsComponent = new DoctorSettings();
|
|
145
160
|
this.editorMap = new Map();
|
|
146
161
|
this.editorMap.set("spec", this.editor);
|
|
@@ -172,7 +187,6 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
172
187
|
this.minimapIconVisible = true;
|
|
173
188
|
this.showDiagnosisButton = false;
|
|
174
189
|
this.nodeLimit = 150;
|
|
175
|
-
this.randomTicker = 0;
|
|
176
190
|
// session call back for when we're online.
|
|
177
191
|
const sessionCallback = (session) => {
|
|
178
192
|
if (session.creditsRemaining) {
|
|
@@ -182,72 +196,66 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
182
196
|
this.creditTicker.credits = session.creditsRemaining;
|
|
183
197
|
}
|
|
184
198
|
this.creditTicker.visible = true;
|
|
185
|
-
this.connectToBroker();
|
|
199
|
+
this.brokerController.connectToBroker();
|
|
186
200
|
};
|
|
187
201
|
// create auth controller
|
|
188
202
|
this.authController = new AuthController(this, sessionCallback, true);
|
|
203
|
+
// listen for auth state changes.
|
|
189
204
|
//@ts-ignore
|
|
190
|
-
this.addEventListener(EditorUpdated, this.specChanged);
|
|
205
|
+
this.addEventListener(EditorUpdated, this.specController.specChanged.bind(this.specController));
|
|
191
206
|
//@ts-ignore
|
|
192
|
-
this.addEventListener(EditorClicked, this.specClicked);
|
|
207
|
+
this.addEventListener(EditorClicked, this.specController.specClicked.bind(this.specController));
|
|
193
208
|
//@ts-ignore
|
|
194
|
-
this.addEventListener(ProblemClicked, this.problemClicked);
|
|
209
|
+
this.addEventListener(ProblemClicked, this.problemController.problemClicked.bind(this.problemController));
|
|
195
210
|
// @ts-ignore
|
|
196
|
-
this.addEventListener(OpenProblemDrawer, this.ruleDocsClicked);
|
|
211
|
+
this.addEventListener(OpenProblemDrawer, this.docsController.ruleDocsClicked.bind(this.docsController));
|
|
197
212
|
// @ts-ignore
|
|
198
|
-
this.addEventListener(RuleViolationClicked, this.ruleGroupClicked);
|
|
213
|
+
this.addEventListener(RuleViolationClicked, this.ruleController.ruleGroupClicked.bind(this.ruleController));
|
|
199
214
|
// @ts-ignore
|
|
200
|
-
this.addEventListener(CustomRulesetEnabled, this.customRulesetEnabled);
|
|
215
|
+
this.addEventListener(CustomRulesetEnabled, this.ruleController.customRulesetEnabled.bind(this.ruleController));
|
|
201
216
|
// @ts-ignore
|
|
202
|
-
this.addEventListener(RulesetSaved, this.rulesetSaved);
|
|
217
|
+
this.addEventListener(RulesetSaved, this.ruleController.rulesetSaved.bind(this.ruleController));
|
|
203
218
|
// @ts-ignore
|
|
204
219
|
this.addEventListener(AddToast, this.addToastEvent);
|
|
205
220
|
this.addEventListener(ExportRuleset, this.exportRuleset);
|
|
206
221
|
// @ts-ignore
|
|
207
|
-
this.addEventListener(RuleClicked, this.ruleClicked);
|
|
222
|
+
this.addEventListener(RuleClicked, this.ruleController.ruleClicked.bind(this.ruleController));
|
|
208
223
|
// @ts-ignore
|
|
209
224
|
this.addEventListener(BuiltInRulesetChanged, this.builtInRulesetSelected);
|
|
210
225
|
// @ts-ignore
|
|
211
|
-
this.addEventListener(ModelTreeNodeClicked, this.modelTreeNodeClicked);
|
|
226
|
+
this.addEventListener(ModelTreeNodeClicked, this.nodeClickerController.modelTreeNodeClicked.bind(this.nodeClickerController));
|
|
212
227
|
// @ts-ignore
|
|
213
|
-
this.addEventListener(RolodexTreeNodeClicked, this.rolodexTreeNodeClicked);
|
|
228
|
+
this.addEventListener(RolodexTreeNodeClicked, this.nodeClickerController.rolodexTreeNodeClicked.bind(this.nodeClickerController));
|
|
214
229
|
// @ts-ignore
|
|
215
|
-
this.addEventListener(
|
|
230
|
+
this.addEventListener(NodeReferenceClicked, this.nodeClickerController.explorerReferenceClicked.bind(this.nodeClickerController));
|
|
216
231
|
// @ts-ignore
|
|
217
|
-
this.addEventListener(
|
|
232
|
+
this.addEventListener(ExplorerNodeClicked, this.nodeClickerController.explorerNodeClicked.bind(this.nodeClickerController));
|
|
218
233
|
// @ts-ignore
|
|
219
|
-
this.addEventListener(
|
|
234
|
+
this.addEventListener(DocumentReferenceClicked, this.nodeClickerController.documentReferenceClicked.bind(this.nodeClickerController));
|
|
220
235
|
// @ts-ignore
|
|
221
|
-
this.addEventListener(
|
|
236
|
+
this.addEventListener(RolodexRootFileSelected, this.rolodexController.rolodexRootFileSelected.bind(this.rolodexController));
|
|
222
237
|
// @ts-ignore
|
|
223
|
-
this.addEventListener(
|
|
238
|
+
this.addEventListener(ArchiveURLRequested, this.fetchUrl.bind(this));
|
|
224
239
|
//@ts-ignore
|
|
225
240
|
this.explorer.equalizer.addEventListener(ExplorerEqualizerChanged, this.filterTreeModel.bind(this));
|
|
226
241
|
//@ts-ignore
|
|
227
242
|
this.explorer.equalizer.addEventListener(ExplorerEqualizerFiltered, this.filterTreeModel.bind(this));
|
|
243
|
+
// @ts-ignore
|
|
228
244
|
this.nukeWorkspace.addEventListener(NukeWorkspaceEvent, this.nukeWorkspaceHandler.bind(this));
|
|
245
|
+
// on logout, nuke it all.
|
|
246
|
+
// @ts-ignore
|
|
247
|
+
this.authController.addEventListener(NukeWorkspaceEvent, this.nukeWorkspaceHandler.bind(this));
|
|
248
|
+
// @ts-ignore
|
|
249
|
+
this.authController.addEventListener(StartSessionFailed, this.platformUnavailable.bind(this));
|
|
229
250
|
this.timeVortex.historyPicker.addEventListener(OpenSettings, this.openSettings.bind(this));
|
|
230
251
|
//@ts-ignore
|
|
231
252
|
this.addEventListener(LoadRenderedNodeIntoInspector, this.loadRenderedNodeIntoInspector.bind(this));
|
|
232
|
-
// extract port from session storage.
|
|
233
|
-
this.busPort = sessionStorage.getItem("pb33f-doctor-port");
|
|
234
|
-
this.busHost = sessionStorage.getItem("pb33f-doctor-host");
|
|
235
|
-
if (!this.busPort) {
|
|
236
|
-
this.busPort = "443"; // default port
|
|
237
|
-
}
|
|
238
|
-
if (!this.busHost) {
|
|
239
|
-
this.busHost = "doctor.pb33f.io"; // default host
|
|
240
|
-
}
|
|
241
|
-
const useTLS = sessionStorage.getItem("pb33f-doctor-tls");
|
|
242
|
-
if (useTLS && useTLS == 'true') {
|
|
243
|
-
this.useTLS = true;
|
|
244
|
-
}
|
|
245
253
|
// hijack navigation buttons.
|
|
246
254
|
window.addEventListener('popstate', (e) => {
|
|
247
255
|
const state = e.state;
|
|
248
256
|
if (state) {
|
|
249
257
|
if (state.activeNode) {
|
|
250
|
-
this.modelTreeNodeClicked(new CustomEvent(ExplorerNodeClicked, {
|
|
258
|
+
this.nodeClickerController.modelTreeNodeClicked(new CustomEvent(ExplorerNodeClicked, {
|
|
251
259
|
detail: {
|
|
252
260
|
nodeHashId: state.activeNode,
|
|
253
261
|
noState: true
|
|
@@ -255,7 +263,7 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
255
263
|
}));
|
|
256
264
|
}
|
|
257
265
|
if (state.ref) {
|
|
258
|
-
this.documentReferenceClicked(new CustomEvent(DocumentReferenceClicked, {
|
|
266
|
+
this.nodeClickerController.documentReferenceClicked(new CustomEvent(DocumentReferenceClicked, {
|
|
259
267
|
detail: {
|
|
260
268
|
jsonPath: state.ref,
|
|
261
269
|
noState: true
|
|
@@ -275,18 +283,18 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
275
283
|
this.showDiagnosisButton = !config.autoDiagnose;
|
|
276
284
|
// if the time vortex is not available, enable skipsState
|
|
277
285
|
this.timeVortex.historyPicker.skipChanges = config.skipTimeline;
|
|
278
|
-
if (config.applicationVersion == this.currentVersion) {
|
|
286
|
+
if (config.applicationVersion == this.brokerController.currentVersion) {
|
|
279
287
|
return;
|
|
280
288
|
}
|
|
281
|
-
if (this.currentVersion && this.currentVersion != 'bootstrap' &&
|
|
289
|
+
if (this.brokerController.currentVersion && this.brokerController.currentVersion != 'bootstrap' &&
|
|
282
290
|
config.applicationVersion &&
|
|
283
291
|
config.applicationVersion != 'bootstrap' &&
|
|
284
|
-
this.currentVersion != config.applicationVersion) {
|
|
285
|
-
console.warn('version changed, reloading', this.currentVersion, config.applicationVersion);
|
|
292
|
+
this.brokerController.currentVersion != config.applicationVersion) {
|
|
293
|
+
console.warn('version changed, reloading', this.brokerController.currentVersion, config.applicationVersion);
|
|
286
294
|
this.nukeWorkspaceHandler();
|
|
287
295
|
}
|
|
288
296
|
else {
|
|
289
|
-
config.applicationVersion = this.currentVersion;
|
|
297
|
+
config.applicationVersion = this.brokerController.currentVersion;
|
|
290
298
|
this.settingsBag?.set(SettingsBag, config);
|
|
291
299
|
}
|
|
292
300
|
}
|
|
@@ -298,15 +306,20 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
298
306
|
this.requestUpdate();
|
|
299
307
|
this.viewerPanel.click();
|
|
300
308
|
}
|
|
301
|
-
|
|
302
|
-
this.randomTicker = Math.floor(Math.random() * 9999999);
|
|
303
|
-
}
|
|
304
|
-
nukeWorkspaceHandler() {
|
|
309
|
+
nukeWorkspaceHandler(e) {
|
|
305
310
|
this.bagManager.resetBags();
|
|
306
311
|
localStorage.removeItem("pb33f-doctor-version");
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
if (!e || !e.detail || e.detail.resetFiles) {
|
|
313
|
+
ModelService.resetWorkspace().then(() => {
|
|
314
|
+
window.location.reload();
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
// no work to do, just reload the page.
|
|
319
|
+
setTimeout(() => {
|
|
320
|
+
window.location.reload();
|
|
321
|
+
}, 50);
|
|
322
|
+
}
|
|
310
323
|
}
|
|
311
324
|
minimapToggled() {
|
|
312
325
|
this.minimapVisible = !this.minimapVisible;
|
|
@@ -318,91 +331,12 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
318
331
|
this.editor = this.querySelector('pb33f-editor#spec-editor');
|
|
319
332
|
this.rulesetEditor = this.querySelector('pb33f-editor#ruleset-editor');
|
|
320
333
|
}
|
|
321
|
-
whoAmI() {
|
|
322
|
-
this.bus.publish({
|
|
323
|
-
destination: "/p/q/" + DoctorServiceChannel,
|
|
324
|
-
body: JSON.stringify({ request: Command.WhoAmI }),
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
connectToBroker() {
|
|
328
|
-
let protocol = "ws://";
|
|
329
|
-
if (this.useTLS) {
|
|
330
|
-
protocol = "wss://";
|
|
331
|
-
}
|
|
332
|
-
// configure wiretap broker.
|
|
333
|
-
const config = {
|
|
334
|
-
brokerURL: protocol + this.busHost + ':' + this.busPort + '/ranch',
|
|
335
|
-
heartbeatIncoming: 0,
|
|
336
|
-
heartbeatOutgoing: 0,
|
|
337
|
-
onConnect: () => {
|
|
338
|
-
console.log("💊 Connected to the %cOpenAPI Doctor%c, we are ready to communicate.", 'background: #0d1117; color: #62C4FFFF; font-weight: bold', 'color: default');
|
|
339
|
-
this.bus.mapChannels();
|
|
340
|
-
this.whoAmI();
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
this.bus.connectToBroker(config);
|
|
344
|
-
}
|
|
345
334
|
addClickTrack(node) {
|
|
346
335
|
history.pushState({ activeNode: node.idHash }, "", `?view=explore&node=${node.idHash}`);
|
|
347
336
|
}
|
|
348
337
|
addRefTrack(ref) {
|
|
349
338
|
history.pushState({ ref: ref }, "", `?view=spec&ref=${ref}`);
|
|
350
339
|
}
|
|
351
|
-
doctorServiceHandler() {
|
|
352
|
-
return (msg) => {
|
|
353
|
-
if (msg.payload?.payload != null) {
|
|
354
|
-
if (isBrokerResponse(msg.payload.payload)) {
|
|
355
|
-
this.brokerConnectionId = msg.payload.payload.broker;
|
|
356
|
-
this.authController.associateBroker(this.brokerConnectionId).then(() => {
|
|
357
|
-
// check version from the server
|
|
358
|
-
const version = msg.payload.payload.version;
|
|
359
|
-
if (version !== "") {
|
|
360
|
-
this.currentVersion = version;
|
|
361
|
-
}
|
|
362
|
-
const memVersion = localStorage.getItem("pb33f-doctor-version");
|
|
363
|
-
if (memVersion) {
|
|
364
|
-
if (this.currentVersion != memVersion) {
|
|
365
|
-
this.nukeWorkspaceHandler();
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
localStorage.setItem("pb33f-doctor-version", this.currentVersion);
|
|
371
|
-
}
|
|
372
|
-
console.log("💊 Welcome to the clinic, the %cdoctor %cis ready to see you. [" + "v" + version + "]", 'color: #62C4FFFF; font-weight: bold', 'color: default');
|
|
373
|
-
this.startTheDoctor();
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
startTheDoctor() {
|
|
380
|
-
this.specChannelSubscription = this.specStreamChannel.subscribe(this.specStreamHandler());
|
|
381
|
-
this.creditChannelSubscription = this.creditStreamChannel.subscribe(this.creditStreamHandler());
|
|
382
|
-
this.bus.mapChannelToBrokerDestination(QueuePrefix + SpecStreamChannel, SpecStreamChannel);
|
|
383
|
-
this.bus.mapChannelToBrokerDestination(QueuePrefix + CreditStreamChannel, CreditStreamChannel);
|
|
384
|
-
this.boostrap();
|
|
385
|
-
}
|
|
386
|
-
specStreamHandler() {
|
|
387
|
-
return (msg) => {
|
|
388
|
-
if (msg.payload?.payload != null) {
|
|
389
|
-
// base64 decode the payload and update the editor!
|
|
390
|
-
const decoded = atob(msg.payload.payload);
|
|
391
|
-
if (this.docBag) {
|
|
392
|
-
this.docBag.set(DefaultDocument, decoded);
|
|
393
|
-
}
|
|
394
|
-
this.editor?.setValue(decoded, true);
|
|
395
|
-
this.requestUpdate();
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
creditStreamHandler() {
|
|
400
|
-
return (msg) => {
|
|
401
|
-
if (msg.payload?.payload != null) {
|
|
402
|
-
this.creditTicker.credits = parseInt(msg.payload.payload);
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
340
|
filterTreeModel(event) {
|
|
407
341
|
this.filteredNodes = new Map();
|
|
408
342
|
event.detail.graph.nodes.forEach((node) => {
|
|
@@ -411,385 +345,6 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
411
345
|
this.modelTree.filteredNodes = this.filteredNodes;
|
|
412
346
|
this.modelTree.renderedNodes = this.renderedNodeMap;
|
|
413
347
|
}
|
|
414
|
-
documentReferenceClicked(evt) {
|
|
415
|
-
let location = '';
|
|
416
|
-
let line, col = 1;
|
|
417
|
-
let path = evt.detail.jsonPath;
|
|
418
|
-
let fullPath = '';
|
|
419
|
-
let file = '';
|
|
420
|
-
let rolodexId = '';
|
|
421
|
-
if (evt.detail.jsonPath.includes('||')) {
|
|
422
|
-
location = evt.detail.jsonPath.split('||')[1];
|
|
423
|
-
path = evt.detail.jsonPath.split('||')[0];
|
|
424
|
-
// location is formatted line:col-endCol
|
|
425
|
-
line = parseInt(location.split(':')[0]);
|
|
426
|
-
col = parseInt(location.split(':')[1]);
|
|
427
|
-
fullPath = evt.detail.jsonPath.split('||')[2];
|
|
428
|
-
if (fullPath != '') {
|
|
429
|
-
file = fullPath.split('#')[0];
|
|
430
|
-
}
|
|
431
|
-
rolodexId = evt.detail.jsonPath.split('||')[3];
|
|
432
|
-
}
|
|
433
|
-
this.editor.editor?.setPosition({ lineNumber: line, column: col });
|
|
434
|
-
this.editor.editor?.revealLineInCenter(line);
|
|
435
|
-
if (this.nodeIdMap.has(path)) {
|
|
436
|
-
const node = this.nodeIdMap.get(path);
|
|
437
|
-
if (node) {
|
|
438
|
-
if (this.nodeIdHashMap.has(node.idHash)) {
|
|
439
|
-
const renderedNode = this.renderedNodeMap.get(node.id);
|
|
440
|
-
if (renderedNode) {
|
|
441
|
-
this.renderedNode.node = renderedNode;
|
|
442
|
-
this.modelTree.explorerClicked(node.id);
|
|
443
|
-
// add a ref click
|
|
444
|
-
if (!evt.detail.noState) {
|
|
445
|
-
this.addRefTrack(evt.detail.jsonPath);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
this.toastManager.addToastManually({
|
|
452
|
-
id: crypto.randomUUID(),
|
|
453
|
-
type: ToastType.INFO,
|
|
454
|
-
title: "Reference not found",
|
|
455
|
-
body: `Something went wrong, '${path}' not found`
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
460
|
-
if (this.rolodexActivePath != undefined && this.rolodexActivePath != file) {
|
|
461
|
-
ModelService.queryRolodex(rolodexId, file).then((result) => {
|
|
462
|
-
this.editor.showBreadcrumb = true;
|
|
463
|
-
this.rolodexActivePath = file;
|
|
464
|
-
this.editor.clearDecorations();
|
|
465
|
-
this.editor.setValue(result.rolodexRoot.instance, true);
|
|
466
|
-
this.editor.editor?.setPosition({ lineNumber: line, column: 1 });
|
|
467
|
-
this.editor.editor?.revealLineInCenter(line);
|
|
468
|
-
this.rolodexTree.explorerClicked(rolodexId);
|
|
469
|
-
this.editor.setCurrentPath(file);
|
|
470
|
-
this.fetchRefMap(file);
|
|
471
|
-
//this.lintSpec(result.rolodexRoot.instance);
|
|
472
|
-
// apply problems
|
|
473
|
-
if (this.rolodexProblemMap.has(this.rolodexActivePath)) {
|
|
474
|
-
const probs = this.rolodexProblemMap.get(this.rolodexActivePath);
|
|
475
|
-
if (probs) {
|
|
476
|
-
this.editor.setMarkers(probs);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}).catch((e) => {
|
|
480
|
-
console.error('rolodex query failed', e);
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
explorerReferenceClicked(evt) {
|
|
486
|
-
let nodeId = '';
|
|
487
|
-
this.explorer.nodeComponents.forEach((node) => {
|
|
488
|
-
if (node.body.node.nodePath === evt.detail.nodePath) {
|
|
489
|
-
const renderedNode = this.renderedNodeMap.get(node.body.node.id);
|
|
490
|
-
if (renderedNode) {
|
|
491
|
-
this.editor.editor?.setPosition({ lineNumber: renderedNode.keyLine, column: 0 });
|
|
492
|
-
this.editor.editor?.revealLineInCenter(renderedNode.keyLine);
|
|
493
|
-
this.renderedNode.node = renderedNode;
|
|
494
|
-
nodeId = node.body.node.id;
|
|
495
|
-
this.explorer.moveToNode(node.body.node);
|
|
496
|
-
this.activeNode = node.body.node;
|
|
497
|
-
this.explorer.activeNode = node.body.node;
|
|
498
|
-
this.explorer.equalizer.activeNode = node.body.node;
|
|
499
|
-
}
|
|
500
|
-
node.body.active = true;
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
node.body.active = false;
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
if (nodeId) {
|
|
507
|
-
this.modelTree.explorerClicked(nodeId);
|
|
508
|
-
this.explorer.requestUpdate();
|
|
509
|
-
this.viewerPanel.click();
|
|
510
|
-
}
|
|
511
|
-
if (evt.detail.nodePath) {
|
|
512
|
-
let p = evt.detail.nodePath;
|
|
513
|
-
if (!p.startsWith('/') && !p.includes('#')) {
|
|
514
|
-
const dir = this.rolodexRootPath.substring(0, this.rolodexRootPath.lastIndexOf('/') + 1);
|
|
515
|
-
p = dir + p;
|
|
516
|
-
}
|
|
517
|
-
if (!p.startsWith('#/')) {
|
|
518
|
-
this.rolodexTreeNodeClicked(new CustomEvent(RolodexTreeNodeClicked, {
|
|
519
|
-
detail: {
|
|
520
|
-
path: p,
|
|
521
|
-
}
|
|
522
|
-
}));
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
rolodexTreeNodeClicked(evt) {
|
|
527
|
-
const fileBag = this.rolodexFilesBag?.get(RolodexFilesBag);
|
|
528
|
-
const handleRolodexResponse = (result) => {
|
|
529
|
-
this.rolodexActivePath = evt.detail.path;
|
|
530
|
-
this.rolodexActiveHash = evt.detail.nodeHashId;
|
|
531
|
-
this.editor.setValue(result.instance, true);
|
|
532
|
-
this.editor.setCurrentPath(this.rolodexActivePath);
|
|
533
|
-
this.fetchRefMap(this.rolodexActivePath);
|
|
534
|
-
const probs = this.rolodexProblemMap.get(this.rolodexActivePath);
|
|
535
|
-
if (probs) {
|
|
536
|
-
this.editor.setMarkers(probs);
|
|
537
|
-
}
|
|
538
|
-
// set the editor file type
|
|
539
|
-
let language = 'yaml';
|
|
540
|
-
const ext = evt.detail?.path?.split('.').pop();
|
|
541
|
-
if (ext) {
|
|
542
|
-
switch (ext) {
|
|
543
|
-
case NodeType.JSON:
|
|
544
|
-
language = NodeType.JSON;
|
|
545
|
-
break;
|
|
546
|
-
case NodeType.GO:
|
|
547
|
-
language = NodeType.GO;
|
|
548
|
-
break;
|
|
549
|
-
case NodeType.PY:
|
|
550
|
-
language = 'python';
|
|
551
|
-
break;
|
|
552
|
-
case NodeType.JS:
|
|
553
|
-
language = 'javascript';
|
|
554
|
-
break;
|
|
555
|
-
case NodeType.TS:
|
|
556
|
-
language = 'typescript';
|
|
557
|
-
break;
|
|
558
|
-
case NodeType.PHP:
|
|
559
|
-
language = NodeType.PHP;
|
|
560
|
-
break;
|
|
561
|
-
case NodeType.XML:
|
|
562
|
-
language = NodeType.XML;
|
|
563
|
-
break;
|
|
564
|
-
case NodeType.JAVA:
|
|
565
|
-
language = NodeType.JAVA;
|
|
566
|
-
break;
|
|
567
|
-
case NodeType.RB:
|
|
568
|
-
language = 'ruby';
|
|
569
|
-
break;
|
|
570
|
-
case NodeType.RS:
|
|
571
|
-
language = 'rust';
|
|
572
|
-
break;
|
|
573
|
-
case NodeType.C:
|
|
574
|
-
language = NodeType.C;
|
|
575
|
-
break;
|
|
576
|
-
case NodeType.CPP:
|
|
577
|
-
language = NodeType.CPP;
|
|
578
|
-
break;
|
|
579
|
-
case NodeType.CS:
|
|
580
|
-
language = 'csharp';
|
|
581
|
-
break;
|
|
582
|
-
case NodeType.MD:
|
|
583
|
-
language = 'markdown';
|
|
584
|
-
break;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
const existingState = this.rolodexStateBag?.get(RolodexStateBag);
|
|
588
|
-
if (existingState) {
|
|
589
|
-
existingState.activePath = evt.detail.path;
|
|
590
|
-
existingState.activeHash = evt.detail.nodeHashId;
|
|
591
|
-
existingState.activeLanguage = language;
|
|
592
|
-
existingState.activeNode = result;
|
|
593
|
-
existingState.rootPath = this.rolodexRootPath;
|
|
594
|
-
this.rolodexStateBag?.set(RolodexStateBag, existingState);
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
const existingState = {
|
|
598
|
-
activePath: evt.detail.path,
|
|
599
|
-
activeHash: evt.detail.nodeHashId,
|
|
600
|
-
activeLanguage: language,
|
|
601
|
-
activeNode: result,
|
|
602
|
-
rootHash: this.rolodexRootHash,
|
|
603
|
-
rootPath: this.rolodexRootPath
|
|
604
|
-
};
|
|
605
|
-
this.rolodexStateBag?.set(RolodexStateBag, existingState);
|
|
606
|
-
}
|
|
607
|
-
this.editor.switchLanguage(language);
|
|
608
|
-
let line = 1;
|
|
609
|
-
let col = 0;
|
|
610
|
-
if (evt.detail.line) {
|
|
611
|
-
line = evt.detail.line;
|
|
612
|
-
}
|
|
613
|
-
if (evt.detail.column) {
|
|
614
|
-
col = evt.detail.column;
|
|
615
|
-
}
|
|
616
|
-
this.editor.editor?.setPosition({ lineNumber: line, column: col });
|
|
617
|
-
this.editor.editor?.revealLineInCenter(line, col);
|
|
618
|
-
//this.lintSpec(result.instance);
|
|
619
|
-
if (evt.detail.path) {
|
|
620
|
-
this.rolodexTree.openNodeByPath(evt.detail.path);
|
|
621
|
-
}
|
|
622
|
-
return language;
|
|
623
|
-
};
|
|
624
|
-
ModelService.queryRolodex(evt.detail.nodeHashId, evt.detail.path).then((result) => {
|
|
625
|
-
this.editor.showBreadcrumb = true;
|
|
626
|
-
// clear all references
|
|
627
|
-
this.referenceMapBag?.reset();
|
|
628
|
-
handleRolodexResponse(result.rolodexRoot);
|
|
629
|
-
if (evt.detail.path) {
|
|
630
|
-
if (fileBag && !fileBag.files[evt.detail.path]) {
|
|
631
|
-
fileBag.files[evt.detail.path] = result.rolodexRoot;
|
|
632
|
-
this.rolodexFilesBag?.set(RolodexFilesBag, fileBag);
|
|
633
|
-
}
|
|
634
|
-
if (!fileBag) {
|
|
635
|
-
const rf = {
|
|
636
|
-
files: { [evt.detail.path]: result.rolodexRoot }
|
|
637
|
-
};
|
|
638
|
-
this.rolodexFilesBag?.set(RolodexFilesBag, rf);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
rolodexRootFileSelected(evt) {
|
|
644
|
-
this.rolodexActivePath = evt.detail.path;
|
|
645
|
-
this.rolodexActiveHash = evt.detail.nodeHashId;
|
|
646
|
-
this.rolodexRootPath = evt.detail.path;
|
|
647
|
-
this.importDisabled = true;
|
|
648
|
-
const existingState = this.rolodexStateBag?.get(RolodexStateBag);
|
|
649
|
-
if (existingState) {
|
|
650
|
-
existingState.activePath = evt.detail.path;
|
|
651
|
-
existingState.activeHash = evt.detail.nodeHashId;
|
|
652
|
-
existingState.rootPath = evt.detail.path;
|
|
653
|
-
existingState.rootHash = evt.detail.nodeHashId;
|
|
654
|
-
this.rolodexStateBag?.set(RolodexStateBag, existingState);
|
|
655
|
-
}
|
|
656
|
-
else {
|
|
657
|
-
const existingState = {
|
|
658
|
-
activePath: evt.detail.path,
|
|
659
|
-
activeHash: evt.detail.nodeHashId,
|
|
660
|
-
rootPath: evt.detail.path,
|
|
661
|
-
rootHash: evt.detail.nodeHashId
|
|
662
|
-
};
|
|
663
|
-
this.rolodexStateBag?.set(RolodexStateBag, existingState);
|
|
664
|
-
}
|
|
665
|
-
if (evt.detail.nodeHashId) {
|
|
666
|
-
this.rolodexRootHash = evt.detail.nodeHashId;
|
|
667
|
-
}
|
|
668
|
-
if (evt.detail.content) {
|
|
669
|
-
this.rolodexNeedsReset = true;
|
|
670
|
-
this.editor.setValue(evt.detail.content, true);
|
|
671
|
-
this.lintSpec(evt.detail.content);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
modelTreeNodeClicked(evt) {
|
|
675
|
-
let node = this.nodeIdMap.get(evt.detail.nodeId);
|
|
676
|
-
if (!node) {
|
|
677
|
-
node = this.nodeIdHashMap.get(evt.detail.nodeId);
|
|
678
|
-
}
|
|
679
|
-
if (node) {
|
|
680
|
-
if (node.origin && node.origin != this.rolodexActivePath && (node.origin != '/root.yaml' && node.origin != 'root.yaml')) {
|
|
681
|
-
// extract the rolodex id using the path
|
|
682
|
-
let hashId = '';
|
|
683
|
-
const fb = this.rolodexFilesBag?.get(RolodexFilesBag);
|
|
684
|
-
if (fb) {
|
|
685
|
-
if (fb.files[node.origin]) {
|
|
686
|
-
hashId = fb.files[node.origin].idHash;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
// we need to fire a rolodex tree node change event.
|
|
690
|
-
this.rolodexTreeNodeClicked(new CustomEvent(RolodexTreeNodeClicked, {
|
|
691
|
-
detail: {
|
|
692
|
-
nodeHashId: hashId,
|
|
693
|
-
path: node.origin
|
|
694
|
-
}
|
|
695
|
-
}));
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
|
-
// don't jump to the root in the editor if the root is selected
|
|
699
|
-
if (node.idHash !== 'root') {
|
|
700
|
-
this.editor.editor?.setPosition({ lineNumber: node.keyLine, column: 0 });
|
|
701
|
-
this.editor.editor?.revealLineInCenter(node.keyLine);
|
|
702
|
-
}
|
|
703
|
-
if (this.explorerVisible) {
|
|
704
|
-
this.explorer.moveToNode(node, evt.detail.first);
|
|
705
|
-
}
|
|
706
|
-
this.activeNode = node;
|
|
707
|
-
// add changes to active node.
|
|
708
|
-
if (evt.detail.changes) {
|
|
709
|
-
node.timeline = evt.detail.changes;
|
|
710
|
-
}
|
|
711
|
-
this.explorer.activeNode = node;
|
|
712
|
-
this.explorer.equalizer.activeNode = node;
|
|
713
|
-
const renderedNode = structuredClone(this.renderedNodeMap.get(node.id));
|
|
714
|
-
if (renderedNode) {
|
|
715
|
-
if (evt.detail.changes) {
|
|
716
|
-
renderedNode.timeline = evt.detail.changes;
|
|
717
|
-
}
|
|
718
|
-
this.renderedNode.node = renderedNode;
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
721
|
-
alert('no id found');
|
|
722
|
-
}
|
|
723
|
-
if (!evt.detail.noState) {
|
|
724
|
-
this.addClickTrack(node);
|
|
725
|
-
evt.detail.noState = true;
|
|
726
|
-
}
|
|
727
|
-
this.explorerNodeClicked(evt, false);
|
|
728
|
-
if (this._firstRun) {
|
|
729
|
-
this._firstRun = false;
|
|
730
|
-
}
|
|
731
|
-
else {
|
|
732
|
-
this.viewerPanel.click();
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
else {
|
|
736
|
-
this.sendToast({
|
|
737
|
-
id: crypto.randomUUID(),
|
|
738
|
-
title: 'Unable to load change model',
|
|
739
|
-
type: ToastType.WARNING,
|
|
740
|
-
body: 'There is no-longer a model with the path `' + evt.detail.nodeId + '` in the document',
|
|
741
|
-
});
|
|
742
|
-
console.error('cannot navigate to node, path not found', evt.detail.nodeId);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
explorerNodeClicked(evt, replaceRenderedNode = true) {
|
|
746
|
-
let found = false;
|
|
747
|
-
let foundRenderedNode;
|
|
748
|
-
this.explorer.nodeComponents.forEach((node) => {
|
|
749
|
-
if (node.id === evt.detail.nodeId) {
|
|
750
|
-
let renderedNode;
|
|
751
|
-
if (replaceRenderedNode) {
|
|
752
|
-
renderedNode = this.renderedNodeMap.get(node.id);
|
|
753
|
-
if (renderedNode && !this._firstRun) {
|
|
754
|
-
this.renderedNode.node = renderedNode;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
this.selectedNodeHashId = node.body.node.idHash;
|
|
758
|
-
node.body.active = true;
|
|
759
|
-
this.activeNode = node.body.node;
|
|
760
|
-
this.explorer.activeNode = node.body.node;
|
|
761
|
-
found = true;
|
|
762
|
-
if (replaceRenderedNode) {
|
|
763
|
-
foundRenderedNode = renderedNode;
|
|
764
|
-
}
|
|
765
|
-
if (!evt.detail.noState) {
|
|
766
|
-
this.addClickTrack(node.body.node);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
node.body.active = false;
|
|
771
|
-
}
|
|
772
|
-
});
|
|
773
|
-
if (!found) {
|
|
774
|
-
// might be filtered, check the filtered nodes
|
|
775
|
-
const node = this.nodeIdMap.get(evt.detail.nodeId);
|
|
776
|
-
if (node) {
|
|
777
|
-
this.selectedNodeHashId = node.idHash;
|
|
778
|
-
this.activeNode = node;
|
|
779
|
-
this.explorer.activeNode = node;
|
|
780
|
-
this.explorer.equalizer.activeNode = node;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
if (foundRenderedNode) {
|
|
784
|
-
// when jumping back to the spec view, we need to set the line
|
|
785
|
-
this.pendingLine = foundRenderedNode.keyLine;
|
|
786
|
-
}
|
|
787
|
-
this.modelTree.explorerClicked(evt.detail.nodeId);
|
|
788
|
-
if (!this._firstRun) {
|
|
789
|
-
this.viewerPanel.click();
|
|
790
|
-
}
|
|
791
|
-
this.explorer.requestUpdate();
|
|
792
|
-
}
|
|
793
348
|
exportRuleset() {
|
|
794
349
|
this.exportRulesetDialog.show();
|
|
795
350
|
}
|
|
@@ -799,452 +354,6 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
799
354
|
sendToast(toast) {
|
|
800
355
|
this.toastManager.addToastManually(toast);
|
|
801
356
|
}
|
|
802
|
-
ruleGroupClicked(event) {
|
|
803
|
-
this.problemsPanel.focus();
|
|
804
|
-
const simEvent = new CustomEvent(ProblemRuleFilterChangedManual, {
|
|
805
|
-
bubbles: true,
|
|
806
|
-
composed: true,
|
|
807
|
-
detail: {
|
|
808
|
-
rule: event.detail.rule
|
|
809
|
-
}
|
|
810
|
-
});
|
|
811
|
-
this.problemsPanel.focus();
|
|
812
|
-
this.problemList.dispatchEvent(simEvent);
|
|
813
|
-
history.pushState({ rule: event.detail.rule }, "", `/${ActiveView.Problems}?rule=${event.detail.rule}`);
|
|
814
|
-
this.controlTabGroup.show(ActiveView.Problems);
|
|
815
|
-
}
|
|
816
|
-
ruleDocsClicked(event) {
|
|
817
|
-
const ruleId = event.detail.rule;
|
|
818
|
-
if (ruleId) {
|
|
819
|
-
switch (event.detail.type) {
|
|
820
|
-
case ProblemDrawerEventType.RULE_DOCS:
|
|
821
|
-
const ruleDoc = this.ruleDocsBag?.get(ruleId);
|
|
822
|
-
if (ruleDoc) {
|
|
823
|
-
event.detail.body = ruleDoc.body;
|
|
824
|
-
this.detailsDrawer.open(event.detail);
|
|
825
|
-
}
|
|
826
|
-
else {
|
|
827
|
-
this.sendToast({
|
|
828
|
-
id: crypto.randomUUID(),
|
|
829
|
-
type: ToastType.INFO,
|
|
830
|
-
title: "Rule documentation unavailable",
|
|
831
|
-
body: `Documentation for '${ruleId}' not available`
|
|
832
|
-
});
|
|
833
|
-
}
|
|
834
|
-
break;
|
|
835
|
-
case ProblemDrawerEventType.HOW_TO_FIX:
|
|
836
|
-
const howToFix = this.howToFixBag?.get(ruleId);
|
|
837
|
-
if (howToFix) {
|
|
838
|
-
event.detail.body = howToFix.howToFix;
|
|
839
|
-
this.detailsDrawer.open(event.detail);
|
|
840
|
-
}
|
|
841
|
-
else {
|
|
842
|
-
this.sendToast({
|
|
843
|
-
id: crypto.randomUUID(),
|
|
844
|
-
type: ToastType.INFO,
|
|
845
|
-
title: "How to fix unavailable",
|
|
846
|
-
body: `Information on how to fix '${ruleId}' not available`
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
break;
|
|
850
|
-
case ProblemDrawerEventType.FUNCTION_DOCS:
|
|
851
|
-
const funcDocs = this.functionDocsBag?.get(ruleId);
|
|
852
|
-
if (funcDocs) {
|
|
853
|
-
event.detail.body = funcDocs.body;
|
|
854
|
-
this.detailsDrawer.open(event.detail);
|
|
855
|
-
}
|
|
856
|
-
else {
|
|
857
|
-
this.sendToast({
|
|
858
|
-
id: crypto.randomUUID(),
|
|
859
|
-
type: ToastType.INFO,
|
|
860
|
-
title: "Function documentation unavailable",
|
|
861
|
-
body: `Documentation for '${ruleId}' not available`
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
break;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
else {
|
|
868
|
-
switch (event.detail.type) {
|
|
869
|
-
case ProblemDrawerEventType.RENDERED_EXAMPLE:
|
|
870
|
-
case ProblemDrawerEventType.MARKDOWN:
|
|
871
|
-
this.detailsDrawer.open(event.detail);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
rulesetSaved(evt) {
|
|
876
|
-
// lint spec
|
|
877
|
-
if (this.docBag) {
|
|
878
|
-
const doc = this.docBag.get(DefaultDocument);
|
|
879
|
-
const config = this.ruleConfigBag?.get(RuleConfigurationBag);
|
|
880
|
-
if (evt.detail.rules) {
|
|
881
|
-
this.customRulesetBag?.set(CustomRulesetBag, evt.detail.rules);
|
|
882
|
-
// get ruleset config and disable everything,
|
|
883
|
-
// then enable the custom rules.
|
|
884
|
-
if (config) {
|
|
885
|
-
// extract config from the event
|
|
886
|
-
const newConfig = evt.detail.config;
|
|
887
|
-
if (newConfig && this.ruleConfigBag) {
|
|
888
|
-
newConfig.returnedRuleset = evt.detail.returnedRules;
|
|
889
|
-
this.ruleConfigBag?.set(RuleConfigurationBag, newConfig);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
RulesetService.getSessionRulesetAsYAML().then((yaml) => {
|
|
893
|
-
if (this.selectedEditorTab == "spec") {
|
|
894
|
-
this.rulesetPulse = true;
|
|
895
|
-
}
|
|
896
|
-
this.rulesetEditor.setValue(yaml, true);
|
|
897
|
-
this.fetchRulesetMap();
|
|
898
|
-
});
|
|
899
|
-
// lint the spec
|
|
900
|
-
this.lintSpec(doc, '');
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
buildRolodexResultMap(results) {
|
|
905
|
-
// TODO: optimize this, it's a bit slow.
|
|
906
|
-
this.rolodexProblemMap.clear();
|
|
907
|
-
results.forEach((problem) => {
|
|
908
|
-
// check if the source location is '/root.yaml'
|
|
909
|
-
if (problem.sourceLocation === '/root.yaml' || problem.sourceLocation === 'root.yaml') {
|
|
910
|
-
problem.sourceLocation = "root";
|
|
911
|
-
}
|
|
912
|
-
if (this.rolodexProblemMap.has(problem.sourceLocation)) {
|
|
913
|
-
const problems = this.rolodexProblemMap.get(problem.sourceLocation);
|
|
914
|
-
if (problems) {
|
|
915
|
-
problems.push(problem);
|
|
916
|
-
if (problem.sourceLocation) {
|
|
917
|
-
this.rolodexProblemMap.set(problem.sourceLocation, problems);
|
|
918
|
-
}
|
|
919
|
-
else {
|
|
920
|
-
if (!this.rolodexRootPath) {
|
|
921
|
-
this.rolodexProblemMap.set("root", problems);
|
|
922
|
-
}
|
|
923
|
-
else {
|
|
924
|
-
this.rolodexProblemMap.set(this.rolodexRootPath, problems);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
else {
|
|
930
|
-
if (problem.sourceLocation) {
|
|
931
|
-
this.rolodexProblemMap.set(problem.sourceLocation, [problem]);
|
|
932
|
-
}
|
|
933
|
-
else {
|
|
934
|
-
if (!this.rolodexRootPath) {
|
|
935
|
-
const currProblems = this.rolodexProblemMap.get("root");
|
|
936
|
-
if (currProblems) {
|
|
937
|
-
currProblems.push(problem);
|
|
938
|
-
this.rolodexProblemMap.set("root", currProblems);
|
|
939
|
-
}
|
|
940
|
-
else {
|
|
941
|
-
this.rolodexProblemMap.set("root", [problem]);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
else {
|
|
945
|
-
const currProblems = this.rolodexProblemMap.get(this.rolodexRootPath);
|
|
946
|
-
if (currProblems) {
|
|
947
|
-
currProblems.push(problem);
|
|
948
|
-
this.rolodexProblemMap.set(this.rolodexRootPath, currProblems);
|
|
949
|
-
}
|
|
950
|
-
else {
|
|
951
|
-
this.rolodexProblemMap.set(this.rolodexRootPath, [problem]);
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
});
|
|
957
|
-
return this.rolodexProblemMap;
|
|
958
|
-
}
|
|
959
|
-
fetchRefMap(currentPath = '') {
|
|
960
|
-
ModelService.fetchReferenceMap().then((result) => {
|
|
961
|
-
this.editor.clearDecorations();
|
|
962
|
-
this.references = result;
|
|
963
|
-
this.editor.links = result;
|
|
964
|
-
this.editor.applyLinkDecorations();
|
|
965
|
-
// add references to our stateful bag
|
|
966
|
-
this.updateRefmapBag(currentPath, result);
|
|
967
|
-
}).catch(() => {
|
|
968
|
-
this.editor.clearDecorations();
|
|
969
|
-
this.editor.clearAllMarkers();
|
|
970
|
-
this.toastManager.addToastManually({
|
|
971
|
-
id: crypto.randomUUID(),
|
|
972
|
-
type: ToastType.INFO,
|
|
973
|
-
title: "File not analyzed",
|
|
974
|
-
body: "This file is not a JSON or YAML file, it has not been analyzed."
|
|
975
|
-
});
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
/* LINT SPEC <---------------------------------------------------------------------------------------------
|
|
979
|
-
*
|
|
980
|
-
* This is our main function, man we need to clean this all up, it's bloated to fuck
|
|
981
|
-
*
|
|
982
|
-
* <--------------------------------------------------------------------------------------------------------
|
|
983
|
-
*/
|
|
984
|
-
lintSpec(value, url) {
|
|
985
|
-
this.activitySpinner.show();
|
|
986
|
-
this.editor.breadcumb.isInvalid = false;
|
|
987
|
-
if (url) {
|
|
988
|
-
if (url === 'root') {
|
|
989
|
-
url = '';
|
|
990
|
-
}
|
|
991
|
-
else {
|
|
992
|
-
this.urlProblem.style.display = 'none';
|
|
993
|
-
this.urlOverlay.style.display = "block";
|
|
994
|
-
this.urlSpinner.style.display = "block";
|
|
995
|
-
this.referenceMapBag?.reset(); // wipe out refs.
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
else {
|
|
999
|
-
this.urlProblem.style.display = 'none';
|
|
1000
|
-
this.urlOverlay.style.display = "none";
|
|
1001
|
-
this.urlSpinner.style.display = "none";
|
|
1002
|
-
}
|
|
1003
|
-
let replaceResults = false;
|
|
1004
|
-
let currentPath = this.rolodexActivePath;
|
|
1005
|
-
if (this.rolodexActivePath === this.rolodexRootPath || this.rolodexActivePath === 'root') {
|
|
1006
|
-
replaceResults = true;
|
|
1007
|
-
currentPath = '';
|
|
1008
|
-
this.editor.showBreadcrumb = false;
|
|
1009
|
-
}
|
|
1010
|
-
if (url && url != '') {
|
|
1011
|
-
try {
|
|
1012
|
-
const parsedUrl = new URL(url);
|
|
1013
|
-
if (parsedUrl) {
|
|
1014
|
-
currentPath = parsedUrl.pathname;
|
|
1015
|
-
this.rolodexActivePath = currentPath;
|
|
1016
|
-
this.rolodexRootPath = currentPath;
|
|
1017
|
-
replaceResults = true;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
catch (e) {
|
|
1021
|
-
// do nothing for now.
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
let revive = true;
|
|
1025
|
-
LintingService.lintFile(value, this.brokerConnectionId, url, currentPath, this.skipTimeline).then((result) => {
|
|
1026
|
-
//if (replaceResults) {
|
|
1027
|
-
this.activitySpinner.hide();
|
|
1028
|
-
const map = this.buildRolodexResultMap(result);
|
|
1029
|
-
if (url) {
|
|
1030
|
-
this.urlOverlay.style.display = "none";
|
|
1031
|
-
this.urlSpinner.style.display = "none";
|
|
1032
|
-
this.urlProblem.style.display = 'none';
|
|
1033
|
-
}
|
|
1034
|
-
// extract empty location problems as we are replacing the root results
|
|
1035
|
-
let rootProblems = this.rolodexProblemMap.get("root");
|
|
1036
|
-
if (!this.rolodexRoot) {
|
|
1037
|
-
rootProblems = [];
|
|
1038
|
-
}
|
|
1039
|
-
if (result && !Array.isArray(result)) {
|
|
1040
|
-
const r = [result];
|
|
1041
|
-
if (this.rolodexProblemMap.size > 0 && this.rolodexProblemMap.has(this.rolodexActivePath)) {
|
|
1042
|
-
const probs = this.rolodexProblemMap.get(this.rolodexActivePath);
|
|
1043
|
-
if (probs) {
|
|
1044
|
-
if (rootProblems) {
|
|
1045
|
-
probs.push(...rootProblems);
|
|
1046
|
-
}
|
|
1047
|
-
this.editor.setMarkers(probs);
|
|
1048
|
-
}
|
|
1049
|
-
else {
|
|
1050
|
-
if (rootProblems) {
|
|
1051
|
-
r.push(...rootProblems);
|
|
1052
|
-
}
|
|
1053
|
-
this.editor.setMarkers(r);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
else {
|
|
1057
|
-
if (rootProblems) {
|
|
1058
|
-
r.push(...rootProblems);
|
|
1059
|
-
}
|
|
1060
|
-
this.editor.setMarkers(r);
|
|
1061
|
-
}
|
|
1062
|
-
this.problemBag?.set(DocumentProblems, r);
|
|
1063
|
-
this.problemList.problems = r;
|
|
1064
|
-
this.problems = r;
|
|
1065
|
-
this.problemsOverview.problems = this.problemList.problemItems;
|
|
1066
|
-
}
|
|
1067
|
-
if (result && Array.isArray(result)) {
|
|
1068
|
-
if (result.length == 0) {
|
|
1069
|
-
this.editor.clearAllMarkers();
|
|
1070
|
-
this.editor.breadcumb.isInvalid = false;
|
|
1071
|
-
this.editor.showBreadcrumb = false;
|
|
1072
|
-
revive = true;
|
|
1073
|
-
this.problemList.isInvalid = false;
|
|
1074
|
-
}
|
|
1075
|
-
// check if this problem is 'unable to parse'
|
|
1076
|
-
if (result.length == 1 && result[0].message.startsWith('unable to parse')) {
|
|
1077
|
-
// short circuit, we are dead.
|
|
1078
|
-
this.editor.clearDecorations();
|
|
1079
|
-
this.editor.clearAllMarkers();
|
|
1080
|
-
this.editor.setMarkers(result);
|
|
1081
|
-
this.editor.breadcumb.isInvalid = true;
|
|
1082
|
-
this.editor.showBreadcrumb = true;
|
|
1083
|
-
this.editor.dead();
|
|
1084
|
-
this.problemList.isInvalid = true;
|
|
1085
|
-
revive = false;
|
|
1086
|
-
}
|
|
1087
|
-
// extract empty location problems as we are replacing the root results
|
|
1088
|
-
if (revive && this.rolodexProblemMap.size > 0 && this.rolodexProblemMap.has(this.rolodexActivePath)) {
|
|
1089
|
-
const probs = this.rolodexProblemMap.get(this.rolodexActivePath);
|
|
1090
|
-
if (probs) {
|
|
1091
|
-
if (rootProblems) {
|
|
1092
|
-
probs.push(...rootProblems);
|
|
1093
|
-
}
|
|
1094
|
-
this.editor.setMarkers(probs);
|
|
1095
|
-
}
|
|
1096
|
-
else {
|
|
1097
|
-
if (rootProblems) {
|
|
1098
|
-
result.push(...rootProblems);
|
|
1099
|
-
}
|
|
1100
|
-
this.editor.setMarkers(result);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
else {
|
|
1104
|
-
if (replaceResults) {
|
|
1105
|
-
this.editor.setMarkers(result);
|
|
1106
|
-
}
|
|
1107
|
-
else {
|
|
1108
|
-
this.fetchRefMap(currentPath);
|
|
1109
|
-
return;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
this.problemBag?.set(DocumentProblems, result);
|
|
1113
|
-
this.problemList.problems = result;
|
|
1114
|
-
this.problems = result;
|
|
1115
|
-
this.problemsOverview.problems = this.problemList.problemItems;
|
|
1116
|
-
if (this.problemsOverview.statistics) {
|
|
1117
|
-
if (result.length == 1) {
|
|
1118
|
-
this.problemsOverview.statistics.statistics.totalErrors = 1;
|
|
1119
|
-
this.problemsOverview.statistics.statistics.overallScore = 0;
|
|
1120
|
-
this.problemsOverview.statistics.evaluation = 'Useless';
|
|
1121
|
-
this.problemsOverview.statistics.diagnosis = '<strong>Specification cannot be used</strong>: <br/><br/>' + result[0].message;
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
// enable pb33f theme.
|
|
1126
|
-
if (revive) {
|
|
1127
|
-
this.editor.revive();
|
|
1128
|
-
}
|
|
1129
|
-
else {
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
// fetch graph
|
|
1133
|
-
if ((this.rolodexRootPath == this.rolodexActivePath || this.rolodexActivePath == 'root') || url) {
|
|
1134
|
-
ModelService.fetchLatestGraph().then((result) => {
|
|
1135
|
-
this.extractGraph(result);
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1138
|
-
// TODO: rolodex query should happen elsewhere too!
|
|
1139
|
-
if (this.rolodexNeedsReset) {
|
|
1140
|
-
ModelService.queryRolodex().then((result) => {
|
|
1141
|
-
this.fetchRefMap(currentPath);
|
|
1142
|
-
this.importDisabled = true;
|
|
1143
|
-
this.editor.showBreadcrumb = true;
|
|
1144
|
-
this.rolodexNeedsReset = false;
|
|
1145
|
-
result.rolodexRoot.treeExpanded = true;
|
|
1146
|
-
this.rolodexTree.isRolodex = true;
|
|
1147
|
-
this.rolodexTree.node = result.rolodexRoot;
|
|
1148
|
-
this.rolodexRoot = result.rolodexRoot;
|
|
1149
|
-
if (this.rolodexActiveHash) {
|
|
1150
|
-
this.rolodexTree.pendingNavigationHash = this.rolodexActiveHash;
|
|
1151
|
-
}
|
|
1152
|
-
if (this.rolodexActivePath) {
|
|
1153
|
-
this.rolodexTree.pendingNavigationPath = this.rolodexActivePath;
|
|
1154
|
-
}
|
|
1155
|
-
this.rolodexResponseBag?.set(RolodexResponseBag, result);
|
|
1156
|
-
const existingState = this.rolodexStateBag?.get(RolodexStateBag);
|
|
1157
|
-
if (!existingState) {
|
|
1158
|
-
const existingState = {
|
|
1159
|
-
activePath: this.rolodexActivePath,
|
|
1160
|
-
rootPath: this.rolodexRootPath,
|
|
1161
|
-
};
|
|
1162
|
-
this.rolodexStateBag?.set(RolodexStateBag, existingState);
|
|
1163
|
-
}
|
|
1164
|
-
this.requestUpdate();
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
else {
|
|
1168
|
-
this.fetchRefMap(currentPath);
|
|
1169
|
-
this.timeVortex.tardisControl.fetchHistory();
|
|
1170
|
-
}
|
|
1171
|
-
// update the overview statistics
|
|
1172
|
-
LintingService.fetchStatistics().then((result) => {
|
|
1173
|
-
let oldScore = 0;
|
|
1174
|
-
if (this.problemsOverview.statistics) {
|
|
1175
|
-
oldScore = this.problemsOverview.statistics.statistics.overallScore;
|
|
1176
|
-
}
|
|
1177
|
-
this.diagnosticBag?.set(DiagnosticBag, result);
|
|
1178
|
-
this.activitySpinner.hide();
|
|
1179
|
-
if (result?.remainingCredit <= 10) {
|
|
1180
|
-
this.statusBar.callsRemaining = result.remainingCredit;
|
|
1181
|
-
this.statusBar.visible = true;
|
|
1182
|
-
console.warn("You are running low on credit, you will need to authenticate soon. " +
|
|
1183
|
-
"" + result.remainingCredit + " credits remaining.");
|
|
1184
|
-
}
|
|
1185
|
-
// determine if the score went up or down and toast it!
|
|
1186
|
-
this.problemsOverview.statistics = result;
|
|
1187
|
-
this.tickRandomly(); // tick randomly to refresh docs iframe.
|
|
1188
|
-
// TODO: re-evaluate these toasts, they get annoying, fucking fast.
|
|
1189
|
-
// if (this.problemsOverview.statistics) {
|
|
1190
|
-
// const newScore = result.statistics.overallScore;
|
|
1191
|
-
// if (oldScore > newScore) {
|
|
1192
|
-
// this.sendToast({
|
|
1193
|
-
// id: crypto.randomUUID(),
|
|
1194
|
-
// type: ToastType.SCOREDOWN,
|
|
1195
|
-
// body: "Your score has decreased. It is now " + newScore + "%",
|
|
1196
|
-
// title: "Score went down by " + (oldScore - newScore) + "%"
|
|
1197
|
-
// });
|
|
1198
|
-
// }
|
|
1199
|
-
// if (oldScore < newScore) {
|
|
1200
|
-
// this.sendToast({
|
|
1201
|
-
// id: crypto.randomUUID(),
|
|
1202
|
-
// type: ToastType.SCOREUP,
|
|
1203
|
-
// body: "Your score has increased to " + newScore + "%",
|
|
1204
|
-
// title: "Score went up by " + (newScore - oldScore) + "%"
|
|
1205
|
-
// });
|
|
1206
|
-
// }
|
|
1207
|
-
// }
|
|
1208
|
-
}).catch((e) => {
|
|
1209
|
-
console.error("statistics service is down", e);
|
|
1210
|
-
this.platformUnavailable(e);
|
|
1211
|
-
});
|
|
1212
|
-
if (!this.explorerBooted) {
|
|
1213
|
-
this.explorer.equalizer.initializeEqualizer();
|
|
1214
|
-
this.explorerBooted = true;
|
|
1215
|
-
}
|
|
1216
|
-
}).catch((e) => {
|
|
1217
|
-
this.activitySpinner.hide();
|
|
1218
|
-
if (!url) {
|
|
1219
|
-
//this.platformUnavailable(e);
|
|
1220
|
-
console.error("so sorry, the doctor cannot see you right now, the clinic is closed.");
|
|
1221
|
-
if (e) {
|
|
1222
|
-
console.error(e.detail);
|
|
1223
|
-
if (e.instance === 'https://pb33f.io/errors/no-credit-remaining') {
|
|
1224
|
-
this.statusBar.callsRemaining = 0;
|
|
1225
|
-
this.statusBar.visible = true;
|
|
1226
|
-
this.sendToast({
|
|
1227
|
-
id: crypto.randomUUID(),
|
|
1228
|
-
type: ToastType.ERROR,
|
|
1229
|
-
body: "Run out of credit, please authenticate for more or wait 24 hours.",
|
|
1230
|
-
title: "Credit exhausted!",
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
this.sendToast({
|
|
1235
|
-
id: crypto.randomUUID(),
|
|
1236
|
-
type: ToastType.ERROR,
|
|
1237
|
-
body: e.detail,
|
|
1238
|
-
title: "Platform Error",
|
|
1239
|
-
});
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
else {
|
|
1244
|
-
this.showUrlError(e);
|
|
1245
|
-
}
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
357
|
updateInspectorDivider() {
|
|
1249
358
|
const panelState = this.panelStateBag?.get(PanelStateBag);
|
|
1250
359
|
if (panelState) {
|
|
@@ -1291,13 +400,13 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
1291
400
|
}
|
|
1292
401
|
platformUnavailable(error) {
|
|
1293
402
|
if (!this.unavailable) {
|
|
1294
|
-
this.loadingOverlay
|
|
1295
|
-
this.activitySpinner
|
|
403
|
+
this.loadingOverlay?.hide();
|
|
404
|
+
this.activitySpinner?.hide();
|
|
1296
405
|
this.errorBanner.errorTitle = "The doctor is out.";
|
|
1297
|
-
if (!error) {
|
|
406
|
+
if (!error || !error.detail) {
|
|
1298
407
|
this.errorBanner.errorMessage = "The clinic is <strong>closed!</strong> " +
|
|
1299
408
|
"The doctor is currently unavailable" +
|
|
1300
|
-
" because there is no response from the platform.";
|
|
409
|
+
" because there is no response (when asked) from the pb33f platform.";
|
|
1301
410
|
}
|
|
1302
411
|
else {
|
|
1303
412
|
this.errorBanner.errorMessage = "The clinic is <strong>closed!</strong> " +
|
|
@@ -1309,716 +418,12 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
1309
418
|
this.controlTabGroup.show(ActiveView.Overview);
|
|
1310
419
|
}
|
|
1311
420
|
}
|
|
1312
|
-
specClicked(event) {
|
|
1313
|
-
this.detailsDrawer.close();
|
|
1314
|
-
if (this.selectedEditorTab == "spec") {
|
|
1315
|
-
let problemFound = false;
|
|
1316
|
-
for (let i = 0; i < this.problems?.length; i++) {
|
|
1317
|
-
if (this.problems[i].startLineNumber === event.detail.line) {
|
|
1318
|
-
this.problemList.lineClicked(event.detail.line, true);
|
|
1319
|
-
this.controlTabGroup.show(ActiveView.Problems);
|
|
1320
|
-
if (this.sidebarClosed) {
|
|
1321
|
-
this.toggleSidebar();
|
|
1322
|
-
}
|
|
1323
|
-
problemFound = true;
|
|
1324
|
-
break;
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
// use the graph lookup to find the node, use the graphResponse, if available if not, pull from bag
|
|
1328
|
-
const graph = this.graphBag?.get(GraphBag);
|
|
1329
|
-
if (graph) {
|
|
1330
|
-
if (graph.graphMap && event.detail.line) {
|
|
1331
|
-
const nodeHash = graph.graphMap[event.detail.line];
|
|
1332
|
-
if (nodeHash) {
|
|
1333
|
-
this.modelTree.explorerClicked(nodeHash);
|
|
1334
|
-
const rendered = this.renderedNodeMap.get(nodeHash);
|
|
1335
|
-
if (rendered) {
|
|
1336
|
-
this.renderedNode.node = rendered;
|
|
1337
|
-
}
|
|
1338
|
-
if (!problemFound) {
|
|
1339
|
-
this.viewerPanel.click();
|
|
1340
|
-
}
|
|
1341
|
-
const n = this.nodeIdHashMap.get(nodeHash);
|
|
1342
|
-
if (n) {
|
|
1343
|
-
this.explorer.activeNode = n;
|
|
1344
|
-
this.explorer.equalizer.activeNode = n;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
if (this.selectedEditorTab == ActiveView.Ruleset) {
|
|
1351
|
-
// check ruleset map for the line number
|
|
1352
|
-
const rulesetMap = this.sessionRulesetMapBag?.get(SessionRulesetMapBag);
|
|
1353
|
-
if (rulesetMap?.rulesMap) {
|
|
1354
|
-
for (let i = 0; i < rulesetMap.rulesMap.length; i++) {
|
|
1355
|
-
if (rulesetMap.rulesMap[i].line === event.detail.line) {
|
|
1356
|
-
this.controlTabGroup.show(ActiveView.Ruleset);
|
|
1357
|
-
if (this.sidebarClosed) {
|
|
1358
|
-
this.toggleSidebar();
|
|
1359
|
-
}
|
|
1360
|
-
break;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
problemClicked(event) {
|
|
1367
|
-
if (this.selectedEditorTab != "spec") {
|
|
1368
|
-
this.editorTabGroup.show("spec");
|
|
1369
|
-
this.selectedEditorTab = "spec";
|
|
1370
|
-
}
|
|
1371
|
-
let sourceLocation = event.detail.problem.problemObject.sourceLocation;
|
|
1372
|
-
// no source? use root
|
|
1373
|
-
if (sourceLocation == '' || sourceLocation == undefined || sourceLocation == 'root') {
|
|
1374
|
-
sourceLocation = this.rolodexRootPath;
|
|
1375
|
-
}
|
|
1376
|
-
// locate the node in rolodex root
|
|
1377
|
-
const node = SearchNodeTreeForPath(this.rolodexRoot, sourceLocation);
|
|
1378
|
-
if (node) {
|
|
1379
|
-
// trigger a rolodex load
|
|
1380
|
-
this.rolodexTreeNodeClicked(new CustomEvent(RolodexTreeNodeClicked, {
|
|
1381
|
-
detail: {
|
|
1382
|
-
nodeHashId: node.idHash,
|
|
1383
|
-
path: sourceLocation,
|
|
1384
|
-
line: event.detail.problem.problemObject.startLineNumber,
|
|
1385
|
-
column: event.detail.problem.problemObject.startColumn
|
|
1386
|
-
}
|
|
1387
|
-
}));
|
|
1388
|
-
this.detailsDrawer.close();
|
|
1389
|
-
// make sure we select the file in the rolodex
|
|
1390
|
-
this.rolodexTree.openNodeByPath(sourceLocation);
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
this.controlTabGroup.show(ActiveView.Problems);
|
|
1394
|
-
this.editor.editor?.revealLineInCenter(event.detail.problem.line);
|
|
1395
|
-
this.editor.editor?.setPosition({
|
|
1396
|
-
lineNumber: event.detail.problem.line,
|
|
1397
|
-
column: event.detail.problem.column
|
|
1398
|
-
});
|
|
1399
|
-
this.detailsDrawer.close();
|
|
1400
|
-
if (!event.detail.launchedFromProblems) {
|
|
1401
|
-
this.problemList.lineClicked(event.detail.problem.problemObject.startLineNumber);
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
loadState() {
|
|
1405
|
-
this.graphBag = this.bagManager.getBag(GraphBag);
|
|
1406
|
-
this.docBag = this.bagManager.getBag(DoctorDocumentBag);
|
|
1407
|
-
this.rolodexResponseBag = this.bagManager.getBag(RolodexResponseBag);
|
|
1408
|
-
this.rolodexFilesBag = this.bagManager.getBag(RolodexFilesBag);
|
|
1409
|
-
this.rolodexStateBag = this.bagManager.getBag(RolodexStateBag);
|
|
1410
|
-
this.referenceMapBag = this.bagManager.getBag(ReferenceMapBag);
|
|
1411
|
-
this.docExpirationBag = this.bagManager.getBag(DocumentationExpirationBag);
|
|
1412
|
-
this.panelStateBag = this.bagManager.getBag(PanelStateBag);
|
|
1413
|
-
this.settingsBag = this.bagManager.getBag(SettingsBag);
|
|
1414
|
-
// register a handler for settings bag changes.
|
|
1415
|
-
this.settingsBag?.onAllChanges(this.settingsChanged.bind(this));
|
|
1416
|
-
this.settingsComponent.settingsBag = this.settingsBag;
|
|
1417
|
-
if (this.settingsBag) {
|
|
1418
|
-
this.settingsChanged('', this.settingsBag.get(SettingsBag));
|
|
1419
|
-
}
|
|
1420
|
-
this.settingsComponent.bootstrap();
|
|
1421
|
-
// load the rolodex
|
|
1422
|
-
if (this.rolodexResponseBag) {
|
|
1423
|
-
const response = this.rolodexResponseBag.get(RolodexResponseBag);
|
|
1424
|
-
if (response) {
|
|
1425
|
-
this.rolodexRoot = response.rolodexRoot;
|
|
1426
|
-
this.rolodexTree.isRolodex = true;
|
|
1427
|
-
this.rolodexTree.node = response.rolodexRoot;
|
|
1428
|
-
response.rolodexRoot.treeExpanded = true;
|
|
1429
|
-
this.requestUpdate();
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
let skipDocBag = false;
|
|
1433
|
-
const checkRefMap = (key) => {
|
|
1434
|
-
let refMap = this.referenceMapBag?.get(ReferenceMapBag);
|
|
1435
|
-
if (refMap) {
|
|
1436
|
-
// TODO: replace with scehduled task to refresh the reference map
|
|
1437
|
-
setTimeout(() => {
|
|
1438
|
-
let refs = refMap?.references[key];
|
|
1439
|
-
if (!refs) {
|
|
1440
|
-
refs = refMap?.references[""]; // single file
|
|
1441
|
-
}
|
|
1442
|
-
if (refs) {
|
|
1443
|
-
this.references = refs;
|
|
1444
|
-
this.editor.links = refs;
|
|
1445
|
-
this.editor.applyLinkDecorations();
|
|
1446
|
-
}
|
|
1447
|
-
}, 5); // editor has not loaded yet, give it a second to breathe.
|
|
1448
|
-
}
|
|
1449
|
-
else {
|
|
1450
|
-
ModelService.fetchReferenceMap().then((result) => {
|
|
1451
|
-
this.references = result;
|
|
1452
|
-
this.editor.links = result;
|
|
1453
|
-
this.editor.applyLinkDecorations();
|
|
1454
|
-
}).catch(() => {
|
|
1455
|
-
this.editor.clearDecorations();
|
|
1456
|
-
this.editor.clearAllMarkers();
|
|
1457
|
-
});
|
|
1458
|
-
}
|
|
1459
|
-
};
|
|
1460
|
-
if (this.rolodexStateBag) {
|
|
1461
|
-
const state = this.rolodexStateBag.get(RolodexStateBag);
|
|
1462
|
-
if (state) {
|
|
1463
|
-
this.rolodexActivePath = state.activePath;
|
|
1464
|
-
this.rolodexActiveHash = state.activeHash;
|
|
1465
|
-
// load the root.
|
|
1466
|
-
if (state.rootHash) {
|
|
1467
|
-
this.rolodexTree.pendingNavigationHash = state.rootHash;
|
|
1468
|
-
}
|
|
1469
|
-
if (state.rootPath) {
|
|
1470
|
-
this.rolodexRootPath = state.rootPath;
|
|
1471
|
-
if (state.activePath) {
|
|
1472
|
-
checkRefMap(state.activePath);
|
|
1473
|
-
}
|
|
1474
|
-
// ensure the session has a root selected
|
|
1475
|
-
ModelService.selectRootPath(state.rootPath).then(() => {
|
|
1476
|
-
// nothing to do.
|
|
1477
|
-
}).catch((e) => {
|
|
1478
|
-
console.error('could not select the root path on boot bro', e);
|
|
1479
|
-
});
|
|
1480
|
-
}
|
|
1481
|
-
if (state.rootHash)
|
|
1482
|
-
this.rolodexRootHash = state.rootHash;
|
|
1483
|
-
if (state.activePath) {
|
|
1484
|
-
this.rolodexTree.pendingNavigationPath = state.activePath;
|
|
1485
|
-
this.rolodexTree.requestUpdate();
|
|
1486
|
-
}
|
|
1487
|
-
if (state.activeNode) {
|
|
1488
|
-
// load the content of the active node into the editor
|
|
1489
|
-
if (state.activeLanguage) {
|
|
1490
|
-
this.editor.switchLanguage(state.activeLanguage);
|
|
1491
|
-
}
|
|
1492
|
-
this.editor.setValue(state.activeNode.instance, true);
|
|
1493
|
-
skipDocBag = true;
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
else {
|
|
1497
|
-
this.rolodexActivePath = "root";
|
|
1498
|
-
// refresh the refmap.
|
|
1499
|
-
checkRefMap(this.rolodexActivePath);
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
if (this.docBag && !skipDocBag) {
|
|
1503
|
-
const doc = this.docBag.get(DefaultDocument);
|
|
1504
|
-
if (doc) {
|
|
1505
|
-
this.editor.setValue(doc, true);
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
this.problemBag = this.bagManager.getBag(DocumentProblems);
|
|
1509
|
-
if (this.problemBag) {
|
|
1510
|
-
const markers = this.problemBag.get(DocumentProblems);
|
|
1511
|
-
if (markers) {
|
|
1512
|
-
this.problems = markers;
|
|
1513
|
-
for (let i = 0; i < markers.length; i++) {
|
|
1514
|
-
markers[i] = Problem.reconstruct(markers[i]);
|
|
1515
|
-
}
|
|
1516
|
-
this.buildRolodexResultMap(markers);
|
|
1517
|
-
if (this.rolodexProblemMap.size > 0 && this.rolodexProblemMap.has(this.rolodexActivePath)) {
|
|
1518
|
-
const probs = this.rolodexProblemMap.get(this.rolodexActivePath);
|
|
1519
|
-
if (probs) {
|
|
1520
|
-
this.editor.setMarkers(probs);
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
this.problemList.problems = markers;
|
|
1524
|
-
this.problemsOverview.problems = this.problemList.problemItems;
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
this.howToFixBag = this.bagManager.getBag(HowToFixBag);
|
|
1528
|
-
this.diagnosticBag = this.bagManager.getBag(DiagnosticBag);
|
|
1529
|
-
if (this.diagnosticBag) {
|
|
1530
|
-
const stats = this.diagnosticBag.get(DiagnosticBag);
|
|
1531
|
-
if (stats) {
|
|
1532
|
-
this.problemsOverview.statistics = stats;
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
// extract graph
|
|
1536
|
-
if (this.graphBag) {
|
|
1537
|
-
const graph = this.graphBag.get(GraphBag);
|
|
1538
|
-
if (graph) {
|
|
1539
|
-
this.extractGraph(graph);
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
// extract panel state
|
|
1543
|
-
if (this.panelStateBag) {
|
|
1544
|
-
const panelState = this.panelStateBag.get(PanelStateBag);
|
|
1545
|
-
if (panelState && panelState.explorerPanel) {
|
|
1546
|
-
this.splitPanelExplorer.position = panelState.explorerPanel;
|
|
1547
|
-
}
|
|
1548
|
-
if (panelState && panelState.rolodexPanel) {
|
|
1549
|
-
if (this.splitPanelRolodex) {
|
|
1550
|
-
this.splitPanelRolodex.position = panelState.rolodexPanel;
|
|
1551
|
-
}
|
|
1552
|
-
this.rolodexDividerPosition = panelState.rolodexPanel;
|
|
1553
|
-
}
|
|
1554
|
-
if (panelState && panelState.inspectorPanel) {
|
|
1555
|
-
this.splitPanelInspector.position = panelState.inspectorPanel;
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
if (!this.rolodexRoot) {
|
|
1559
|
-
this.importDisabled = false;
|
|
1560
|
-
}
|
|
1561
|
-
else {
|
|
1562
|
-
this.importDisabled = true;
|
|
1563
|
-
}
|
|
1564
|
-
// extract rulesets from bags
|
|
1565
|
-
const promises = [];
|
|
1566
|
-
this.defaultRulesetBag = this.bagManager.getBag(DefaultRulesetBag);
|
|
1567
|
-
if (this.defaultRulesetBag) {
|
|
1568
|
-
const ruleset = this.defaultRulesetBag.get(DefaultRulesetBag);
|
|
1569
|
-
if (ruleset) {
|
|
1570
|
-
this.defaultRuleset = ruleset;
|
|
1571
|
-
}
|
|
1572
|
-
else {
|
|
1573
|
-
promises.push(this.fetchDefaultRuleset());
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
// OWASP ruleset
|
|
1577
|
-
this.OWASPRulesetBag = this.bagManager.getBag(OWASPRulesetBag);
|
|
1578
|
-
if (this.OWASPRulesetBag) {
|
|
1579
|
-
const ruleset = this.OWASPRulesetBag.get(OWASPRulesetBag);
|
|
1580
|
-
if (ruleset) {
|
|
1581
|
-
this.OWASPRuleset = ruleset;
|
|
1582
|
-
}
|
|
1583
|
-
else {
|
|
1584
|
-
promises.push(this.fetchOWASPRuleset());
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
// All ruleset
|
|
1588
|
-
this.allRulesetBag = this.bagManager.getBag(AllRulesetBag);
|
|
1589
|
-
if (this.allRulesetBag) {
|
|
1590
|
-
const ruleset = this.allRulesetBag.get(AllRulesetBag);
|
|
1591
|
-
if (ruleset) {
|
|
1592
|
-
this.allRuleset = ruleset;
|
|
1593
|
-
}
|
|
1594
|
-
else {
|
|
1595
|
-
promises.push(this.fetchAllRuleset());
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
// functions
|
|
1599
|
-
this.functionsBag = this.bagManager.getBag(FunctionsBag);
|
|
1600
|
-
this.functionSchemaBag = this.bagManager.getBag(FunctionsSchemaBag);
|
|
1601
|
-
if (this.functionsBag) {
|
|
1602
|
-
const functions = this.functionsBag.get(FunctionsBag);
|
|
1603
|
-
if (functions) {
|
|
1604
|
-
this.functions = functions;
|
|
1605
|
-
}
|
|
1606
|
-
else {
|
|
1607
|
-
promises.push(this.fetchFunctions());
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
// custom ruleset
|
|
1611
|
-
this.customRulesetBag = this.bagManager.getBag(CustomRulesetBag);
|
|
1612
|
-
if (this.customRulesetBag) {
|
|
1613
|
-
const ruleset = this.customRulesetBag.get(CustomRulesetBag);
|
|
1614
|
-
if (ruleset) {
|
|
1615
|
-
this.customRuleset = ruleset;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
// create rule configuration bag
|
|
1619
|
-
this.ruleConfigBag = this.bagManager.getBag(RuleConfigurationBag);
|
|
1620
|
-
// create rule configuration bag
|
|
1621
|
-
this.sessionRulesetMapBag = this.bagManager.getBag(SessionRulesetMapBag);
|
|
1622
|
-
// fire off all network requests, then configure the ruleset management.
|
|
1623
|
-
Promise.all(promises).then(() => {
|
|
1624
|
-
// configure rule management
|
|
1625
|
-
this.manageRuleset.defaultRuleset = this.defaultRuleset;
|
|
1626
|
-
this.manageRuleset.owaspRuleset = this.OWASPRuleset;
|
|
1627
|
-
this.manageRuleset.allRuleset = this.allRuleset;
|
|
1628
|
-
this.manageRuleset.functions = this.functions;
|
|
1629
|
-
const config = this.ruleConfigBag?.get(RuleConfigurationBag);
|
|
1630
|
-
if (config) {
|
|
1631
|
-
this.manageRuleset.rulesetConfig = config;
|
|
1632
|
-
}
|
|
1633
|
-
else {
|
|
1634
|
-
this.manageRuleset.rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
|
|
1635
|
-
}
|
|
1636
|
-
setTimeout(() => {
|
|
1637
|
-
this.manageRuleset.buildRulesets();
|
|
1638
|
-
if (this.customRuleset && this.customRuleset.rules.size > 0) {
|
|
1639
|
-
this.manageRuleset.customRuleset = this.customRuleset;
|
|
1640
|
-
}
|
|
1641
|
-
this.fetchSessionRulesetAsYaml().then((result) => {
|
|
1642
|
-
this.rulesetEditor?.setValue(result, true);
|
|
1643
|
-
this.fetchRulesetMap();
|
|
1644
|
-
}).catch((e) => {
|
|
1645
|
-
this.platformUnavailable(e);
|
|
1646
|
-
});
|
|
1647
|
-
}, 50);
|
|
1648
|
-
});
|
|
1649
|
-
// refresh state for how to fix.
|
|
1650
|
-
this.fetchDocs();
|
|
1651
|
-
}
|
|
1652
|
-
extractGraph(graph) {
|
|
1653
|
-
// handled stripped nodes
|
|
1654
|
-
if (graph.stripped) {
|
|
1655
|
-
this.explorer.nodeLimitExceeded = true;
|
|
1656
|
-
this.modelTree.nodeLimitExceeded = true;
|
|
1657
|
-
if (graph.strippedCount) {
|
|
1658
|
-
this.explorer.nodeLimit = graph.strippedCount;
|
|
1659
|
-
this.modelTree.nodeLimit = graph.strippedCount;
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
else {
|
|
1663
|
-
this.explorer.nodeLimitExceeded = false;
|
|
1664
|
-
this.modelTree.nodeLimitExceeded = false;
|
|
1665
|
-
}
|
|
1666
|
-
this.explorer.renderedNodeMap.clear();
|
|
1667
|
-
this.nodeMap.clear();
|
|
1668
|
-
this.nodeIdMap.clear();
|
|
1669
|
-
this.nodeIdHashMap.clear();
|
|
1670
|
-
const renderedNodes = new Map();
|
|
1671
|
-
graph?.nodesRendered?.forEach((node) => {
|
|
1672
|
-
this.explorer.renderedNodeMap.set(node.id, node);
|
|
1673
|
-
renderedNodes.set(node.id, node);
|
|
1674
|
-
});
|
|
1675
|
-
for (let i = 0; i < graph?.nodesRendered?.length; i++) {
|
|
1676
|
-
this.renderedNodeMap.set(graph.nodesRendered[i].id, graph.nodesRendered[i]);
|
|
1677
|
-
}
|
|
1678
|
-
graph?.nodes?.forEach((node) => {
|
|
1679
|
-
this.nodeMap.set(node.id, node);
|
|
1680
|
-
if (node.idHash.includes('root')) {
|
|
1681
|
-
this.nodeIdMap.set('root', node);
|
|
1682
|
-
this.nodeIdHashMap.set(node.id, node);
|
|
1683
|
-
}
|
|
1684
|
-
else {
|
|
1685
|
-
this.nodeIdMap.set(node.id, node);
|
|
1686
|
-
this.nodeIdHashMap.set(node.idHash, node);
|
|
1687
|
-
}
|
|
1688
|
-
if (node.filtered) {
|
|
1689
|
-
this.filteredNodes.set(node.id, node);
|
|
1690
|
-
}
|
|
1691
|
-
const renderedNode = this.renderedNodeMap.get(node.id);
|
|
1692
|
-
if (this.activeNode?.id === node.id && this.renderedNodeMap.get(node.id)) {
|
|
1693
|
-
if (this.renderedNode && renderedNode) {
|
|
1694
|
-
this.renderedNode.node = renderedNode;
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
});
|
|
1698
|
-
this.graphBag?.set(GraphBag, graph);
|
|
1699
|
-
this.explorer.updateGraphResponse(graph);
|
|
1700
|
-
if (graph && graph.nodes) {
|
|
1701
|
-
this.modelTree.node = graph?.nodesRendered[0]; // update tree
|
|
1702
|
-
}
|
|
1703
|
-
if (!this.explorer.equalizer.isInitialized()) {
|
|
1704
|
-
this.explorer.equalizer.initializeEqualizer();
|
|
1705
|
-
}
|
|
1706
|
-
else {
|
|
1707
|
-
this.explorer.equalizer.runEQ(true);
|
|
1708
|
-
}
|
|
1709
|
-
// sync timeline
|
|
1710
|
-
this.timeVortex.checkHistory();
|
|
1711
|
-
}
|
|
1712
|
-
customRulesetEnabled(event) {
|
|
1713
|
-
const customRS = { rules: new Map() };
|
|
1714
|
-
customRS.id = crypto.randomUUID();
|
|
1715
|
-
customRS.owner = this.authController.session.sessionId;
|
|
1716
|
-
event.detail.rules.forEach((rule) => {
|
|
1717
|
-
if (rule.rule.id != rule.ruleId) {
|
|
1718
|
-
rule.rule.id = rule.ruleId;
|
|
1719
|
-
}
|
|
1720
|
-
customRS.rules.set(rule.ruleId, rule.rule);
|
|
1721
|
-
});
|
|
1722
|
-
// write state
|
|
1723
|
-
this.customRulesetBag?.set(CustomRulesetBag, customRS);
|
|
1724
|
-
if (event.detail.ruleConfig) {
|
|
1725
|
-
this.ruleConfigBag?.set(RuleConfigurationBag, event.detail.ruleConfig);
|
|
1726
|
-
}
|
|
1727
|
-
else {
|
|
1728
|
-
this.ruleConfigBag?.reset();
|
|
1729
|
-
// reset session ruleset
|
|
1730
|
-
RulesetService.resetSessionRuleset(event.detail.rulesetReset).then(() => {
|
|
1731
|
-
this.sendToast({
|
|
1732
|
-
id: crypto.randomUUID(),
|
|
1733
|
-
type: ToastType.INFO,
|
|
1734
|
-
body: "Ruleset has been reset to the default",
|
|
1735
|
-
title: "Ruleset reset",
|
|
1736
|
-
});
|
|
1737
|
-
if (this.docBag) {
|
|
1738
|
-
const doc = this.docBag.get(DefaultDocument);
|
|
1739
|
-
let path = this.rolodexActivePath;
|
|
1740
|
-
if (path == 'root') {
|
|
1741
|
-
path = "";
|
|
1742
|
-
}
|
|
1743
|
-
this.lintSpec(doc, this.rolodexActivePath);
|
|
1744
|
-
}
|
|
1745
|
-
this.fetchSessionRulesetAsYaml().then((result) => {
|
|
1746
|
-
this.rulesetEditor?.setValue(result, true);
|
|
1747
|
-
});
|
|
1748
|
-
}).catch((e) => {
|
|
1749
|
-
this.sendToast({
|
|
1750
|
-
id: crypto.randomUUID(),
|
|
1751
|
-
type: ToastType.ERROR,
|
|
1752
|
-
body: e.detail,
|
|
1753
|
-
title: "Cannot reset ruleset",
|
|
1754
|
-
});
|
|
1755
|
-
});
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
async fetchSessionRulesetAsYaml() {
|
|
1759
|
-
return new Promise(async (resolve, reject) => {
|
|
1760
|
-
RulesetService.getSessionRulesetAsYAML().then((result) => {
|
|
1761
|
-
resolve(result);
|
|
1762
|
-
}).catch((e) => {
|
|
1763
|
-
console.error("cannot fetch session ruleset: ", e.title);
|
|
1764
|
-
reject(e);
|
|
1765
|
-
});
|
|
1766
|
-
});
|
|
1767
|
-
}
|
|
1768
|
-
async fetchFunctions() {
|
|
1769
|
-
return new Promise(async (resolve) => {
|
|
1770
|
-
RulesetService.getFunctions().then((result) => {
|
|
1771
|
-
this.functions = result;
|
|
1772
|
-
this.functionsBag?.set(FunctionsBag, result);
|
|
1773
|
-
// extract schemas for each function
|
|
1774
|
-
const promises = [];
|
|
1775
|
-
result.forEach((functionId) => {
|
|
1776
|
-
promises.push(this.fetchFunctionSchema(functionId));
|
|
1777
|
-
});
|
|
1778
|
-
Promise.all(promises).then(() => {
|
|
1779
|
-
resolve(result);
|
|
1780
|
-
});
|
|
1781
|
-
});
|
|
1782
|
-
});
|
|
1783
|
-
}
|
|
1784
|
-
async fetchFunctionSchema(functionId) {
|
|
1785
|
-
return new Promise(async (resolve) => {
|
|
1786
|
-
RulesetService.getFunctionSchema(functionId).then((result) => {
|
|
1787
|
-
let m = this.functionSchemaBag?.get(FunctionsSchemaBag);
|
|
1788
|
-
if (!m) {
|
|
1789
|
-
m = new Map();
|
|
1790
|
-
}
|
|
1791
|
-
m.set(functionId, result);
|
|
1792
|
-
this.functionSchemaBag?.set(FunctionsSchemaBag, m);
|
|
1793
|
-
resolve(result);
|
|
1794
|
-
});
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
1797
|
-
async fetchDefaultRuleset() {
|
|
1798
|
-
return new Promise(async (resolve) => {
|
|
1799
|
-
RulesetService.getDefaultRuleset().then((result) => {
|
|
1800
|
-
this.defaultRuleset = result;
|
|
1801
|
-
this.defaultRulesetBag?.set(DefaultRulesetBag, result);
|
|
1802
|
-
resolve(result);
|
|
1803
|
-
});
|
|
1804
|
-
});
|
|
1805
|
-
}
|
|
1806
|
-
async fetchOWASPRuleset() {
|
|
1807
|
-
return new Promise(async (resolve) => {
|
|
1808
|
-
RulesetService.getOWASPRuleset().then((result) => {
|
|
1809
|
-
this.OWASPRuleset = result;
|
|
1810
|
-
this.OWASPRulesetBag?.set(OWASPRulesetBag, result);
|
|
1811
|
-
resolve(result);
|
|
1812
|
-
});
|
|
1813
|
-
});
|
|
1814
|
-
}
|
|
1815
|
-
async fetchAllRuleset() {
|
|
1816
|
-
return new Promise(async (resolve) => {
|
|
1817
|
-
RulesetService.getAllRuleset().then((result) => {
|
|
1818
|
-
this.allRuleset = result;
|
|
1819
|
-
this.allRulesetBag?.set(AllRulesetBag, result);
|
|
1820
|
-
resolve(result);
|
|
1821
|
-
});
|
|
1822
|
-
});
|
|
1823
|
-
}
|
|
1824
|
-
fetchDocs() {
|
|
1825
|
-
this.activitySpinner.show();
|
|
1826
|
-
const url = new URL(window.location.href);
|
|
1827
|
-
const urlParam = url.searchParams.get('url');
|
|
1828
|
-
if (urlParam) {
|
|
1829
|
-
//this.urlInput.value = urlParam;
|
|
1830
|
-
this.activeURL = urlParam;
|
|
1831
|
-
this.lintSpec('', urlParam);
|
|
1832
|
-
}
|
|
1833
|
-
LintingService.fetchAllHowToFix().then((result) => {
|
|
1834
|
-
if (result) {
|
|
1835
|
-
result.forEach((howToFix) => {
|
|
1836
|
-
this.howToFixBag?.set(howToFix.ruleId, howToFix);
|
|
1837
|
-
});
|
|
1838
|
-
}
|
|
1839
|
-
}).catch((e) => {
|
|
1840
|
-
this.platformUnavailable(e);
|
|
1841
|
-
console.error("documentation service is down");
|
|
1842
|
-
});
|
|
1843
|
-
this.ruleDocsBag = this.bagManager.getBag(RuleDocumentationBag);
|
|
1844
|
-
this.functionDocsBag = this.bagManager.getBag(FunctionDocumentationBag);
|
|
1845
|
-
// populate docs via worker.
|
|
1846
|
-
this.ruleDocsWorker.addEventListener("message", (event) => {
|
|
1847
|
-
const data = event.data;
|
|
1848
|
-
if (data) {
|
|
1849
|
-
data.forEach((doc) => {
|
|
1850
|
-
if (doc.ruleId) {
|
|
1851
|
-
this.ruleDocsBag?.set(doc.ruleId, doc);
|
|
1852
|
-
}
|
|
1853
|
-
if (doc.functionId) {
|
|
1854
|
-
this.functionDocsBag?.set(doc.functionId, doc);
|
|
1855
|
-
}
|
|
1856
|
-
});
|
|
1857
|
-
this.activitySpinner.hide();
|
|
1858
|
-
}
|
|
1859
|
-
});
|
|
1860
|
-
// let ruleDocs: string[] = [];
|
|
1861
|
-
// let functionDocs: string[] = [];
|
|
1862
|
-
// if (this.ruleDocsBag) {
|
|
1863
|
-
// ruleDocs = Array.from(this.ruleDocsBag.export().keys());
|
|
1864
|
-
// }
|
|
1865
|
-
// if (this.functionDocsBag) {
|
|
1866
|
-
// functionDocs = Array.from(this.functionDocsBag.export().keys());
|
|
1867
|
-
// }
|
|
1868
|
-
const fetchDocs = () => {
|
|
1869
|
-
this.ruleDocsWorker.postMessage({
|
|
1870
|
-
start: true,
|
|
1871
|
-
endpoint: this.doctorEndpoint,
|
|
1872
|
-
existingRules: [],
|
|
1873
|
-
existingFunctions: []
|
|
1874
|
-
});
|
|
1875
|
-
};
|
|
1876
|
-
// check expiration
|
|
1877
|
-
if (this.docExpirationBag) {
|
|
1878
|
-
const expiration = this.docExpirationBag.get(DocumentationExpirationBag);
|
|
1879
|
-
// if the docs are older than 15 days, refresh them.
|
|
1880
|
-
if (expiration) {
|
|
1881
|
-
const now = new Date().getTime();
|
|
1882
|
-
const then = new Date(expiration).getTime();
|
|
1883
|
-
// if (now - then > 1296000000) {
|
|
1884
|
-
// fetchDocs();
|
|
1885
|
-
// } else {
|
|
1886
|
-
// this.activitySpinner.hide();
|
|
1887
|
-
// }
|
|
1888
|
-
fetchDocs(); // always fetch for now.
|
|
1889
|
-
}
|
|
1890
|
-
else {
|
|
1891
|
-
fetchDocs();
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
else {
|
|
1895
|
-
fetchDocs();
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
fetchRulesetMap() {
|
|
1899
|
-
RulesetService.getSessionRulesetMap().then((result) => {
|
|
1900
|
-
this.sessionRulesetMapBag?.set(SessionRulesetMapBag, result);
|
|
1901
|
-
}).catch(() => {
|
|
1902
|
-
console.warn("map is empty, or unavailable, Did you submit an empty ruleset?");
|
|
1903
|
-
this.sendToast({
|
|
1904
|
-
id: crypto.randomUUID(),
|
|
1905
|
-
type: ToastType.WARNING,
|
|
1906
|
-
body: "map is empty, or unavailable, Did you submit an empty ruleset?",
|
|
1907
|
-
title: "Issue fetching ruleset map"
|
|
1908
|
-
});
|
|
1909
|
-
});
|
|
1910
|
-
}
|
|
1911
|
-
ruleClicked(evt) {
|
|
1912
|
-
// get rule map from bag
|
|
1913
|
-
const map = this.sessionRulesetMapBag?.get(SessionRulesetMapBag);
|
|
1914
|
-
if (map) {
|
|
1915
|
-
const rule = map.rulesMap.find((r) => r.ruleId === evt.detail.ruleId);
|
|
1916
|
-
if (rule) {
|
|
1917
|
-
this.selectedEditorTab = "ruleset";
|
|
1918
|
-
this.editorTabGroup.show(ActiveView.Ruleset);
|
|
1919
|
-
this.rulesetEditor.editor?.setPosition({ lineNumber: rule.line, column: rule.start });
|
|
1920
|
-
this.rulesetEditor.editor?.revealLineInCenter(rule.line);
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
421
|
builtInRulesetSelected() {
|
|
1925
422
|
// todo
|
|
1926
423
|
}
|
|
1927
|
-
rulesetManuallyChanged() {
|
|
1928
|
-
clearTimeout(this.bounceId);
|
|
1929
|
-
this.bounceId = window.setTimeout(() => {
|
|
1930
|
-
const ruleset = this.rulesetEditor.editor?.getValue();
|
|
1931
|
-
RulesetService.validateRuleset(ruleset).then((result) => {
|
|
1932
|
-
// clear any problems
|
|
1933
|
-
this.manageRuleset.clearRuleProblems();
|
|
1934
|
-
// create a new custom ruleset with a map of rules
|
|
1935
|
-
let customRS = { rules: new Map() };
|
|
1936
|
-
customRS.id = crypto.randomUUID();
|
|
1937
|
-
customRS.owner = this.authController.session.sessionId;
|
|
1938
|
-
customRS.rules = new Map(Object.entries(result.rules));
|
|
1939
|
-
customRS.rules.forEach((rule, id) => {
|
|
1940
|
-
rule.id = id; // set the id to the key
|
|
1941
|
-
});
|
|
1942
|
-
// write state
|
|
1943
|
-
this.customRulesetBag?.set(CustomRulesetBag, customRS);
|
|
1944
|
-
this.customRuleset = customRS;
|
|
1945
|
-
if (customRS.rules.size > 0) {
|
|
1946
|
-
// rebuild the ruleset management
|
|
1947
|
-
this.manageRuleset.customRulesetManual = customRS;
|
|
1948
|
-
}
|
|
1949
|
-
this.selectedEditorTab = ActiveView.Ruleset;
|
|
1950
|
-
this.controlTabGroup.show(ActiveView.Ruleset);
|
|
1951
|
-
this.rulesetEditor.setMarkers([]);
|
|
1952
|
-
this.fetchRulesetMap();
|
|
1953
|
-
}).catch((e) => {
|
|
1954
|
-
this.sendToast({
|
|
1955
|
-
id: crypto.randomUUID(),
|
|
1956
|
-
type: ToastType.ERROR,
|
|
1957
|
-
body: e.detail,
|
|
1958
|
-
title: e.title
|
|
1959
|
-
});
|
|
1960
|
-
console.error('unable to validate ruleset', e);
|
|
1961
|
-
// process bad rules
|
|
1962
|
-
const ruleErrors = e.body;
|
|
1963
|
-
const markers = [];
|
|
1964
|
-
ruleErrors?.forEach((err) => {
|
|
1965
|
-
markers.push({
|
|
1966
|
-
severity: MarkerSeverity.Error,
|
|
1967
|
-
message: err.ruleError,
|
|
1968
|
-
startLineNumber: err.line,
|
|
1969
|
-
startColumn: err.startCol,
|
|
1970
|
-
endLineNumber: err.line,
|
|
1971
|
-
endColumn: err.endCol
|
|
1972
|
-
});
|
|
1973
|
-
});
|
|
1974
|
-
// convert to JSON
|
|
1975
|
-
RulesetService.convertToJSON(ruleset).then((json) => {
|
|
1976
|
-
// create a new custom ruleset with a map of rules
|
|
1977
|
-
let customRS = { rules: new Map() };
|
|
1978
|
-
customRS.id = crypto.randomUUID();
|
|
1979
|
-
customRS.owner = this.authController.session.sessionId;
|
|
1980
|
-
customRS.rules = new Map(Object.entries(json.rules));
|
|
1981
|
-
customRS.rules.forEach((rule, id) => {
|
|
1982
|
-
if (rule.id != id)
|
|
1983
|
-
rule.id = id; // set the id to the key
|
|
1984
|
-
});
|
|
1985
|
-
this.customRuleset = customRS;
|
|
1986
|
-
if (customRS.rules.size > 0) {
|
|
1987
|
-
// rebuild the ruleset management
|
|
1988
|
-
this.manageRuleset.customRulesetManual = customRS;
|
|
1989
|
-
}
|
|
1990
|
-
this.rulesetEditor.setMarkers([]);
|
|
1991
|
-
// clear any problems
|
|
1992
|
-
this.manageRuleset.clearRuleProblems();
|
|
1993
|
-
// set problems.
|
|
1994
|
-
this.rulesetEditor.setMarkers(markers);
|
|
1995
|
-
this.manageRuleset.processBadRules(ruleErrors);
|
|
1996
|
-
this.controlTabGroup.show(ActiveView.Ruleset);
|
|
1997
|
-
}).catch((e) => {
|
|
1998
|
-
console.error("unable to convert ruleset to JSON", e);
|
|
1999
|
-
});
|
|
2000
|
-
});
|
|
2001
|
-
}, this.debounceTimeRuleset);
|
|
2002
|
-
}
|
|
2003
|
-
specChanged(event) {
|
|
2004
|
-
const editor = this.editorMap.get(event.detail.id);
|
|
2005
|
-
if (editor && event.detail.id === 'ruleset-editor') {
|
|
2006
|
-
this.rulesetManuallyChanged();
|
|
2007
|
-
return;
|
|
2008
|
-
}
|
|
2009
|
-
if (this.docBag) {
|
|
2010
|
-
this.docBag.set(DefaultDocument, event.detail.content);
|
|
2011
|
-
}
|
|
2012
|
-
if (this.autoDiagnose) {
|
|
2013
|
-
clearTimeout(this.bounceId);
|
|
2014
|
-
this.bounceId = window.setTimeout(() => {
|
|
2015
|
-
this.lintSpec(event.detail.content);
|
|
2016
|
-
}, this.debounceTime);
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2019
424
|
runDiagnostics() {
|
|
2020
425
|
if (!this.autoDiagnose) {
|
|
2021
|
-
this.lintSpec(this.editor.getValue());
|
|
426
|
+
this.diagnosticController.lintSpec(this.editor.getValue());
|
|
2022
427
|
}
|
|
2023
428
|
}
|
|
2024
429
|
boostrap() {
|
|
@@ -2028,20 +433,20 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
2028
433
|
if (urlParam) {
|
|
2029
434
|
//this.urlInput.value = urlParam;
|
|
2030
435
|
this.activeURL = urlParam;
|
|
2031
|
-
this.lintSpec('', urlParam);
|
|
436
|
+
this.diagnosticController.lintSpec('', urlParam);
|
|
2032
437
|
return;
|
|
2033
438
|
}
|
|
2034
439
|
setTimeout(() => {
|
|
2035
|
-
this.loadingOverlay.hide();
|
|
2036
440
|
// check for a history
|
|
2037
441
|
this.timeVortex.doctor = this;
|
|
2038
442
|
this.timeVortex.checkHistory();
|
|
2039
443
|
const editorValue = this.docBag?.get(DefaultDocument);
|
|
2040
444
|
if (!editorValue) {
|
|
2041
445
|
LintingService.bootstrapEditor().then((result) => {
|
|
446
|
+
this.loadingOverlay.hide();
|
|
2042
447
|
this.editor.setValue(result, true);
|
|
2043
448
|
this.rolodexActivePath = "";
|
|
2044
|
-
this.specChanged(new CustomEvent(EditorUpdated, {
|
|
449
|
+
this.specController.specChanged(new CustomEvent(EditorUpdated, {
|
|
2045
450
|
detail: {
|
|
2046
451
|
content: result,
|
|
2047
452
|
id: "spec"
|
|
@@ -2049,40 +454,31 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
2049
454
|
}));
|
|
2050
455
|
});
|
|
2051
456
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
457
|
+
else {
|
|
458
|
+
ModelService.getCurrentSpec().then((result) => {
|
|
459
|
+
this.loadingOverlay.hide();
|
|
460
|
+
this.rolodexController.queryRolodex();
|
|
461
|
+
if (result != editorValue) {
|
|
462
|
+
this.editor.setValue(result, true);
|
|
463
|
+
this.rolodexActivePath = "";
|
|
464
|
+
this.specController.specChanged(new CustomEvent(EditorUpdated, {
|
|
465
|
+
detail: {
|
|
466
|
+
content: result,
|
|
467
|
+
id: "spec"
|
|
468
|
+
}
|
|
469
|
+
}));
|
|
470
|
+
}
|
|
471
|
+
});
|
|
2060
472
|
}
|
|
2061
|
-
}
|
|
2062
|
-
if (jsonRS) {
|
|
2063
|
-
let reportData = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(jsonRS, null, 2));
|
|
2064
|
-
this.downloadRulesetLink.download = "ruleset.json";
|
|
2065
|
-
this.downloadRulesetLink.href = reportData;
|
|
2066
|
-
this.downloadRulesetLink.click();
|
|
2067
|
-
this.exportRulesetDialog.hide();
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
exportYAML() {
|
|
2071
|
-
RulesetService.getSessionRulesetAsYAML().then((yaml) => {
|
|
2072
|
-
let reportData = "data:text/yaml;charset=utf-8," + encodeURIComponent(yaml);
|
|
2073
|
-
this.downloadRulesetLink.download = "ruleset.yaml";
|
|
2074
|
-
this.downloadRulesetLink.href = reportData;
|
|
2075
|
-
this.downloadRulesetLink.click();
|
|
2076
|
-
this.exportRulesetDialog.hide();
|
|
2077
|
-
});
|
|
473
|
+
}, 50);
|
|
2078
474
|
}
|
|
2079
475
|
confirmExport() {
|
|
2080
476
|
switch (this.exportSelection.value) {
|
|
2081
477
|
case "json":
|
|
2082
|
-
this.exportJSON();
|
|
478
|
+
this.ruleController.exportJSON();
|
|
2083
479
|
break;
|
|
2084
480
|
case "yaml":
|
|
2085
|
-
this.exportYAML();
|
|
481
|
+
this.ruleController.exportYAML();
|
|
2086
482
|
break;
|
|
2087
483
|
}
|
|
2088
484
|
}
|
|
@@ -2276,6 +672,29 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
2276
672
|
</sl-tab-group>
|
|
2277
673
|
`;
|
|
2278
674
|
}
|
|
675
|
+
const controls = html `
|
|
676
|
+
<div class="controls">
|
|
677
|
+
<sl-tooltip content="Upload zip file or tar.gz (tarball)" placement="top">
|
|
678
|
+
<sl-button ?disabled=${this.importDisabled} class="import-button" variant="text"
|
|
679
|
+
size="small" @click="${() => {
|
|
680
|
+
this.uploadArchive.show();
|
|
681
|
+
}}">
|
|
682
|
+
Import
|
|
683
|
+
</sl-button>
|
|
684
|
+
</sl-tooltip>
|
|
685
|
+
<sl-tooltip content="Nuke / reset workspace" placement="top">
|
|
686
|
+
<sl-icon-button class="nuke-session-button" name="radioactive" @click="${() => {
|
|
687
|
+
this.nukeWorkspace.show();
|
|
688
|
+
}}">
|
|
689
|
+
</sl-icon-button>
|
|
690
|
+
</sl-tooltip>
|
|
691
|
+
</div>`;
|
|
692
|
+
let navigatorView = html `
|
|
693
|
+
${controls}
|
|
694
|
+
${modelTree}
|
|
695
|
+
`;
|
|
696
|
+
if (this.authController.state && this.authController.state.authenticated) {
|
|
697
|
+
}
|
|
2279
698
|
return html `
|
|
2280
699
|
${this.uploadArchive}
|
|
2281
700
|
${this.nukeWorkspace}
|
|
@@ -2308,30 +727,11 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
2308
727
|
${this.activitySpinner}
|
|
2309
728
|
${this.errorBanner}
|
|
2310
729
|
${overlay}
|
|
2311
|
-
|
|
2312
730
|
<sl-split-panel id="explorer-split-panel" class="split-panel-explorer" position="12"
|
|
2313
731
|
@sl-reposition="${this.updateExplorerDivider}">
|
|
2314
732
|
<sl-icon id="split-divider-tree" slot="divider" name="grip-vertical" class="divider-vert"></sl-icon>
|
|
2315
733
|
<div slot="start" class="model-tree">
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
<sl-tooltip content="Upload zip file or tar.gz (tarball)" placement="top">
|
|
2319
|
-
<sl-button ?disabled=${this.importDisabled} class="import-button" variant="text"
|
|
2320
|
-
size="small" @click="${() => {
|
|
2321
|
-
this.uploadArchive.show();
|
|
2322
|
-
}}">
|
|
2323
|
-
Import
|
|
2324
|
-
</sl-button>
|
|
2325
|
-
</sl-tooltip>
|
|
2326
|
-
<sl-tooltip content="Nuke / reset workspace" placement="top">
|
|
2327
|
-
<sl-icon-button class="nuke-session-button" name="radioactive" @click="${() => {
|
|
2328
|
-
this.nukeWorkspace.show();
|
|
2329
|
-
}}">
|
|
2330
|
-
</sl-icon-button>
|
|
2331
|
-
</sl-tooltip>
|
|
2332
|
-
|
|
2333
|
-
</div>
|
|
2334
|
-
${modelTree}
|
|
734
|
+
${navigatorView}
|
|
2335
735
|
${this.creditTicker}
|
|
2336
736
|
</div>
|
|
2337
737
|
<div slot="end">
|
|
@@ -2462,15 +862,17 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
2462
862
|
</sl-split-panel>
|
|
2463
863
|
</div>
|
|
2464
864
|
</sl-split-panel>
|
|
2465
|
-
|
|
2466
865
|
</div>`;
|
|
2467
866
|
}
|
|
867
|
+
randomTicker() {
|
|
868
|
+
return crypto.randomUUID().toString();
|
|
869
|
+
}
|
|
2468
870
|
// <iframe src="${this.doctorEndpoint}/model/scalar-template?z=${this.randomTicker}" width="100%" height="100%" style="border: none"></iframe>
|
|
2469
871
|
fetchUrl(event) {
|
|
2470
872
|
this.activeURL = event.detail.url;
|
|
2471
873
|
this.rolodexNeedsReset = true;
|
|
2472
874
|
this.rolodexActivePath = "/";
|
|
2473
|
-
this.lintSpec('', event.detail.url);
|
|
875
|
+
this.diagnosticController.lintSpec('', event.detail.url);
|
|
2474
876
|
}
|
|
2475
877
|
hideUrlError() {
|
|
2476
878
|
this.urlProblem.style.display = 'none';
|
|
@@ -2574,9 +976,6 @@ __decorate([
|
|
|
2574
976
|
__decorate([
|
|
2575
977
|
query('#inspector-split-panel')
|
|
2576
978
|
], TheDoctor.prototype, "splitPanelInspector", void 0);
|
|
2577
|
-
__decorate([
|
|
2578
|
-
state()
|
|
2579
|
-
], TheDoctor.prototype, "randomTicker", void 0);
|
|
2580
979
|
__decorate([
|
|
2581
980
|
state()
|
|
2582
981
|
], TheDoctor.prototype, "rulesetPulse", void 0);
|