@pb33f/cowboy-components 0.3.3 → 0.3.4
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/manage-ruleset/manage-ruleset.js +7 -4
- package/dist/components/paginator/paginator-navigator.js +3 -0
- package/dist/components/paginator/paginator.css.js +5 -2
- package/dist/components/paginator/paginator.d.ts +1 -0
- package/dist/components/paginator/paginator.js +9 -3
- package/dist/components/the-doctor/sparks.d.ts +17 -0
- package/dist/components/the-doctor/sparks.js +81 -0
- package/dist/components/the-doctor/the-doctor.css.js +74 -26
- package/dist/components/the-doctor/the-doctor.d.ts +29 -1
- package/dist/components/the-doctor/the-doctor.js +204 -23
- package/dist/cowboy-components.umd.cjs +1040 -941
- package/dist/model/channels.d.ts +11 -0
- package/dist/model/channels.js +11 -0
- package/dist/model/errors.d.ts +1 -1
- package/dist/services/header-service.d.ts +5 -0
- package/dist/services/header-service.js +16 -0
- package/dist/services/linting-service.d.ts +1 -1
- package/dist/services/linting-service.js +19 -9
- package/package.json +1 -1
|
@@ -44,6 +44,11 @@ import { ModelTree } from "../model-tree/tree.js";
|
|
|
44
44
|
import { ExplorerComponent } from "../visualizer/explorer.js";
|
|
45
45
|
import { RenderedNodeComponent } from "../model-renderer/rendered-node.js";
|
|
46
46
|
import tabsCss from "../../css/tabs.css.js";
|
|
47
|
+
import { CreateBus } from "@pb33f/ranch";
|
|
48
|
+
import { Command, DoctorServiceChannel, isBrokerResponse, QueuePrefix, SpecStreamChannel } from "../../model/channels";
|
|
49
|
+
import formsCss from "../../css/forms.css";
|
|
50
|
+
import { PixelSparks } from "./sparks.js";
|
|
51
|
+
import spinnerCss from "../../css/spinner.css";
|
|
47
52
|
export const GraphBag = "pb33f-doctor-graph";
|
|
48
53
|
export const DoctorDocumentBag = "pb33f-doctor-editor";
|
|
49
54
|
export const HowToFixBag = "pb33f-doctor-howtofix";
|
|
@@ -67,6 +72,15 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
67
72
|
this.debounceTime = 400;
|
|
68
73
|
this.debounceTimeRuleset = 900;
|
|
69
74
|
this.bounceId = 0;
|
|
75
|
+
this.useTLS = false;
|
|
76
|
+
// bus it up
|
|
77
|
+
this.bus = CreateBus();
|
|
78
|
+
this.doctorServiceChannel = this.bus.createChannel(DoctorServiceChannel);
|
|
79
|
+
this.specStreamChannel = this.bus.createChannel(SpecStreamChannel);
|
|
80
|
+
this.bus.mapChannelToBrokerDestination(QueuePrefix + DoctorServiceChannel, DoctorServiceChannel);
|
|
81
|
+
this.bus.mapChannelToBrokerDestination(QueuePrefix + SpecStreamChannel, SpecStreamChannel);
|
|
82
|
+
this.doctorChannelSubscription = this.doctorServiceChannel.subscribe(this.doctorServiceHandler());
|
|
83
|
+
this.specChannelSubscription = this.specStreamChannel.subscribe(this.specStreamHandler());
|
|
70
84
|
// create a stateful bag manager
|
|
71
85
|
this.bagManager = CreateBagManager(true);
|
|
72
86
|
this.bagManager.loadStatefulBags().then(this.loadState.bind(this));
|
|
@@ -140,6 +154,19 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
140
154
|
this.explorer.equalizer.addEventListener(ExplorerEqualizerChanged, this.filterTreeModel.bind(this));
|
|
141
155
|
//@ts-ignore
|
|
142
156
|
this.explorer.equalizer.addEventListener(ExplorerEqualizerFiltered, this.filterTreeModel.bind(this));
|
|
157
|
+
// extract port from session storage.
|
|
158
|
+
this.busPort = localStorage.getItem("pb33f-doctor-port");
|
|
159
|
+
this.busHost = localStorage.getItem("pb33f-doctor-host");
|
|
160
|
+
if (!this.busPort) {
|
|
161
|
+
this.busPort = "9090"; // default port
|
|
162
|
+
}
|
|
163
|
+
if (!this.busHost) {
|
|
164
|
+
this.busHost = "localhost"; // default host
|
|
165
|
+
}
|
|
166
|
+
const useTLS = localStorage.getItem("pb33f-doctor-tls");
|
|
167
|
+
if (useTLS && useTLS == 'true') {
|
|
168
|
+
this.useTLS = true;
|
|
169
|
+
}
|
|
143
170
|
// hijack navigation buttons.
|
|
144
171
|
window.addEventListener('popstate', (e) => {
|
|
145
172
|
const state = e.state;
|
|
@@ -155,9 +182,57 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
155
182
|
}
|
|
156
183
|
});
|
|
157
184
|
}
|
|
185
|
+
whoAmI() {
|
|
186
|
+
this.bus.publish({
|
|
187
|
+
destination: "/p/q/" + DoctorServiceChannel,
|
|
188
|
+
body: JSON.stringify({ request: Command.WhoAmI }),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
connectToBroker() {
|
|
192
|
+
let protocol = "ws://";
|
|
193
|
+
if (this.useTLS) {
|
|
194
|
+
protocol = "wss://";
|
|
195
|
+
}
|
|
196
|
+
// configure wiretap broker.
|
|
197
|
+
const config = {
|
|
198
|
+
brokerURL: protocol + this.busHost + ':' + this.busPort + '/ranch',
|
|
199
|
+
heartbeatIncoming: 0,
|
|
200
|
+
heartbeatOutgoing: 0,
|
|
201
|
+
onConnect: () => {
|
|
202
|
+
console.log("💊 Connected to the %cOpenAPI Doctor%c, we are ready to communicate.", 'background: #0d1117; color: #62C4FFFF; font-weight: bold', 'color: default');
|
|
203
|
+
this.whoAmI();
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
this.bus.connectToBroker(config);
|
|
207
|
+
}
|
|
158
208
|
addClickTrack(node) {
|
|
159
209
|
history.pushState({ activeNode: node.idHash }, "", `?view=explore&node=${node.idHash}`);
|
|
160
210
|
}
|
|
211
|
+
doctorServiceHandler() {
|
|
212
|
+
return (msg) => {
|
|
213
|
+
if (msg.payload?.payload != null) {
|
|
214
|
+
if (isBrokerResponse(msg.payload.payload)) {
|
|
215
|
+
this.brokerConnectionId = msg.payload.payload.broker;
|
|
216
|
+
console.log("💊 Welcome patient %c" + this.brokerConnectionId, 'color: #62C4FFFF; font-weight: bold');
|
|
217
|
+
this.boostrap();
|
|
218
|
+
this.loadingOverlay.hide();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
specStreamHandler() {
|
|
224
|
+
return (msg) => {
|
|
225
|
+
if (msg.payload?.payload != null) {
|
|
226
|
+
// base64 decode the payload and update the editor!
|
|
227
|
+
const decoded = atob(msg.payload.payload);
|
|
228
|
+
if (this.docBag) {
|
|
229
|
+
this.docBag.set(DefaultDocument, decoded);
|
|
230
|
+
}
|
|
231
|
+
this.editor?.setValue(decoded, true);
|
|
232
|
+
this.requestUpdate();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
161
236
|
filterTreeModel(event) {
|
|
162
237
|
this.filteredNodes = new Map();
|
|
163
238
|
event.detail.graph.nodes.forEach((node) => {
|
|
@@ -362,9 +437,19 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
362
437
|
}
|
|
363
438
|
}
|
|
364
439
|
}
|
|
365
|
-
lintSpec(value) {
|
|
440
|
+
lintSpec(value, url) {
|
|
366
441
|
this.activitySpinner.show();
|
|
367
|
-
|
|
442
|
+
if (url) {
|
|
443
|
+
this.urlProblem.style.display = 'none';
|
|
444
|
+
this.urlOverlay.style.display = "block";
|
|
445
|
+
this.urlSpinner.style.display = "block";
|
|
446
|
+
}
|
|
447
|
+
LintingService.lintFile(value, this.brokerConnectionId, url).then((result) => {
|
|
448
|
+
if (url) {
|
|
449
|
+
this.urlOverlay.style.display = "none";
|
|
450
|
+
this.urlSpinner.style.display = "none";
|
|
451
|
+
this.urlProblem.style.display = 'none';
|
|
452
|
+
}
|
|
368
453
|
if (result && !Array.isArray(result)) {
|
|
369
454
|
this.editor.setMarkers([result]);
|
|
370
455
|
this.problemBag?.set(DocumentProblems, [result]);
|
|
@@ -424,21 +509,26 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
424
509
|
this.platformUnavailable(e);
|
|
425
510
|
});
|
|
426
511
|
}).catch((e) => {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
512
|
+
if (!url) {
|
|
513
|
+
this.platformUnavailable(e);
|
|
514
|
+
console.error("so sorry, the doctor cannot see you right now, the clinic is closed.");
|
|
515
|
+
if (e) {
|
|
516
|
+
console.error(e.detail);
|
|
517
|
+
if (e.instance === 'https://pb33f.io/errors/no-credit-remaining') {
|
|
518
|
+
this.statusBar.callsRemaining = 0;
|
|
519
|
+
this.statusBar.visible = true;
|
|
520
|
+
this.sendToast({
|
|
521
|
+
id: crypto.randomUUID(),
|
|
522
|
+
type: ToastType.ERROR,
|
|
523
|
+
body: "Run out of credit, please authenticate for more or wait 24 hours.",
|
|
524
|
+
title: "Credit exhausted!",
|
|
525
|
+
});
|
|
526
|
+
}
|
|
440
527
|
}
|
|
441
528
|
}
|
|
529
|
+
else {
|
|
530
|
+
this.showUrlError(e);
|
|
531
|
+
}
|
|
442
532
|
});
|
|
443
533
|
}
|
|
444
534
|
platformUnavailable(error) {
|
|
@@ -536,6 +626,7 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
536
626
|
FeedbackService.doctorEndpoint = this.doctorEndpoint;
|
|
537
627
|
RulesetService.doctorEndpoint = this.doctorEndpoint;
|
|
538
628
|
ModelService.doctorEndpoint = this.doctorEndpoint;
|
|
629
|
+
this.connectToBroker();
|
|
539
630
|
this.graphBag = this.bagManager.getBag(GraphBag);
|
|
540
631
|
this.docBag = this.bagManager.getBag(DoctorDocumentBag);
|
|
541
632
|
if (this.docBag) {
|
|
@@ -644,7 +735,6 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
644
735
|
else {
|
|
645
736
|
this.manageRuleset.rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
|
|
646
737
|
}
|
|
647
|
-
this.loadingOverlay.hide();
|
|
648
738
|
setTimeout(() => {
|
|
649
739
|
this.manageRuleset.buildRulesets();
|
|
650
740
|
if (this.CustomRuleset && this.CustomRuleset.rules.size > 0) {
|
|
@@ -826,9 +916,9 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
826
916
|
LintingService.startSession().then((session) => {
|
|
827
917
|
this.session = session;
|
|
828
918
|
// bootstrap async
|
|
829
|
-
setTimeout(() => {
|
|
830
|
-
|
|
831
|
-
});
|
|
919
|
+
// setTimeout(() => {
|
|
920
|
+
// this.boostrap();
|
|
921
|
+
// });
|
|
832
922
|
LintingService.fetchAllHowToFix().then((result) => {
|
|
833
923
|
if (result) {
|
|
834
924
|
result.forEach((howToFix) => {
|
|
@@ -982,6 +1072,14 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
982
1072
|
}, this.debounceTime);
|
|
983
1073
|
}
|
|
984
1074
|
boostrap() {
|
|
1075
|
+
// if the url is set in the query string, fetch it and run a lint with the URL
|
|
1076
|
+
const url = new URL(window.location.href);
|
|
1077
|
+
const urlParam = url.searchParams.get('url');
|
|
1078
|
+
if (urlParam) {
|
|
1079
|
+
this.urlInput.value = urlParam;
|
|
1080
|
+
this.lintSpec('', urlParam);
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
985
1083
|
if (this.editor.getValue() === '') {
|
|
986
1084
|
LintingService.bootstrapEditor().then((result) => {
|
|
987
1085
|
this.editor.setValue(result, true);
|
|
@@ -1146,6 +1244,7 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
1146
1244
|
<sl-icon-button class="collapse-side" name="chevron-bar-right"
|
|
1147
1245
|
@click="${this.toggleSidebar}"></sl-icon-button>
|
|
1148
1246
|
</div>`;
|
|
1247
|
+
let sparks = new PixelSparks();
|
|
1149
1248
|
return html `
|
|
1150
1249
|
${welcomeBox}
|
|
1151
1250
|
${this.toastManager}
|
|
@@ -1201,13 +1300,45 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
1201
1300
|
@click="${this.closeExplorer}">
|
|
1202
1301
|
Ruleset ${rulesetPulsePill}
|
|
1203
1302
|
</sl-tab>
|
|
1204
|
-
|
|
1205
|
-
<sl-tab-panel name="spec" class="tab-panel"
|
|
1303
|
+
|
|
1304
|
+
<sl-tab-panel name="spec" class="tab-panel">
|
|
1305
|
+
|
|
1306
|
+
<div class="controls">
|
|
1307
|
+
<div style="margin-top: 8px; margin-right: 5px;">URL:</div>
|
|
1308
|
+
<sl-input id="url-input" class="url-input"
|
|
1309
|
+
placeholder="https://api.pb33f.io/train-travel.yaml" size="small"
|
|
1310
|
+
@keydown="${this.validateUrl}"
|
|
1311
|
+
@keyup="${this.validateUrl}"></sl-input>
|
|
1312
|
+
<sl-button id="url-input-button" class="url-input-button close-button"
|
|
1313
|
+
size="small" variant="neutral" disabled
|
|
1314
|
+
@click="${this.fetchUrl}">Fetch
|
|
1315
|
+
</sl-button>
|
|
1316
|
+
</div>
|
|
1317
|
+
<div class="main-view">
|
|
1318
|
+
<div id="editor-url-overlay" class="editor-url-overlay">
|
|
1319
|
+
<div id="url-spinner">
|
|
1320
|
+
<div class="pb33f-loader">
|
|
1321
|
+
<div class="spin"></div>
|
|
1322
|
+
Fetching from URL '<strong>${this.activeURL}</strong>'...
|
|
1323
|
+
</div>
|
|
1324
|
+
</div>
|
|
1325
|
+
<div id="url-problem" class="url-problem">
|
|
1326
|
+
<pb33f-attention-box type="warning" headerText="Problem with URL">
|
|
1327
|
+
<h4>Error: ${this.urlErrorCode}</h4>
|
|
1328
|
+
<p>${this.urlErrorMessage}</p>
|
|
1329
|
+
<sl-button @click="${this.hideUrlError}">OK</sl-button>
|
|
1330
|
+
<p></p>
|
|
1331
|
+
</pb33f-attention-box>
|
|
1332
|
+
</div>
|
|
1333
|
+
</div>
|
|
1334
|
+
${this.editor}
|
|
1335
|
+
</div>
|
|
1336
|
+
</sl-tab-panel>
|
|
1206
1337
|
<sl-tab-panel name="ruleset" class="tab-panel">${this.rulesetEditor}</sl-tab-panel>
|
|
1207
1338
|
<sl-tab-panel name="explorer" class="tab-panel"
|
|
1208
1339
|
@mouseleave="${this.ungrabExplorer}">${this.explorer}
|
|
1209
1340
|
</sl-tab-panel>
|
|
1210
|
-
|
|
1341
|
+
|
|
1211
1342
|
</sl-tab-group>
|
|
1212
1343
|
</div>
|
|
1213
1344
|
${mainPanelView}
|
|
@@ -1224,11 +1355,42 @@ let TheDoctor = class TheDoctor extends LitElement {
|
|
|
1224
1355
|
// <sl-tab-panel name="docs" class="tab-panel">
|
|
1225
1356
|
// </sl-tab-panel>
|
|
1226
1357
|
}
|
|
1358
|
+
fetchUrl() {
|
|
1359
|
+
this.activeURL = this.urlInput.value;
|
|
1360
|
+
this.lintSpec('', this.urlInput.value);
|
|
1361
|
+
}
|
|
1362
|
+
hideUrlError() {
|
|
1363
|
+
this.urlProblem.style.display = 'none';
|
|
1364
|
+
this.urlOverlay.style.display = 'none';
|
|
1365
|
+
this.urlSpinner.style.display = 'none';
|
|
1366
|
+
}
|
|
1367
|
+
showUrlError(e) {
|
|
1368
|
+
this.urlErrorCode = e.status;
|
|
1369
|
+
this.urlErrorMessage = e.detail;
|
|
1370
|
+
this.urlSpinner.style.display = 'none';
|
|
1371
|
+
this.urlOverlay.style.display = 'block';
|
|
1372
|
+
this.urlProblem.style.display = 'block';
|
|
1373
|
+
this.requestUpdate();
|
|
1374
|
+
}
|
|
1375
|
+
validateUrl(evt) {
|
|
1376
|
+
if (evt.key === "Enter") {
|
|
1377
|
+
this.fetchUrl();
|
|
1378
|
+
}
|
|
1379
|
+
const urlValue = this.urlInput.value;
|
|
1380
|
+
if (urlValue.match(urlRegex)) {
|
|
1381
|
+
this.urlInputButton.disabled = false;
|
|
1382
|
+
this.urlInputButton.classList.remove('close-button');
|
|
1383
|
+
}
|
|
1384
|
+
else {
|
|
1385
|
+
this.urlInputButton.disabled = true;
|
|
1386
|
+
this.urlInputButton.classList.add('close-button');
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1227
1389
|
ungrabExplorer() {
|
|
1228
1390
|
this.explorer.grabbed = false;
|
|
1229
1391
|
}
|
|
1230
1392
|
};
|
|
1231
|
-
TheDoctor.styles = [theDoctorCss, linksCss, dialogCss, buttonCss, radioGroupsCss, tabsCss];
|
|
1393
|
+
TheDoctor.styles = [theDoctorCss, linksCss, dialogCss, buttonCss, radioGroupsCss, tabsCss, formsCss, spinnerCss];
|
|
1232
1394
|
__decorate([
|
|
1233
1395
|
query('#overviewPanel')
|
|
1234
1396
|
], TheDoctor.prototype, "overviewPanel", void 0);
|
|
@@ -1262,6 +1424,12 @@ __decorate([
|
|
|
1262
1424
|
__decorate([
|
|
1263
1425
|
query('div.problems-data')
|
|
1264
1426
|
], TheDoctor.prototype, "problemsDataDiv", void 0);
|
|
1427
|
+
__decorate([
|
|
1428
|
+
query('#url-input-button')
|
|
1429
|
+
], TheDoctor.prototype, "urlInputButton", void 0);
|
|
1430
|
+
__decorate([
|
|
1431
|
+
query('#url-input')
|
|
1432
|
+
], TheDoctor.prototype, "urlInput", void 0);
|
|
1265
1433
|
__decorate([
|
|
1266
1434
|
property({ type: Boolean })
|
|
1267
1435
|
], TheDoctor.prototype, "unavailable", void 0);
|
|
@@ -1286,7 +1454,20 @@ __decorate([
|
|
|
1286
1454
|
__decorate([
|
|
1287
1455
|
state()
|
|
1288
1456
|
], TheDoctor.prototype, "explorerVisible", void 0);
|
|
1457
|
+
__decorate([
|
|
1458
|
+
state()
|
|
1459
|
+
], TheDoctor.prototype, "activeURL", void 0);
|
|
1460
|
+
__decorate([
|
|
1461
|
+
query('#editor-url-overlay')
|
|
1462
|
+
], TheDoctor.prototype, "urlOverlay", void 0);
|
|
1463
|
+
__decorate([
|
|
1464
|
+
query('#url-problem')
|
|
1465
|
+
], TheDoctor.prototype, "urlProblem", void 0);
|
|
1466
|
+
__decorate([
|
|
1467
|
+
query('#url-spinner')
|
|
1468
|
+
], TheDoctor.prototype, "urlSpinner", void 0);
|
|
1289
1469
|
TheDoctor = __decorate([
|
|
1290
1470
|
customElement("pb33f-doctor")
|
|
1291
1471
|
], TheDoctor);
|
|
1292
1472
|
export { TheDoctor };
|
|
1473
|
+
const urlRegex = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
|