@emeryld/rrroutes-contract 2.7.10 → 2.7.12
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/README.md +1 -1
- package/dist/export/defaultViewerTemplate.d.ts +1 -1
- package/dist/export/flattenSchema.d.ts +1 -0
- package/dist/index.cjs +35 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +35 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tools/finalized-leaves-viewer.html +435 -141
|
@@ -50,22 +50,68 @@
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.controls {
|
|
53
|
+
display: grid;
|
|
54
|
+
gap: 14px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.primary-row {
|
|
53
58
|
display: grid;
|
|
54
59
|
gap: 10px;
|
|
60
|
+
grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.4fr) minmax(220px, 1fr);
|
|
61
|
+
align-items: end;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.control-block {
|
|
65
|
+
display: grid;
|
|
66
|
+
gap: 6px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.control-label {
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
color: var(--muted);
|
|
55
72
|
}
|
|
56
73
|
|
|
57
|
-
.
|
|
74
|
+
.quick-toggles {
|
|
58
75
|
display: flex;
|
|
59
76
|
flex-wrap: wrap;
|
|
60
77
|
gap: 8px;
|
|
78
|
+
align-items: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.scope-row {
|
|
82
|
+
border-top: 1px solid var(--border);
|
|
83
|
+
padding-top: 12px;
|
|
84
|
+
display: grid;
|
|
85
|
+
gap: 10px;
|
|
61
86
|
}
|
|
62
87
|
|
|
63
|
-
.
|
|
88
|
+
.scope-actions {
|
|
64
89
|
display: flex;
|
|
65
90
|
flex-wrap: wrap;
|
|
66
91
|
gap: 8px;
|
|
67
92
|
}
|
|
68
93
|
|
|
94
|
+
.scope-groups {
|
|
95
|
+
display: grid;
|
|
96
|
+
gap: 10px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.scope-group {
|
|
100
|
+
display: grid;
|
|
101
|
+
gap: 6px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.scope-group-title {
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
color: var(--muted);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.scope-group-chips {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-wrap: wrap;
|
|
112
|
+
gap: 6px;
|
|
113
|
+
}
|
|
114
|
+
|
|
69
115
|
.field-item {
|
|
70
116
|
display: inline-flex;
|
|
71
117
|
align-items: center;
|
|
@@ -86,7 +132,7 @@
|
|
|
86
132
|
|
|
87
133
|
button {
|
|
88
134
|
border: 1px solid var(--border);
|
|
89
|
-
border-radius:
|
|
135
|
+
border-radius: 6px;
|
|
90
136
|
padding: 7px 10px;
|
|
91
137
|
font: inherit;
|
|
92
138
|
background: var(--surface-2);
|
|
@@ -190,12 +236,82 @@
|
|
|
190
236
|
background: var(--surface-2);
|
|
191
237
|
}
|
|
192
238
|
|
|
239
|
+
.chip-btn {
|
|
240
|
+
cursor: pointer;
|
|
241
|
+
}
|
|
242
|
+
|
|
193
243
|
.chip.ok {
|
|
194
244
|
border-color: #b5e4c8;
|
|
195
245
|
color: var(--ok);
|
|
196
246
|
background: #effbf4;
|
|
197
247
|
}
|
|
198
248
|
|
|
249
|
+
.pill-toggle {
|
|
250
|
+
border: 1px solid var(--border);
|
|
251
|
+
border-radius: 999px;
|
|
252
|
+
padding: 6px 12px;
|
|
253
|
+
font-size: 12px;
|
|
254
|
+
background: var(--surface-2);
|
|
255
|
+
color: var(--text);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.pill-toggle[aria-pressed='true'] {
|
|
259
|
+
border-color: var(--accent);
|
|
260
|
+
background: rgba(167, 100, 211, 0.25);
|
|
261
|
+
color: #f0d8ff;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.scope-action {
|
|
265
|
+
font-size: 12px;
|
|
266
|
+
padding: 5px 10px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.field-chip {
|
|
270
|
+
font-size: 12px;
|
|
271
|
+
padding: 5px 10px;
|
|
272
|
+
border-radius: 999px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.field-chip[aria-pressed='true'] {
|
|
276
|
+
border-color: var(--schema-accent);
|
|
277
|
+
background: rgba(251, 189, 35, 0.22);
|
|
278
|
+
color: #ffe7aa;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.advanced-panel {
|
|
282
|
+
border-top: 1px solid var(--border);
|
|
283
|
+
padding-top: 10px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.advanced-panel > summary {
|
|
287
|
+
color: var(--text);
|
|
288
|
+
font-size: 13px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.advanced-content {
|
|
292
|
+
margin-top: 10px;
|
|
293
|
+
display: flex;
|
|
294
|
+
flex-wrap: wrap;
|
|
295
|
+
gap: 12px;
|
|
296
|
+
align-items: center;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.advanced-content .field-item {
|
|
300
|
+
padding: 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.active-filters-row {
|
|
304
|
+
border-top: 1px solid var(--border);
|
|
305
|
+
padding-top: 10px;
|
|
306
|
+
display: grid;
|
|
307
|
+
gap: 6px;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.active-filters-title {
|
|
311
|
+
color: var(--muted);
|
|
312
|
+
font-size: 12px;
|
|
313
|
+
}
|
|
314
|
+
|
|
199
315
|
.icon-row {
|
|
200
316
|
display: flex;
|
|
201
317
|
gap: 6px;
|
|
@@ -214,6 +330,16 @@
|
|
|
214
330
|
background: var(--surface-2);
|
|
215
331
|
}
|
|
216
332
|
|
|
333
|
+
.icon-badge.feed {
|
|
334
|
+
width: auto;
|
|
335
|
+
min-width: 46px;
|
|
336
|
+
padding: 2px 8px;
|
|
337
|
+
font-weight: 700;
|
|
338
|
+
border-color: var(--schema-accent);
|
|
339
|
+
color: var(--schema-accent);
|
|
340
|
+
background: rgba(251, 189, 35, 0.15);
|
|
341
|
+
}
|
|
342
|
+
|
|
217
343
|
.icon-badge.warn {
|
|
218
344
|
border-color: #f2d5d5;
|
|
219
345
|
color: #a02424;
|
|
@@ -329,6 +455,11 @@
|
|
|
329
455
|
}
|
|
330
456
|
|
|
331
457
|
@media (max-width: 720px) {
|
|
458
|
+
.primary-row {
|
|
459
|
+
grid-template-columns: 1fr;
|
|
460
|
+
align-items: stretch;
|
|
461
|
+
}
|
|
462
|
+
|
|
332
463
|
.grid-3 {
|
|
333
464
|
grid-template-columns: 1fr;
|
|
334
465
|
}
|
|
@@ -339,47 +470,65 @@
|
|
|
339
470
|
<div class="wrap">
|
|
340
471
|
<h1>Finalized Leaves Viewer</h1>
|
|
341
472
|
<div class="card controls">
|
|
342
|
-
<
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<label>
|
|
348
|
-
Search text:
|
|
349
|
-
<input id="searchInput" type="text" placeholder="Type to search..." />
|
|
350
|
-
</label>
|
|
351
|
-
|
|
352
|
-
<div class="field-row">
|
|
353
|
-
<label class="field-item">
|
|
354
|
-
<input id="caseSensitive" type="checkbox" />
|
|
355
|
-
<span>case sensitive</span>
|
|
356
|
-
</label>
|
|
357
|
-
<label class="field-item">
|
|
358
|
-
<input id="regexSearch" type="checkbox" />
|
|
359
|
-
<span>regex</span>
|
|
473
|
+
<div class="primary-row">
|
|
474
|
+
<label class="control-block">
|
|
475
|
+
<span class="control-label">Load export JSON file</span>
|
|
476
|
+
<input id="fileInput" type="file" accept="application/json,.json" />
|
|
360
477
|
</label>
|
|
361
|
-
<label class="
|
|
362
|
-
<span>
|
|
363
|
-
<
|
|
364
|
-
<option value="contains" selected>contains</option>
|
|
365
|
-
<option value="exact">exact</option>
|
|
366
|
-
</select>
|
|
367
|
-
</label>
|
|
368
|
-
<label class="field-item">
|
|
369
|
-
<input id="schemaRowsMatchOnly" type="checkbox" />
|
|
370
|
-
<span>schema rows match filter</span>
|
|
478
|
+
<label class="control-block">
|
|
479
|
+
<span class="control-label">Search text</span>
|
|
480
|
+
<input id="searchInput" type="text" placeholder="Type to search..." />
|
|
371
481
|
</label>
|
|
482
|
+
<div class="control-block">
|
|
483
|
+
<span class="control-label">Quick filters</span>
|
|
484
|
+
<div class="quick-toggles">
|
|
485
|
+
<button id="caseSensitive" class="pill-toggle" type="button" aria-pressed="false">
|
|
486
|
+
Case sensitive
|
|
487
|
+
</button>
|
|
488
|
+
<button id="regexSearch" class="pill-toggle" type="button" aria-pressed="false">
|
|
489
|
+
Regex
|
|
490
|
+
</button>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<div class="scope-row">
|
|
496
|
+
<div class="scope-actions">
|
|
497
|
+
<button id="selectAllFields" class="scope-action" type="button">All</button>
|
|
498
|
+
<button id="clearAllFields" class="scope-action" type="button">None</button>
|
|
499
|
+
<button id="coreFields" class="scope-action" type="button">Core</button>
|
|
500
|
+
<button id="schemasOnlyFields" class="scope-action" type="button">Schema</button>
|
|
501
|
+
<button id="sourceOnlyFields" class="scope-action" type="button">Source</button>
|
|
502
|
+
</div>
|
|
503
|
+
<div id="fieldChipGroups" class="scope-groups"></div>
|
|
372
504
|
</div>
|
|
373
505
|
|
|
374
|
-
<
|
|
375
|
-
|
|
376
|
-
<
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
506
|
+
<details class="advanced-panel">
|
|
507
|
+
<summary>Advanced filters</summary>
|
|
508
|
+
<div class="advanced-content">
|
|
509
|
+
<label class="field-item">
|
|
510
|
+
<span>type match</span>
|
|
511
|
+
<select id="typeMatchMode">
|
|
512
|
+
<option value="contains" selected>contains</option>
|
|
513
|
+
<option value="exact">exact</option>
|
|
514
|
+
</select>
|
|
515
|
+
</label>
|
|
516
|
+
<button
|
|
517
|
+
id="schemaRowsMatchOnly"
|
|
518
|
+
class="pill-toggle"
|
|
519
|
+
type="button"
|
|
520
|
+
aria-pressed="false"
|
|
521
|
+
>
|
|
522
|
+
Schema rows match only
|
|
523
|
+
</button>
|
|
524
|
+
<button id="resetFilters" type="button">Reset filters</button>
|
|
525
|
+
</div>
|
|
526
|
+
</details>
|
|
527
|
+
|
|
528
|
+
<div class="active-filters-row">
|
|
529
|
+
<div class="active-filters-title">Active filters</div>
|
|
530
|
+
<div id="activeFilterChips" class="chips filters"></div>
|
|
381
531
|
</div>
|
|
382
|
-
<div id="activeFilterChips" class="chips filters"></div>
|
|
383
532
|
|
|
384
533
|
<div id="status" class="meta">Load a JSON export to begin.</div>
|
|
385
534
|
</div>
|
|
@@ -461,24 +610,56 @@
|
|
|
461
610
|
|
|
462
611
|
const SCHEMA_SECTIONS = ['params', 'query', 'body', 'output']
|
|
463
612
|
const SCHEMA_FIELD_IDS = new Set(SCHEMA_SECTIONS)
|
|
464
|
-
const
|
|
465
|
-
|
|
613
|
+
const SOURCE_FIELD_IDS = new Set(['sourceDefinition', 'sourceSchemas'])
|
|
614
|
+
const SCHEMA_SCOPE_FIELD_IDS = new Set([...SCHEMA_SECTIONS, 'types'])
|
|
615
|
+
const CORE_FIELD_IDS = new Set(
|
|
616
|
+
SEARCH_FIELDS.map((field) => field.id).filter(
|
|
617
|
+
(id) => !SCHEMA_SCOPE_FIELD_IDS.has(id) && !SOURCE_FIELD_IDS.has(id),
|
|
618
|
+
),
|
|
466
619
|
)
|
|
620
|
+
const FIELD_GROUPS = [
|
|
621
|
+
{
|
|
622
|
+
id: 'core',
|
|
623
|
+
label: 'Core fields',
|
|
624
|
+
fieldIds: SEARCH_FIELDS.filter((field) => CORE_FIELD_IDS.has(field.id)).map(
|
|
625
|
+
(field) => field.id,
|
|
626
|
+
),
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: 'schema',
|
|
630
|
+
label: 'Schema fields',
|
|
631
|
+
fieldIds: SEARCH_FIELDS.filter((field) => SCHEMA_SCOPE_FIELD_IDS.has(field.id)).map(
|
|
632
|
+
(field) => field.id,
|
|
633
|
+
),
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
id: 'source',
|
|
637
|
+
label: 'Source fields',
|
|
638
|
+
fieldIds: SEARCH_FIELDS.filter((field) => SOURCE_FIELD_IDS.has(field.id)).map(
|
|
639
|
+
(field) => field.id,
|
|
640
|
+
),
|
|
641
|
+
},
|
|
642
|
+
]
|
|
467
643
|
|
|
468
|
-
const state = {
|
|
644
|
+
const state = {
|
|
645
|
+
payload: null,
|
|
646
|
+
leaves: [],
|
|
647
|
+
selectedFieldIds: new Set(SEARCH_FIELDS.map((field) => field.id)),
|
|
648
|
+
}
|
|
469
649
|
|
|
470
650
|
const fileInput = document.getElementById('fileInput')
|
|
471
651
|
const searchInput = document.getElementById('searchInput')
|
|
472
|
-
const
|
|
473
|
-
const
|
|
652
|
+
const caseSensitiveToggle = document.getElementById('caseSensitive')
|
|
653
|
+
const regexSearchToggle = document.getElementById('regexSearch')
|
|
474
654
|
const typeMatchModeInput = document.getElementById('typeMatchMode')
|
|
475
|
-
const
|
|
476
|
-
const
|
|
655
|
+
const schemaRowsMatchOnlyToggle = document.getElementById('schemaRowsMatchOnly')
|
|
656
|
+
const fieldChipGroups = document.getElementById('fieldChipGroups')
|
|
477
657
|
const activeFilterChips = document.getElementById('activeFilterChips')
|
|
478
658
|
const selectAllFieldsBtn = document.getElementById('selectAllFields')
|
|
479
659
|
const clearAllFieldsBtn = document.getElementById('clearAllFields')
|
|
660
|
+
const coreFieldsBtn = document.getElementById('coreFields')
|
|
480
661
|
const schemasOnlyFieldsBtn = document.getElementById('schemasOnlyFields')
|
|
481
|
-
const
|
|
662
|
+
const sourceOnlyFieldsBtn = document.getElementById('sourceOnlyFields')
|
|
482
663
|
const resetFiltersBtn = document.getElementById('resetFilters')
|
|
483
664
|
const statusEl = document.getElementById('status')
|
|
484
665
|
const resultsEl = document.getElementById('results')
|
|
@@ -499,6 +680,21 @@
|
|
|
499
680
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
500
681
|
}
|
|
501
682
|
|
|
683
|
+
function isPressed(button) {
|
|
684
|
+
return button?.getAttribute('aria-pressed') === 'true'
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function setPressed(button, pressed) {
|
|
688
|
+
if (!button) return
|
|
689
|
+
button.setAttribute('aria-pressed', pressed ? 'true' : 'false')
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function togglePressed(button) {
|
|
693
|
+
const next = !isPressed(button)
|
|
694
|
+
setPressed(button, next)
|
|
695
|
+
return next
|
|
696
|
+
}
|
|
697
|
+
|
|
502
698
|
function createSearchEngine(queryRaw, options) {
|
|
503
699
|
const query = queryRaw || ''
|
|
504
700
|
const caseSensitive = Boolean(options.caseSensitive)
|
|
@@ -697,13 +893,6 @@
|
|
|
697
893
|
return matched
|
|
698
894
|
}
|
|
699
895
|
|
|
700
|
-
function selectedFieldIds() {
|
|
701
|
-
return SEARCH_FIELDS.filter((field) => {
|
|
702
|
-
const input = document.getElementById(`field-${field.id}`)
|
|
703
|
-
return Boolean(input && input.checked)
|
|
704
|
-
}).map((field) => field.id)
|
|
705
|
-
}
|
|
706
|
-
|
|
707
896
|
function matchesLeaf(leaf, engine, selectedIds) {
|
|
708
897
|
if (!engine.active) return true
|
|
709
898
|
if (selectedIds.length === 0) return false
|
|
@@ -773,12 +962,27 @@
|
|
|
773
962
|
function sourceHref(source) {
|
|
774
963
|
if (!source || !source.file) return undefined
|
|
775
964
|
const normalizedPath = String(source.file).replace(/\\/g, '/')
|
|
776
|
-
const
|
|
777
|
-
|
|
965
|
+
const platform =
|
|
966
|
+
(navigator.userAgentData && navigator.userAgentData.platform) ||
|
|
967
|
+
navigator.platform ||
|
|
968
|
+
''
|
|
969
|
+
const isWindows = /win/i.test(platform)
|
|
970
|
+
const vscodePath = isWindows
|
|
971
|
+
? normalizedPath.replace(/^\/+/, '')
|
|
972
|
+
: normalizedPath.startsWith('/')
|
|
973
|
+
? normalizedPath
|
|
974
|
+
: `/${normalizedPath}`
|
|
975
|
+
const line = Number.isFinite(source.line) ? source.line : 1
|
|
976
|
+
const column = Number.isFinite(source.column) ? source.column : 1
|
|
977
|
+
|
|
978
|
+
return `vscode://file/${encodeURI(vscodePath)}:${line}:${column}`
|
|
778
979
|
}
|
|
779
980
|
|
|
780
981
|
function sourceDisplay(source) {
|
|
781
|
-
return ''
|
|
982
|
+
if (!source || !source.file) return '—'
|
|
983
|
+
const line = Number.isFinite(source.line) ? source.line : 1
|
|
984
|
+
const column = Number.isFinite(source.column) ? source.column : 1
|
|
985
|
+
return `${source.file}:${line}:${column}`
|
|
782
986
|
}
|
|
783
987
|
|
|
784
988
|
function createSourceRow(key, source, engine) {
|
|
@@ -829,6 +1033,28 @@
|
|
|
829
1033
|
return result
|
|
830
1034
|
}
|
|
831
1035
|
|
|
1036
|
+
const SCHEMA_SOURCE_KEYS_BY_SECTION = {
|
|
1037
|
+
params: 'paramsSchema',
|
|
1038
|
+
query: 'querySchema',
|
|
1039
|
+
body: 'bodySchema',
|
|
1040
|
+
output: 'outputSchema',
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
function getSchemaSource(source, sectionName) {
|
|
1044
|
+
const schemaKey = SCHEMA_SOURCE_KEYS_BY_SECTION[sectionName]
|
|
1045
|
+
if (!schemaKey || !source?.schemas || typeof source.schemas !== 'object') {
|
|
1046
|
+
return {
|
|
1047
|
+
schemaKey,
|
|
1048
|
+
sourceValue: undefined,
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
return {
|
|
1053
|
+
schemaKey,
|
|
1054
|
+
sourceValue: source.schemas[schemaKey],
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
832
1058
|
function createTreeNode(name = '') {
|
|
833
1059
|
return {
|
|
834
1060
|
name,
|
|
@@ -916,14 +1142,14 @@
|
|
|
916
1142
|
return row
|
|
917
1143
|
}
|
|
918
1144
|
|
|
919
|
-
function renderSeparatedSchemas(flatSchema, engine, selectedIds) {
|
|
1145
|
+
function renderSeparatedSchemas(flatSchema, engine, selectedIds, source) {
|
|
920
1146
|
if (!flatSchema || typeof flatSchema !== 'object') return null
|
|
921
1147
|
const section = el('div', 'section')
|
|
922
1148
|
section.appendChild(el('h3', '', 'Schemas (separated by section)'))
|
|
923
1149
|
|
|
924
1150
|
const grouped = splitFlatSchemaBySection(flatSchema)
|
|
925
1151
|
let hasAnySchemaEntries = false
|
|
926
|
-
const limitToMatchedRows =
|
|
1152
|
+
const limitToMatchedRows = isPressed(schemaRowsMatchOnlyToggle) && engine.active
|
|
927
1153
|
|
|
928
1154
|
SCHEMA_SECTIONS.forEach((sectionName) => {
|
|
929
1155
|
const rawEntries = grouped[sectionName]
|
|
@@ -944,6 +1170,17 @@
|
|
|
944
1170
|
setHighlighted(header, sectionName, engine)
|
|
945
1171
|
block.appendChild(header)
|
|
946
1172
|
|
|
1173
|
+
const schemaSource = getSchemaSource(source, sectionName)
|
|
1174
|
+
if (schemaSource.sourceValue) {
|
|
1175
|
+
block.appendChild(
|
|
1176
|
+
createSourceRow(
|
|
1177
|
+
schemaSource.schemaKey || `${sectionName}Schema`,
|
|
1178
|
+
schemaSource.sourceValue,
|
|
1179
|
+
engine,
|
|
1180
|
+
),
|
|
1181
|
+
)
|
|
1182
|
+
}
|
|
1183
|
+
|
|
947
1184
|
const tree = buildSchemaTree(entries, sectionName)
|
|
948
1185
|
block.appendChild(renderTreeNode(tree, engine, true))
|
|
949
1186
|
|
|
@@ -977,9 +1214,9 @@
|
|
|
977
1214
|
|
|
978
1215
|
const iconRow = el('div', 'icon-row')
|
|
979
1216
|
if (cfg.feed) {
|
|
980
|
-
const feed = el('span', 'icon-badge')
|
|
981
|
-
feed.title = 'Feed'
|
|
982
|
-
setHighlighted(feed, '
|
|
1217
|
+
const feed = el('span', 'icon-badge feed')
|
|
1218
|
+
feed.title = 'Feed endpoint'
|
|
1219
|
+
setHighlighted(feed, 'Feed', engine)
|
|
983
1220
|
iconRow.appendChild(feed)
|
|
984
1221
|
}
|
|
985
1222
|
if (cfg.deprecated) {
|
|
@@ -1014,30 +1251,11 @@
|
|
|
1014
1251
|
|
|
1015
1252
|
const sourceByLeaf = state.payload?.sourceByLeaf || {}
|
|
1016
1253
|
const source = sourceByLeaf[leaf.key]
|
|
1017
|
-
if (source) {
|
|
1018
|
-
|
|
1019
|
-
sourceSection.appendChild(el('h3', '', 'Source'))
|
|
1020
|
-
sourceSection.appendChild(createSourceRow('definition', source.definition, engine))
|
|
1021
|
-
|
|
1022
|
-
const schemaSources = source.schemas || {}
|
|
1023
|
-
const schemaEntries = Object.entries(schemaSources)
|
|
1024
|
-
if (schemaEntries.length > 0) {
|
|
1025
|
-
const schemaGrid = el('div', 'grid-2')
|
|
1026
|
-
schemaEntries.forEach(([schemaName, schemaSource]) => {
|
|
1027
|
-
const display = schemaSource?.sourceName
|
|
1028
|
-
? `${schemaName}: ${schemaSource.sourceName}`
|
|
1029
|
-
: schemaSource?.tag
|
|
1030
|
-
? `${schemaName}: ${schemaSource.tag}`
|
|
1031
|
-
: schemaName
|
|
1032
|
-
schemaGrid.appendChild(createSourceRow(display, schemaSource, engine))
|
|
1033
|
-
})
|
|
1034
|
-
sourceSection.appendChild(schemaGrid)
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
content.appendChild(sourceSection)
|
|
1254
|
+
if (source?.definition) {
|
|
1255
|
+
overview.appendChild(createSourceRow('definition', source.definition, engine))
|
|
1038
1256
|
}
|
|
1039
1257
|
|
|
1040
|
-
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds)
|
|
1258
|
+
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds, source)
|
|
1041
1259
|
if (separatedSchemas) {
|
|
1042
1260
|
content.appendChild(separatedSchemas)
|
|
1043
1261
|
}
|
|
@@ -1048,8 +1266,8 @@
|
|
|
1048
1266
|
|
|
1049
1267
|
function renderResults() {
|
|
1050
1268
|
const engine = createSearchEngine(searchInput.value.trim(), {
|
|
1051
|
-
caseSensitive:
|
|
1052
|
-
regex:
|
|
1269
|
+
caseSensitive: isPressed(caseSensitiveToggle),
|
|
1270
|
+
regex: isPressed(regexSearchToggle),
|
|
1053
1271
|
})
|
|
1054
1272
|
|
|
1055
1273
|
if (engine.error) {
|
|
@@ -1082,65 +1300,136 @@
|
|
|
1082
1300
|
syncFilterStateToUrl()
|
|
1083
1301
|
}
|
|
1084
1302
|
|
|
1085
|
-
function
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const input = document.createElement('input')
|
|
1090
|
-
input.type = 'checkbox'
|
|
1091
|
-
input.id = `field-${field.id}`
|
|
1092
|
-
input.checked = true
|
|
1093
|
-
input.addEventListener('change', renderResults)
|
|
1094
|
-
label.appendChild(input)
|
|
1095
|
-
label.appendChild(el('span', '', field.label))
|
|
1096
|
-
fieldCheckboxes.appendChild(label)
|
|
1097
|
-
})
|
|
1303
|
+
function selectedFieldIds() {
|
|
1304
|
+
return SEARCH_FIELDS.filter((field) => state.selectedFieldIds.has(field.id)).map(
|
|
1305
|
+
(field) => field.id,
|
|
1306
|
+
)
|
|
1098
1307
|
}
|
|
1099
1308
|
|
|
1100
|
-
function
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1309
|
+
function renderFieldChips() {
|
|
1310
|
+
fieldChipGroups.innerHTML = ''
|
|
1311
|
+
FIELD_GROUPS.forEach((group) => {
|
|
1312
|
+
const groupWrap = el('div', 'scope-group')
|
|
1313
|
+
groupWrap.appendChild(el('div', 'scope-group-title', group.label))
|
|
1314
|
+
const chipsWrap = el('div', 'scope-group-chips')
|
|
1315
|
+
|
|
1316
|
+
group.fieldIds.forEach((fieldId) => {
|
|
1317
|
+
const field = SEARCH_FIELDS.find((item) => item.id === fieldId)
|
|
1318
|
+
if (!field) return
|
|
1319
|
+
const chip = document.createElement('button')
|
|
1320
|
+
chip.type = 'button'
|
|
1321
|
+
chip.className = 'field-chip'
|
|
1322
|
+
chip.textContent = field.label
|
|
1323
|
+
setPressed(chip, state.selectedFieldIds.has(field.id))
|
|
1324
|
+
chip.addEventListener('click', () => {
|
|
1325
|
+
if (state.selectedFieldIds.has(field.id)) {
|
|
1326
|
+
state.selectedFieldIds.delete(field.id)
|
|
1327
|
+
} else {
|
|
1328
|
+
state.selectedFieldIds.add(field.id)
|
|
1329
|
+
}
|
|
1330
|
+
renderFieldChips()
|
|
1331
|
+
renderResults()
|
|
1332
|
+
})
|
|
1333
|
+
chipsWrap.appendChild(chip)
|
|
1334
|
+
})
|
|
1335
|
+
|
|
1336
|
+
groupWrap.appendChild(chipsWrap)
|
|
1337
|
+
fieldChipGroups.appendChild(groupWrap)
|
|
1105
1338
|
})
|
|
1106
|
-
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
function setFieldSelection(allowedIds, options = {}) {
|
|
1342
|
+
const { rerender = true } = options
|
|
1343
|
+
state.selectedFieldIds = new Set(
|
|
1344
|
+
SEARCH_FIELDS.map((field) => field.id).filter((id) => allowedIds.has(id)),
|
|
1345
|
+
)
|
|
1346
|
+
renderFieldChips()
|
|
1347
|
+
if (rerender) renderResults()
|
|
1107
1348
|
}
|
|
1108
1349
|
|
|
1109
1350
|
function resetFiltersToDefault() {
|
|
1110
1351
|
searchInput.value = ''
|
|
1111
|
-
|
|
1112
|
-
|
|
1352
|
+
setPressed(caseSensitiveToggle, false)
|
|
1353
|
+
setPressed(regexSearchToggle, false)
|
|
1113
1354
|
typeMatchModeInput.value = 'contains'
|
|
1114
|
-
|
|
1115
|
-
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)))
|
|
1355
|
+
setPressed(schemaRowsMatchOnlyToggle, false)
|
|
1356
|
+
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)), { rerender: false })
|
|
1357
|
+
renderResults()
|
|
1116
1358
|
}
|
|
1117
1359
|
|
|
1118
1360
|
function renderActiveFilterChips({ selectedIds, hasRegexError }) {
|
|
1119
1361
|
activeFilterChips.innerHTML = ''
|
|
1120
|
-
const chips = []
|
|
1121
|
-
|
|
1122
1362
|
const searchValue = searchInput.value.trim()
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1363
|
+
const chipModels = []
|
|
1364
|
+
|
|
1365
|
+
if (searchValue) {
|
|
1366
|
+
chipModels.push({
|
|
1367
|
+
text: `search: ${searchValue}`,
|
|
1368
|
+
onClick: () => {
|
|
1369
|
+
searchInput.value = ''
|
|
1370
|
+
renderResults()
|
|
1371
|
+
},
|
|
1372
|
+
})
|
|
1373
|
+
}
|
|
1374
|
+
if (typeMatchModeInput.value === 'exact') {
|
|
1375
|
+
chipModels.push({
|
|
1376
|
+
text: 'type mode: exact',
|
|
1377
|
+
onClick: () => {
|
|
1378
|
+
typeMatchModeInput.value = 'contains'
|
|
1379
|
+
renderResults()
|
|
1380
|
+
},
|
|
1381
|
+
})
|
|
1382
|
+
}
|
|
1383
|
+
if (isPressed(schemaRowsMatchOnlyToggle)) {
|
|
1384
|
+
chipModels.push({
|
|
1385
|
+
text: 'schema rows: matched only',
|
|
1386
|
+
onClick: () => {
|
|
1387
|
+
setPressed(schemaRowsMatchOnlyToggle, false)
|
|
1388
|
+
renderResults()
|
|
1389
|
+
},
|
|
1390
|
+
})
|
|
1391
|
+
}
|
|
1392
|
+
if (isPressed(caseSensitiveToggle)) {
|
|
1393
|
+
chipModels.push({
|
|
1394
|
+
text: 'case sensitive',
|
|
1395
|
+
onClick: () => {
|
|
1396
|
+
setPressed(caseSensitiveToggle, false)
|
|
1397
|
+
renderResults()
|
|
1398
|
+
},
|
|
1399
|
+
})
|
|
1400
|
+
}
|
|
1401
|
+
if (isPressed(regexSearchToggle)) {
|
|
1402
|
+
chipModels.push({
|
|
1403
|
+
text: 'regex',
|
|
1404
|
+
onClick: () => {
|
|
1405
|
+
setPressed(regexSearchToggle, false)
|
|
1406
|
+
renderResults()
|
|
1407
|
+
},
|
|
1408
|
+
})
|
|
1409
|
+
}
|
|
1410
|
+
if (hasRegexError) chipModels.push({ text: 'regex error' })
|
|
1130
1411
|
|
|
1131
1412
|
const allIds = SEARCH_FIELDS.map((field) => field.id)
|
|
1132
1413
|
if (selectedIds.length !== allIds.length) {
|
|
1133
|
-
|
|
1414
|
+
chipModels.push({
|
|
1415
|
+
text: `fields: ${selectedIds.join(', ') || 'none'}`,
|
|
1416
|
+
onClick: () => setFieldSelection(new Set(allIds)),
|
|
1417
|
+
})
|
|
1134
1418
|
}
|
|
1135
1419
|
|
|
1136
|
-
if (
|
|
1420
|
+
if (chipModels.length === 0) {
|
|
1137
1421
|
activeFilterChips.appendChild(el('span', 'empty', 'No active filters'))
|
|
1138
1422
|
return
|
|
1139
1423
|
}
|
|
1140
1424
|
|
|
1141
|
-
|
|
1142
|
-
const chip =
|
|
1143
|
-
chip.
|
|
1425
|
+
chipModels.forEach((chipModel) => {
|
|
1426
|
+
const chip = document.createElement(chipModel.onClick ? 'button' : 'span')
|
|
1427
|
+
chip.className = chipModel.onClick ? 'chip chip-btn' : 'chip'
|
|
1428
|
+
chip.textContent = chipModel.text
|
|
1429
|
+
if (chipModel.onClick) {
|
|
1430
|
+
chip.type = 'button'
|
|
1431
|
+
chip.addEventListener('click', chipModel.onClick)
|
|
1432
|
+
}
|
|
1144
1433
|
activeFilterChips.appendChild(chip)
|
|
1145
1434
|
})
|
|
1146
1435
|
}
|
|
@@ -1148,10 +1437,10 @@
|
|
|
1148
1437
|
function collectFilterState() {
|
|
1149
1438
|
return {
|
|
1150
1439
|
search: searchInput.value,
|
|
1151
|
-
caseSensitive:
|
|
1152
|
-
regex:
|
|
1440
|
+
caseSensitive: isPressed(caseSensitiveToggle),
|
|
1441
|
+
regex: isPressed(regexSearchToggle),
|
|
1153
1442
|
typeMatchMode: typeMatchModeInput.value === 'exact' ? 'exact' : 'contains',
|
|
1154
|
-
schemaRowsMatchOnly:
|
|
1443
|
+
schemaRowsMatchOnly: isPressed(schemaRowsMatchOnlyToggle),
|
|
1155
1444
|
selectedFields: selectedFieldIds(),
|
|
1156
1445
|
}
|
|
1157
1446
|
}
|
|
@@ -1178,20 +1467,15 @@
|
|
|
1178
1467
|
const parsed = JSON.parse(decodeURIComponent(raw))
|
|
1179
1468
|
isHydratingFromUrl = true
|
|
1180
1469
|
if (typeof parsed.search === 'string') searchInput.value = parsed.search
|
|
1181
|
-
|
|
1182
|
-
|
|
1470
|
+
setPressed(caseSensitiveToggle, Boolean(parsed.caseSensitive))
|
|
1471
|
+
setPressed(regexSearchToggle, Boolean(parsed.regex))
|
|
1183
1472
|
if (parsed.typeMatchMode === 'exact' || parsed.typeMatchMode === 'contains') {
|
|
1184
1473
|
typeMatchModeInput.value = parsed.typeMatchMode
|
|
1185
1474
|
}
|
|
1186
|
-
|
|
1475
|
+
setPressed(schemaRowsMatchOnlyToggle, Boolean(parsed.schemaRowsMatchOnly))
|
|
1187
1476
|
|
|
1188
1477
|
if (Array.isArray(parsed.selectedFields)) {
|
|
1189
|
-
|
|
1190
|
-
SEARCH_FIELDS.forEach((field) => {
|
|
1191
|
-
const input = document.getElementById(`field-${field.id}`)
|
|
1192
|
-
if (!input) return
|
|
1193
|
-
input.checked = allowed.has(field.id)
|
|
1194
|
-
})
|
|
1478
|
+
setFieldSelection(new Set(parsed.selectedFields), { rerender: false })
|
|
1195
1479
|
}
|
|
1196
1480
|
} catch (error) {
|
|
1197
1481
|
// Ignore malformed hash state.
|
|
@@ -1235,20 +1519,30 @@
|
|
|
1235
1519
|
})
|
|
1236
1520
|
|
|
1237
1521
|
searchInput.addEventListener('input', renderResults)
|
|
1238
|
-
|
|
1239
|
-
|
|
1522
|
+
caseSensitiveToggle.addEventListener('click', () => {
|
|
1523
|
+
togglePressed(caseSensitiveToggle)
|
|
1524
|
+
renderResults()
|
|
1525
|
+
})
|
|
1526
|
+
regexSearchToggle.addEventListener('click', () => {
|
|
1527
|
+
togglePressed(regexSearchToggle)
|
|
1528
|
+
renderResults()
|
|
1529
|
+
})
|
|
1240
1530
|
typeMatchModeInput.addEventListener('change', renderResults)
|
|
1241
|
-
|
|
1531
|
+
schemaRowsMatchOnlyToggle.addEventListener('click', () => {
|
|
1532
|
+
togglePressed(schemaRowsMatchOnlyToggle)
|
|
1533
|
+
renderResults()
|
|
1534
|
+
})
|
|
1242
1535
|
|
|
1243
1536
|
selectAllFieldsBtn.addEventListener('click', () =>
|
|
1244
1537
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id))),
|
|
1245
1538
|
)
|
|
1246
1539
|
clearAllFieldsBtn.addEventListener('click', () => setFieldSelection(new Set()))
|
|
1247
|
-
|
|
1248
|
-
|
|
1540
|
+
coreFieldsBtn.addEventListener('click', () => setFieldSelection(CORE_FIELD_IDS))
|
|
1541
|
+
schemasOnlyFieldsBtn.addEventListener('click', () => setFieldSelection(SCHEMA_SCOPE_FIELD_IDS))
|
|
1542
|
+
sourceOnlyFieldsBtn.addEventListener('click', () => setFieldSelection(SOURCE_FIELD_IDS))
|
|
1249
1543
|
resetFiltersBtn.addEventListener('click', resetFiltersToDefault)
|
|
1250
1544
|
|
|
1251
|
-
|
|
1545
|
+
renderFieldChips()
|
|
1252
1546
|
hydrateFilterStateFromUrl()
|
|
1253
1547
|
initializeFromBakedPayload()
|
|
1254
1548
|
renderResults()
|