@pb33f/cowboy-components 0.3.1 → 0.3.3

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.
@@ -27,10 +27,21 @@ export default css `
27
27
  color: var(--primary-color);
28
28
  margin-top: 22px;
29
29
  }
30
+
31
+ sl-icon-button {
32
+ font-size: 1.2rem;
33
+ color: var(--primary-color);
34
+ margin-top: 22px;
35
+ }
36
+
37
+
38
+ sl-icon-button.sort {
39
+ margin: 0;
40
+ padding: 0;
41
+ }
30
42
 
31
- sl-icon-button#save-button {
32
- color: var(--warn-color);
33
- animation: pulse-animation 1.5s infinite;
43
+ sl-icon-button.sort::part(base) {
44
+ padding: 7px 5px 2px 10px
34
45
  }
35
46
 
36
47
  @keyframes pulse-animation {
@@ -19,6 +19,8 @@ export declare class ManageRuleset extends LitElement {
19
19
  customWipeDialog: SlDialog;
20
20
  confirmWipeButton: SlButton;
21
21
  allRulesSwitch: SlSwitch;
22
+ sortAlpha: boolean;
23
+ sortSeverity: boolean;
22
24
  private _defaultRuleset;
23
25
  private _owaspRuleset;
24
26
  private _allRuleset;
@@ -43,6 +45,7 @@ export declare class ManageRuleset extends LitElement {
43
45
  clearRuleProblems(): void;
44
46
  processBadRules(ruleError: RuleError[]): void;
45
47
  rulesetSaved(ruleset: RuleSet, returnedRuleset: RuleSet): void;
48
+ private _noSort;
46
49
  private dirty;
47
50
  private copyActiveRulesetCustom;
48
51
  private buildConfig;
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js';
8
8
  import '@shoelace-style/shoelace/dist/components/radio-button/radio-button.js';
9
9
  import '@shoelace-style/shoelace/dist/components/dialog/dialog.js';
10
- import { customElement, query } from "lit/decorators.js";
10
+ import { customElement, property, query } from "lit/decorators.js";
11
11
  import { html, LitElement } from "lit";
12
12
  import manageRulesetCss from "./manage-ruleset.css.js";
13
13
  import { RuleComponent } from "./rule.js";
@@ -26,6 +26,7 @@ export const customRuleset = "custom";
26
26
  let ManageRuleset = class ManageRuleset extends LitElement {
27
27
  constructor() {
28
28
  super();
29
+ this._noSort = false;
29
30
  this._defaultRules = [];
30
31
  this._owaspRules = [];
31
32
  this._allRules = [];
@@ -33,6 +34,8 @@ let ManageRuleset = class ManageRuleset extends LitElement {
33
34
  this._rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
34
35
  this.currentRuleset = defaultRuleset;
35
36
  this.allRulesEnabled = true;
37
+ this.sortAlpha = true;
38
+ this.sortSeverity = false;
36
39
  // @ts-ignore
37
40
  this.addEventListener(RulesetDirty, this.dirty.bind(this));
38
41
  this.addEventListener(RulesetSaved, this.rulesetUpdated.bind(this));
@@ -165,6 +168,7 @@ let ManageRuleset = class ManageRuleset extends LitElement {
165
168
  else {
166
169
  this.copyActiveRulesetCustom();
167
170
  }
171
+ this._noSort = true;
168
172
  }
169
173
  copyActiveRulesetCustom(submittedRule) {
170
174
  const customRules = [];
@@ -493,10 +497,68 @@ let ManageRuleset = class ManageRuleset extends LitElement {
493
497
  }
494
498
  render() {
495
499
  let selectAll = html ``;
500
+ let sortBySeverity = html ``;
501
+ let sortByAlpha = html ``;
496
502
  let numRules = 0;
497
503
  if (this._activeRuleset) {
498
504
  numRules = this._activeRuleset.length;
499
505
  }
506
+ const priority = { error: 0, warn: 1, info: 2 };
507
+ // if sortSeverity or sortAlpha is true, sort the ruleset by alpha or severity, or both starting
508
+ // with severity and then alpha
509
+ if (this.sortSeverity && !this._noSort) {
510
+ console.log('yeah man');
511
+ this._activeRuleset?.sort((a, b) => {
512
+ if (a && b) {
513
+ if (a.rule && b.rule) {
514
+ if (a.rule.severity === b.rule.severity) {
515
+ if (a.rule.id && b.rule.id) {
516
+ if (this.sortAlpha) {
517
+ return a.rule.id.localeCompare(b.rule.id);
518
+ }
519
+ else {
520
+ return b.rule.id.localeCompare(a.rule.id);
521
+ }
522
+ }
523
+ }
524
+ if (a.rule.severity && b.rule.severity) {
525
+ return priority[b.rule.severity] - priority[a.rule.severity];
526
+ }
527
+ }
528
+ }
529
+ return 0;
530
+ });
531
+ }
532
+ else {
533
+ if (!this._noSort) {
534
+ this._activeRuleset?.sort((a, b) => {
535
+ if (a && b) {
536
+ if (a.rule && b.rule) {
537
+ if (a.rule.severity === b.rule.severity) {
538
+ if (a.rule.id && b.rule.id) {
539
+ if (this.sortAlpha) {
540
+ return a.rule.id.localeCompare(b.rule.id);
541
+ }
542
+ else {
543
+ return b.rule.id.localeCompare(a.rule.id);
544
+ }
545
+ }
546
+ }
547
+ if (a.rule.severity && b.rule.severity) {
548
+ if (this.sortSeverity) {
549
+ return priority[b.rule.severity] - priority[a.rule.severity];
550
+ }
551
+ else {
552
+ return priority[a.rule.severity] - priority[b.rule.severity];
553
+ }
554
+ }
555
+ }
556
+ }
557
+ return 0;
558
+ });
559
+ }
560
+ }
561
+ this._noSort = false;
500
562
  if (numRules > 0) {
501
563
  selectAll = html `
502
564
  <div class="toggle-allcheck">
@@ -506,6 +568,14 @@ let ManageRuleset = class ManageRuleset extends LitElement {
506
568
  </sl-switch>
507
569
  </div>
508
570
  `;
571
+ sortByAlpha = html `<div class="sort-by-alpha">
572
+ <sl-icon-button @click="${() => { this.sortAlpha = !this.sortAlpha; }}"
573
+ name="${this.sortAlpha ? 'sort-alpha-down' : 'sort-alpha-down-alt'}" class="sort"></sl-icon-button>
574
+ </div>`;
575
+ sortBySeverity = html `<div class="sort-by-severity">
576
+ <sl-icon-button @click="${() => { this.sortSeverity = !this.sortSeverity; }}"
577
+ name="${this.sortSeverity ? 'sort-down-alt' : 'sort-down'}" class="sort"></sl-icon-button>
578
+ </div>`;
509
579
  }
510
580
  let rules = html `
511
581
  <div class="pb33f-loader">
@@ -552,7 +622,11 @@ let ManageRuleset = class ManageRuleset extends LitElement {
552
622
  </div>
553
623
  </div>
554
624
  <div class="ruleset-body">
555
- ${selectAll}
625
+ <div style="display: flex;">
626
+ ${selectAll}
627
+ ${sortByAlpha}
628
+ ${sortBySeverity}
629
+ </div>
556
630
  ${rules}
557
631
  </div>
558
632
  </div>
@@ -594,6 +668,12 @@ __decorate([
594
668
  __decorate([
595
669
  query('sl-switch')
596
670
  ], ManageRuleset.prototype, "allRulesSwitch", void 0);
671
+ __decorate([
672
+ property({ type: Boolean })
673
+ ], ManageRuleset.prototype, "sortAlpha", void 0);
674
+ __decorate([
675
+ property({ type: Boolean })
676
+ ], ManageRuleset.prototype, "sortSeverity", void 0);
597
677
  ManageRuleset = __decorate([
598
678
  customElement('pb33f-manage-ruleset')
599
679
  ], ManageRuleset);
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, property, query, state } from "lit/decorators.js";
8
8
  import { html, LitElement } from "lit";
9
9
  import { ProblemDrawerEventType } from "../problem-list/details-drawer.js";
10
- import { OpenProblemDrawer, RuleNameUpdated, RulesetDirty } from "../../events/doctor";
10
+ import { OpenProblemDrawer, RuleNameUpdated, RulesetDirty, SeverityChanged } from "../../events/doctor";
11
11
  import { RuleActionComponent } from "./rule-action.js";
12
12
  import ruleCss from "./rule.css.js";
13
13
  import formsCss from "../../css/forms.css.js";
@@ -112,6 +112,13 @@ let RuleInputComponent = class RuleInputComponent extends LitElement {
112
112
  }
113
113
  updateSeverity() {
114
114
  this.rule.severity = this.severity.value;
115
+ this.dispatchEvent(new CustomEvent(SeverityChanged, {
116
+ bubbles: true,
117
+ composed: true,
118
+ detail: {
119
+ severity: this.rule.severity
120
+ }
121
+ }));
115
122
  this.dirty();
116
123
  }
117
124
  updateCategory() {
@@ -62,7 +62,9 @@ export default css `
62
62
 
63
63
  sl-details::part(header) {
64
64
  font-size: 0.9rem;
65
- padding: 5px;
65
+ padding-top: 5px;
66
+ padding-bottom: 8px;
67
+ padding-left: 0;
66
68
  font-family: var(--font-stack-bold), monospace;
67
69
  }
68
70
 
@@ -15,10 +15,12 @@ import ruleCss from "./rule.css.js";
15
15
  import formsCss from "../../css/forms.css.js";
16
16
  import buttonCss from "../../css/button.css.js";
17
17
  import "./rule-action.js";
18
- import { RuleClicked, RuleNameUpdated, RulesetDirty } from "../../events/doctor.js";
18
+ import { RuleClicked, RuleNameUpdated, RulesetDirty, SeverityChanged } from "../../events/doctor.js";
19
19
  import { RuleInputComponent } from "./rule-input.js";
20
20
  import linksCss from "../../css/links.css.js";
21
21
  import listsCss from "../../css/lists.css.js";
22
+ import { NodeType } from "../../model/node_type.js";
23
+ import { IconColor, IconSize } from "../model-icon/model-icon.js";
22
24
  let RuleComponent = class RuleComponent extends LitElement {
23
25
  constructor(rule, id, custom) {
24
26
  super();
@@ -35,6 +37,11 @@ let RuleComponent = class RuleComponent extends LitElement {
35
37
  this.ruleInput.addEventListener(RuleNameUpdated, (evt) => {
36
38
  this.nameUpdated(evt.detail.name);
37
39
  });
40
+ //@ts-ignore
41
+ this.ruleInput.addEventListener(SeverityChanged, (evt) => {
42
+ this.rule.severity = evt.detail.severity;
43
+ this.requestUpdate();
44
+ });
38
45
  }
39
46
  nameUpdated(name) {
40
47
  this.rule.id = name;
@@ -108,6 +115,38 @@ let RuleComponent = class RuleComponent extends LitElement {
108
115
  </div>
109
116
  </div>`;
110
117
  }
118
+ let summary = html ``;
119
+ switch (this.rule.severity) {
120
+ case 'error':
121
+ summary = html `
122
+ <div slot="summary">
123
+ <pb33f-model-icon style="margin-right: 5px;"
124
+ icon="${NodeType.ERROR}"
125
+ color="${IconColor.error}"
126
+ size="${IconSize.small}"></pb33f-model-icon>
127
+ ${this.rule.id}
128
+ </div>`;
129
+ break;
130
+ case 'warn':
131
+ summary = html `<div slot="summary">
132
+ <pb33f-model-icon style="margin-right: 5px;"
133
+ icon="${NodeType.WARNING}"
134
+ color="${IconColor.warning}"
135
+ size="${IconSize.small}"></pb33f-model-icon>
136
+ ${this.rule.id}
137
+ </div>`;
138
+ break;
139
+ case 'info':
140
+ summary = html `
141
+ <div slot="summary">
142
+ <pb33f-model-icon style="margin-right: 5px;"
143
+ icon="${NodeType.INFO}"
144
+ color="${IconColor.primary}"
145
+ size="${IconSize.small}"></pb33f-model-icon>
146
+ ${this.rule.id}
147
+ </div>`;
148
+ break;
149
+ }
111
150
  return html `
112
151
  <div class="rule">
113
152
  <div class="check">
@@ -115,8 +154,8 @@ let RuleComponent = class RuleComponent extends LitElement {
115
154
  </div>
116
155
  ${errorCol}
117
156
  <div class="details">
118
- <sl-details summary="${this.rule.id}"
119
- class="${this.error ? 'error-rule' : ''}" @sl-show="${this.opened}">
157
+ <sl-details class="${this.error ? 'error-rule' : ''}" @sl-show="${this.opened}">
158
+ ${summary}
120
159
  ${errorBox}
121
160
  ${this.ruleInput}
122
161
  </sl-details>
@@ -61,6 +61,16 @@ let RenderedSchemaNodeComponent = class RenderedSchemaNodeComponent extends HasE
61
61
  if (typeof this.schema !== 'object') {
62
62
  return html `<div class="schema-item">${this.schema}</div>`;
63
63
  }
64
+ // check if this is just a string array, if so, just render it
65
+ if (Array.isArray(this.schema) && this.schema.every(item => typeof item === 'string')) {
66
+ return html `
67
+ <div class="schema-item" style="display: block">
68
+
69
+ ${this.schema.map((item, index) => {
70
+ return html `<div>[${index}] <code class="root" style="margin-left: 2px">${item}</code></div>`;
71
+ })}
72
+ </div>`;
73
+ }
64
74
  const sch = this.schema;
65
75
  if (isHasRef(sch)) {
66
76
  const segs = this.schema.$ref?.split('/');
@@ -60,9 +60,6 @@ let DiagnosticEvaluation = class DiagnosticEvaluation extends LitElement {
60
60
  render() {
61
61
  this.links = [];
62
62
  let parsed = this.convertToLinks(marked.parse(this.diagnosis).toString());
63
- this.links.sort((a, b) => {
64
- return a.localeCompare(b);
65
- });
66
63
  const renderedLinks = this.links.map((link) => {
67
64
  return html `<li><a href="#" @click=${() => { this.viewRuleDocs(link); }}>${link}</a></li>`;
68
65
  });
@@ -1,5 +1,6 @@
1
1
  import { LitElement, TemplateResult } from "lit";
2
2
  import { ProblemItem } from "../problem-list/problem-item.js";
3
+ import { MarkerSeverity } from "monaco-editor";
3
4
  export declare class ProblemOverviewGroup extends LitElement {
4
5
  static styles: import("lit").CSSResult[];
5
6
  rank: number;
@@ -7,6 +8,7 @@ export declare class ProblemOverviewGroup extends LitElement {
7
8
  groupName: string;
8
9
  description: string;
9
10
  category: string;
11
+ severity: MarkerSeverity;
10
12
  violationPercent: number;
11
13
  problems: ProblemItem[];
12
14
  constructor();
@@ -12,6 +12,7 @@ import { OpenProblemDrawer, ProblemClicked, RuleViolationClicked } from "../../e
12
12
  import sharedCss from "../../css/shared.css.js";
13
13
  import buttonCss from "../../css/button.css.js";
14
14
  import { ProblemItem } from "../problem-list/problem-item.js";
15
+ import { MarkerSeverity } from "monaco-editor";
15
16
  let ProblemOverviewGroup = class ProblemOverviewGroup extends LitElement {
16
17
  constructor() {
17
18
  super();
@@ -64,13 +65,22 @@ let ProblemOverviewGroup = class ProblemOverviewGroup extends LitElement {
64
65
  if (!this.groupName || this.groupName === '') {
65
66
  this.groupName = 'invalid OpenAPI specification';
66
67
  }
68
+ let severity = html ``;
69
+ if (this.severity === MarkerSeverity.Error) {
70
+ clazz = "error";
71
+ severity = html `
72
+ <pb33f-model-icon color="error" size="small" icon="error"></pb33f-model-icon>
73
+ `;
74
+ pc = html `
75
+ <pb33f-percent-bar value="${this.violationPercent}" error></pb33f-percent-bar>`;
76
+ }
67
77
  return html `
68
78
  <div class="problem-overview-group">
69
79
  <div class="group-rank">
70
- <span>${this.rank}</span>
80
+ <span class="${clazz}">${this.rank}</span>
71
81
  </div>
72
82
  <div class="group-details">
73
- <span class="name ${clazz}" @click="${this.viewRuleDocs}">${this.groupName}</span>
83
+ ${severity}<span class="name ${clazz}" @click="${this.viewRuleDocs}">${this.groupName}</span>
74
84
  ${pc}
75
85
  </div>
76
86
  <div class="violations">
@@ -109,6 +119,9 @@ __decorate([
109
119
  __decorate([
110
120
  property()
111
121
  ], ProblemOverviewGroup.prototype, "category", void 0);
122
+ __decorate([
123
+ property()
124
+ ], ProblemOverviewGroup.prototype, "severity", void 0);
112
125
  __decorate([
113
126
  property({ type: Number })
114
127
  ], ProblemOverviewGroup.prototype, "violationPercent", void 0);
@@ -42,6 +42,7 @@ let ProblemsOverview = class ProblemsOverview extends LitElement {
42
42
  const group = new ProblemOverviewGroup();
43
43
  group.groupName = problem.problemObject.source;
44
44
  group.totalViolations = 1;
45
+ group.severity = problem.problemObject.severity;
45
46
  group.problems = [problem];
46
47
  problemOverviewGroups.set(rule, group);
47
48
  }
@@ -52,9 +53,14 @@ let ProblemsOverview = class ProblemsOverview extends LitElement {
52
53
  group.violationPercent = Math.round((group.totalViolations / totalViolations) * 100);
53
54
  }
54
55
  const values = Array.from(problemOverviewGroups.values());
55
- // order by violations
56
+ // order by violations, errors first.
56
57
  values.sort((a, b) => {
57
- return b.totalViolations - a.totalViolations;
58
+ if (a.severity === b.severity) {
59
+ return b.totalViolations - a.totalViolations;
60
+ }
61
+ else {
62
+ return b.severity - a.severity;
63
+ }
58
64
  });
59
65
  // stack rank.
60
66
  for (let i = 0; i < values.length; i++) {
@@ -54,7 +54,9 @@ let FeedbackComponent = class FeedbackComponent extends LitElement {
54
54
  <p>
55
55
  If you would like to report an issue we can track, please use <a href="https://github.com/pb33f/doctor/issues">github</a>.
56
56
  </p>
57
-
57
+ <p>
58
+ To learn more about the Doctor, <a href="https://quobix.com/articles/introducing-the-doctor/">read this article</a>.
59
+ </p>
58
60
  <p>
59
61
  Want to talk to <a href="https://quobix.com">quobix</a> live? join the <a href="https://discord.gg/UAcUF78MQN">discord</a>.
60
62
  </p>
@@ -40,6 +40,7 @@ export declare class TheDoctor extends LitElement {
40
40
  overviewPanel: SlTab;
41
41
  problemsPanel: SlTab;
42
42
  viewerPanel: SlTab;
43
+ explorerPanel: SlTab;
43
44
  controlTabGroup: SlTabGroup;
44
45
  editorTabGroup: SlTabGroup;
45
46
  welcomeBox: AttentionBox;
@@ -109,6 +110,7 @@ export declare class TheDoctor extends LitElement {
109
110
  activeNode: Node;
110
111
  readonly nodeLimit: number;
111
112
  constructor(doctorEndpoint?: string);
113
+ addClickTrack(node: Node): void;
112
114
  filterTreeModel(event: CustomEvent<ExplorerEqualizerChangedEvent>): void;
113
115
  explorerReferenceClicked(evt: CustomEvent<NodeReferenceEvent>): void;
114
116
  modelTreeNodeClicked(evt: CustomEvent<NodeClickedEvent>): void;
@@ -144,17 +144,19 @@ let TheDoctor = class TheDoctor extends LitElement {
144
144
  window.addEventListener('popstate', (e) => {
145
145
  const state = e.state;
146
146
  if (state) {
147
- switch (state.view) {
148
- case ActiveView.Problems:
149
- this.controlTabGroup.show(ActiveView.Problems);
150
- break;
151
- case ActiveView.Overview:
152
- this.controlTabGroup.show(ActiveView.Overview);
153
- break;
147
+ if (state.activeNode) {
148
+ this.modelTreeNodeClicked(new CustomEvent(ExplorerNodeClicked, {
149
+ detail: {
150
+ nodeHashId: state.activeNode,
151
+ noState: true
152
+ }
153
+ }));
154
154
  }
155
155
  }
156
156
  });
157
- //history.pushState({view: ActiveView.Overview}, "", ActiveView.Overview);
157
+ }
158
+ addClickTrack(node) {
159
+ history.pushState({ activeNode: node.idHash }, "", `?view=explore&node=${node.idHash}`);
158
160
  }
159
161
  filterTreeModel(event) {
160
162
  this.filteredNodes = new Map();
@@ -206,6 +208,10 @@ let TheDoctor = class TheDoctor extends LitElement {
206
208
  if (renderedNode) {
207
209
  this.renderedNode.node = renderedNode;
208
210
  }
211
+ if (!evt.detail.noState) {
212
+ this.addClickTrack(node);
213
+ evt.detail.noState = true;
214
+ }
209
215
  this.explorerNodeClicked(evt);
210
216
  this.viewerPanel.click();
211
217
  }
@@ -223,6 +229,9 @@ let TheDoctor = class TheDoctor extends LitElement {
223
229
  this.activeNode = node.body.node;
224
230
  this.explorer.activeNode = node.body.node;
225
231
  found = true;
232
+ if (!evt.detail.noState) {
233
+ this.addClickTrack(node.body.node);
234
+ }
226
235
  }
227
236
  else {
228
237
  node.body.active = false;
@@ -1167,7 +1176,7 @@ let TheDoctor = class TheDoctor extends LitElement {
1167
1176
  ${this.activitySpinner}
1168
1177
  ${this.errorBanner}
1169
1178
  ${overlay}
1170
-
1179
+
1171
1180
  <sl-split-panel class="split-panel-explorer" position="12">
1172
1181
  <sl-icon id="split-divider-tree" slot="divider" name="grip-vertical"></sl-icon>
1173
1182
  <div slot="start" class="model-tree">
@@ -1180,10 +1189,10 @@ let TheDoctor = class TheDoctor extends LitElement {
1180
1189
  ${this.detailsDrawer}
1181
1190
  <sl-tab-group class="tab-group" @sl-tab-show="${this.selectEditorTab}"
1182
1191
  id="editor-controls">
1192
+
1183
1193
  <sl-tab slot="nav" panel="spec" class="tab" id="spec"
1184
1194
  @click="${this.closeExplorer}">
1185
- OpenAPI
1186
- Spec
1195
+ OpenAPI Spec
1187
1196
  </sl-tab>
1188
1197
  <sl-tab slot="nav" panel="explorer" class="tab" id="explorer"
1189
1198
  @click="${this.toggleExplorer}">Explorer
@@ -1192,11 +1201,13 @@ let TheDoctor = class TheDoctor extends LitElement {
1192
1201
  @click="${this.closeExplorer}">
1193
1202
  Ruleset ${rulesetPulsePill}
1194
1203
  </sl-tab>
1204
+
1195
1205
  <sl-tab-panel name="spec" class="tab-panel">${this.editor}</sl-tab-panel>
1196
1206
  <sl-tab-panel name="ruleset" class="tab-panel">${this.rulesetEditor}</sl-tab-panel>
1197
1207
  <sl-tab-panel name="explorer" class="tab-panel"
1198
1208
  @mouseleave="${this.ungrabExplorer}">${this.explorer}
1199
1209
  </sl-tab-panel>
1210
+
1200
1211
  </sl-tab-group>
1201
1212
  </div>
1202
1213
  ${mainPanelView}
@@ -1205,6 +1216,13 @@ let TheDoctor = class TheDoctor extends LitElement {
1205
1216
  </sl-split-panel>
1206
1217
  ${this.statusBar}
1207
1218
  </div>`;
1219
+ // docs <iframe src="/docs.html" width="100%" height="100%"
1220
+ // style="border: none"></iframe>
1221
+ // <sl-tab slot="nav" panel="docs" class="tab" id="docs">
1222
+ // Docs
1223
+ // </sl-tab>
1224
+ // <sl-tab-panel name="docs" class="tab-panel">
1225
+ // </sl-tab-panel>
1208
1226
  }
1209
1227
  ungrabExplorer() {
1210
1228
  this.explorer.grabbed = false;
@@ -1220,6 +1238,9 @@ __decorate([
1220
1238
  __decorate([
1221
1239
  query('#viewerPanel')
1222
1240
  ], TheDoctor.prototype, "viewerPanel", void 0);
1241
+ __decorate([
1242
+ query('#explorer')
1243
+ ], TheDoctor.prototype, "explorerPanel", void 0);
1223
1244
  __decorate([
1224
1245
  query('sl-tab-group#manager-controls')
1225
1246
  ], TheDoctor.prototype, "controlTabGroup", void 0);