Skip to content

Commit cee3c92

Browse files
committed
List unregistered Stimulus Controllers
1 parent 3acb935 commit cee3c92

1 file changed

Lines changed: 147 additions & 128 deletions

File tree

src/browser_panel/panel/tabs/StimulusTab.svelte

Lines changed: 147 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
})
2525
let stimulusControllers = $state([])
2626
let registeredStimulusIdentifiers = $state([])
27+
let notUsedStimulusIdentifiers = $derived(registeredStimulusIdentifiers.filter((identifier) => !stimulusControllers.find((n) => n.identifier === identifier)))
2728
let uniqueIdentifiers = $derived([...new Set(stimulusControllers.map((n) => n.identifier).filter(Boolean))].sort())
2829
let counts = $derived(
2930
stimulusControllers.reduce((acc, n) => {
@@ -133,143 +134,161 @@
133134
}
134135
</script>
135136

136-
<Splitpanes horizontal={$horizontalPanes} dblClickSplitter={false}>
137-
<Pane class="stimulus-identifiers-list-pane full-pane" size={options.stimulusIdentifiersPaneDimensions?.streams || 35} minSize={20}>
138-
<div class="pane-container">
139-
<div class="pane-header flex-center">
140-
{#if stimulusControllers.length === 0}
141-
<h3 class="pane-header-title">Controllers</h3>
142-
{/if}
143-
</div>
144-
{#if stimulusControllers.length > 0}
145-
<div class="pane-scrollable-list">
146-
{#each uniqueIdentifiers as identifier, index (identifier)}
147-
<div
148-
class="entry-row p-1 cursor-pointer"
149-
animate:flip={{ delay: 0, duration: 200 }}
150-
role="button"
151-
tabindex="0"
152-
onclick={() => setSelectedIdentifier(identifier)}
153-
onkeydown={handleIdentifiersKeyboardNavigation}
154-
onmouseenter={() => addHighlightOverlay(`[data-controller~="${identifier}"]`)}
155-
onmouseleave={() => hideHighlightOverlay()}
156-
class:selected={selected.identifier === identifier}
157-
>
158-
<div class="d-flex justify-content-between align-items-center">
159-
<div id={`identifier-${index}`} class:error-text-underline={!isIdentifierRegistered(identifier)}>
160-
{identifier}
137+
{#if stimulusControllers.length === 0}
138+
<div class="no-entry-hint mt-4">
139+
<span>No Stimulus Controllers seen yet</span>
140+
<span>We'll keep looking</span>
141+
</div>
142+
{:else}
143+
<Splitpanes horizontal={$horizontalPanes} dblClickSplitter={false}>
144+
<Pane class="stimulus-identifiers-list-pane full-pane" size={options.stimulusIdentifiersPaneDimensions?.streams || 35} minSize={20}>
145+
<div class="pane-container">
146+
<div class="pane-header flex-center">
147+
{#if stimulusControllers.length === 0}
148+
<h3 class="pane-header-title">Controllers</h3>
149+
{/if}
150+
</div>
151+
{#if stimulusControllers.length > 0}
152+
<div class="pane-scrollable-list">
153+
{#each uniqueIdentifiers as identifier, index (identifier)}
154+
<div
155+
class="entry-row p-1 cursor-pointer"
156+
animate:flip={{ delay: 0, duration: 200 }}
157+
role="button"
158+
tabindex="0"
159+
onclick={() => setSelectedIdentifier(identifier)}
160+
onkeydown={handleIdentifiersKeyboardNavigation}
161+
onmouseenter={() => addHighlightOverlay(`[data-controller~="${identifier}"]`)}
162+
onmouseleave={() => hideHighlightOverlay()}
163+
class:selected={selected.identifier === identifier}
164+
>
165+
<div class="d-flex justify-content-between align-items-center">
166+
<div id={`identifier-${index}`} class:error-text-underline={!isIdentifierRegistered(identifier)}>
167+
{identifier}
168+
</div>
169+
{#if !isIdentifierRegistered(identifier)}
170+
<wa-tooltip for={`identifier-${index}`} style="--max-width: 200px;">
171+
<div>This controller does not appear to be registered in window.Stimulus.</div>
172+
</wa-tooltip>
173+
{/if}
174+
<div>{counts[identifier]}</div>
161175
</div>
162-
{#if !isIdentifierRegistered(identifier)}
163-
<wa-tooltip for={`identifier-${index}`} style="--max-width: 200px;">
164-
<div>This controller does not appear to be registered in window.Stimulus.</div>
165-
</wa-tooltip>
166-
{/if}
167-
<div>{counts[identifier]}</div>
168176
</div>
169-
</div>
170-
{/each}
171-
</div>
172-
{:else}
173-
<div class="no-entry-hint">
174-
<span>No Stimulus Controllers seen yet</span>
175-
<span>We'll keep looking</span>
176-
</div>
177-
{/if}
178-
</div>
179-
</Pane>
177+
{/each}
180178

181-
<Pane class="stimulus-controller-list-pane full-pane" size={options.stimulusControllerPaneDimensions?.details || 35} minSize={20}>
182-
<div class="pane-container">
183-
<div class="pane-header flex-center"></div>
184-
{#if selected.identifier}
185-
<div class="pane-scrollable-list">
186-
{#each getStimulusInstances(selected.identifier) as instance (instance.uuid)}
187-
<div
188-
class="entry-row entry-row--table-layout p-1 cursor-pointer"
189-
class:selected={selected.uuid === instance.uuid}
190-
animate:flip={{ delay: 0, duration: 200 }}
191-
role="button"
192-
tabindex="0"
193-
onclick={() => setSelectedController(instance)}
194-
onkeydown={handleInstancesKeyboardNavigation}
195-
onmouseenter={() => addHighlightOverlay(selectorByUUID(instance.uuid))}
196-
onmouseleave={() => hideHighlightOverlay()}
197-
>
198-
<div class="d-table-row">
199-
<div class="stimulus-instance-first-column">
200-
<StripedHtmlTag element={instance} />
179+
{#if notUsedStimulusIdentifiers.length > 0}
180+
{#each notUsedStimulusIdentifiers as identifier (identifier)}
181+
<div class="entry-row p-1" animate:flip={{ delay: 0, duration: 200 }}>
182+
<div class="d-flex justify-content-between align-items-center text-muted">
183+
{identifier}
184+
<div>0</div>
185+
</div>
201186
</div>
187+
{/each}
188+
{/if}
189+
</div>
190+
{:else}
191+
<div class="no-entry-hint">
192+
<span>No Stimulus Controllers seen yet</span>
193+
<span>We'll keep looking</span>
194+
</div>
195+
{/if}
196+
</div>
197+
</Pane>
198+
199+
<Pane class="stimulus-controller-list-pane full-pane" size={options.stimulusControllerPaneDimensions?.details || 35} minSize={20}>
200+
<div class="pane-container">
201+
<div class="pane-header flex-center"></div>
202+
{#if selected.identifier}
203+
<div class="pane-scrollable-list">
204+
{#each getStimulusInstances(selected.identifier) as instance (instance.uuid)}
205+
<div
206+
class="entry-row entry-row--table-layout p-1 cursor-pointer"
207+
class:selected={selected.uuid === instance.uuid}
208+
animate:flip={{ delay: 0, duration: 200 }}
209+
role="button"
210+
tabindex="0"
211+
onclick={() => setSelectedController(instance)}
212+
onkeydown={handleInstancesKeyboardNavigation}
213+
onmouseenter={() => addHighlightOverlay(selectorByUUID(instance.uuid))}
214+
onmouseleave={() => hideHighlightOverlay()}
215+
>
216+
<div class="d-table-row">
217+
<div class="stimulus-instance-first-column">
218+
<StripedHtmlTag element={instance} />
219+
</div>
202220

203-
<div class="stimulus-instance-second-column">
204-
<div class="me-3 overflow-x-auto scrollbar-none">
205-
<InspectButton class="btn-hoverable me-2" uuid={instance.uuid}></InspectButton>
221+
<div class="stimulus-instance-second-column">
222+
<div class="me-3 overflow-x-auto scrollbar-none">
223+
<InspectButton class="btn-hoverable me-2" uuid={instance.uuid}></InspectButton>
224+
</div>
206225
</div>
207226
</div>
208227
</div>
209-
</div>
210-
{/each}
211-
</div>
212-
{:else}
213-
<div class="no-entry-hint">
214-
<span>Nothing selected</span>
215-
<span>Select a Stimulus Controller to see its details</span>
216-
</div>
217-
{/if}
218-
</div>
219-
</Pane>
220-
221-
<Pane class="stimulus-detail-pane full-pane" size={options.stimulusDetailsPaneDimensions?.details || 30} minSize={20}>
222-
<div class="pane-container">
223-
<div class="pane-header flex-center"></div>
224-
{#if selected.controller}
225-
<div class="pane-scrollable-list">
226-
{#if selected.controller.values.length > 0}
227-
<div class="pane-section-heading">Values</div>
228-
{#each Object.entries(selected.controller.values) as [_key, valueObject] (selected.uuid + selected.identifier + valueObject.key)}
229-
{@const dataAttribute = `data-${selected.identifier}-${valueObject.key}`}
230-
<ValueTreeItem {valueObject} {selected} {dataAttribute} />
231-
{/each}
232-
{/if}
233-
{#if selected.controller.targets.length > 0}
234-
<div class="pane-section-heading">Targets</div>
235-
{#each selected.controller.targets.sort((a, b) => a.elements?.length < b.elements?.length) as target (selected.uuid + selected.identifier + target.name)}
236-
<TargetTreeItem {target} {selected} />
237-
{/each}
238-
{/if}
239-
{#if selected.controller.outlets.length > 0}
240-
<div class="pane-section-heading">Outlets</div>
241-
{#each selected.controller.outlets.sort((a, b) => a.elements?.length < b.elements?.length) as outlet (selected.uuid + selected.identifier + outlet.name)}
242-
<OutletTreeItem {outlet} {selected} />
243-
{/each}
244-
{/if}
245-
{#if selected.controller.classes.length > 0}
246-
<div class="pane-section-heading">Classes</div>
247-
{#each selected.controller.classes.sort((a, b) => a.classes?.length < b.classes?.length) as klass (selected.uuid + selected.identifier + klass.name)}
248-
<ClassTreeItem {klass} {selected} />
249228
{/each}
250-
{/if}
251-
{#if selected.controller.actions.length > 0}
252-
<div class="pane-section-heading">Actions</div>
253-
{#each selected.controller.actions as action (selected.uuid + selected.identifier + action.descriptor)}
254-
<ActionTreeItem {action} {selected} />
255-
{/each}
256-
{/if}
257-
{#if selected.controller.values.length === 0 && selected.controller.targets.length === 0 && selected.controller.outlets.length === 0 && selected.controller.classes.length === 0 && selected.controller.actions.length === 0}
258-
<div class="no-entry-hint">
259-
<span>No details available</span>
260-
<span>This controller has no values, targets, outlets, classes or actions</span>
261-
</div>
262-
{/if}
263-
</div>
264-
{:else}
265-
<div class="no-entry-hint">
266-
<span>Nothing selected</span>
267-
<span>Select a Stimulus Controller to see its details</span>
268-
</div>
269-
{/if}
270-
</div>
271-
</Pane>
272-
</Splitpanes>
229+
</div>
230+
{:else}
231+
<div class="no-entry-hint">
232+
<span>Nothing selected</span>
233+
<span>Select a Stimulus Controller to see its details</span>
234+
</div>
235+
{/if}
236+
</div>
237+
</Pane>
238+
239+
<Pane class="stimulus-detail-pane full-pane" size={options.stimulusDetailsPaneDimensions?.details || 30} minSize={20}>
240+
<div class="pane-container">
241+
<div class="pane-header flex-center"></div>
242+
{#if selected.controller}
243+
<div class="pane-scrollable-list">
244+
{#if selected.controller.values.length > 0}
245+
<div class="pane-section-heading">Values</div>
246+
{#each Object.entries(selected.controller.values) as [_key, valueObject] (selected.uuid + selected.identifier + valueObject.key)}
247+
{@const dataAttribute = `data-${selected.identifier}-${valueObject.key}`}
248+
<ValueTreeItem {valueObject} {selected} {dataAttribute} />
249+
{/each}
250+
{/if}
251+
{#if selected.controller.targets.length > 0}
252+
<div class="pane-section-heading">Targets</div>
253+
{#each selected.controller.targets.sort((a, b) => a.elements?.length < b.elements?.length) as target (selected.uuid + selected.identifier + target.name)}
254+
<TargetTreeItem {target} {selected} />
255+
{/each}
256+
{/if}
257+
{#if selected.controller.outlets.length > 0}
258+
<div class="pane-section-heading">Outlets</div>
259+
{#each selected.controller.outlets.sort((a, b) => a.elements?.length < b.elements?.length) as outlet (selected.uuid + selected.identifier + outlet.name)}
260+
<OutletTreeItem {outlet} {selected} />
261+
{/each}
262+
{/if}
263+
{#if selected.controller.classes.length > 0}
264+
<div class="pane-section-heading">Classes</div>
265+
{#each selected.controller.classes.sort((a, b) => a.classes?.length < b.classes?.length) as klass (selected.uuid + selected.identifier + klass.name)}
266+
<ClassTreeItem {klass} {selected} />
267+
{/each}
268+
{/if}
269+
{#if selected.controller.actions.length > 0}
270+
<div class="pane-section-heading">Actions</div>
271+
{#each selected.controller.actions as action (selected.uuid + selected.identifier + action.descriptor)}
272+
<ActionTreeItem {action} {selected} />
273+
{/each}
274+
{/if}
275+
{#if selected.controller.values.length === 0 && selected.controller.targets.length === 0 && selected.controller.outlets.length === 0 && selected.controller.classes.length === 0 && selected.controller.actions.length === 0}
276+
<div class="no-entry-hint">
277+
<span>No details available</span>
278+
<span>This controller has no values, targets, outlets, classes or actions</span>
279+
</div>
280+
{/if}
281+
</div>
282+
{:else}
283+
<div class="no-entry-hint">
284+
<span>Nothing selected</span>
285+
<span>Select a Stimulus Controller to see its details</span>
286+
</div>
287+
{/if}
288+
</div>
289+
</Pane>
290+
</Splitpanes>
291+
{/if}
273292

274293
<style>
275294
.stimulus-instance-first-column {

0 commit comments

Comments
 (0)