@tanstack/query-devtools 5.0.0-alpha.84 → 5.0.0-alpha.87

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.
Files changed (44) hide show
  1. package/build/Devtools/OYHFZDAP.jsx +6711 -0
  2. package/build/Devtools/QBS7PB6D.js +5885 -0
  3. package/build/Devtools/QPWQM7BG.js +6068 -0
  4. package/build/Devtools/RZF5MSB2.jsx +6637 -0
  5. package/build/chunk/DFC6JMPR.jsx +1280 -0
  6. package/build/chunk/LOJK4LQB.jsx +1280 -0
  7. package/{dist/esm/index-7c6d68e3.js → build/chunk/MZOCHHZD.js} +648 -416
  8. package/{dist/cjs/index-edbb2275.cjs → build/chunk/YHTPXJWR.js} +648 -446
  9. package/build/dev.cjs +8116 -0
  10. package/build/dev.js +99 -0
  11. package/build/dev.jsx +98 -0
  12. package/build/index.cjs +7940 -0
  13. package/build/index.d.cts +55 -0
  14. package/build/index.d.ts +55 -0
  15. package/build/index.js +99 -0
  16. package/build/index.jsx +98 -0
  17. package/package.json +24 -18
  18. package/src/Devtools.tsx +1 -3
  19. package/dist/cjs/Devtools-0f2840bd.cjs +0 -6766
  20. package/dist/cjs/Devtools-0f2840bd.cjs.map +0 -1
  21. package/dist/cjs/index-edbb2275.cjs.map +0 -1
  22. package/dist/cjs/index.cjs +0 -8
  23. package/dist/cjs/index.cjs.map +0 -1
  24. package/dist/esm/Devtools-26de9f2c.js +0 -6758
  25. package/dist/esm/Devtools-26de9f2c.js.map +0 -1
  26. package/dist/esm/index-7c6d68e3.js.map +0 -1
  27. package/dist/esm/index.js +0 -2
  28. package/dist/esm/index.js.map +0 -1
  29. package/dist/source/Context.js +0 -10
  30. package/dist/source/Devtools.jsx +0 -1512
  31. package/dist/source/Explorer.jsx +0 -264
  32. package/dist/source/fonts.js +0 -7
  33. package/dist/source/icons/index.jsx +0 -344
  34. package/dist/source/index.jsx +0 -88
  35. package/dist/source/theme.js +0 -304
  36. package/dist/source/utils.jsx +0 -77
  37. package/dist/types/Context.d.ts +0 -28
  38. package/dist/types/Devtools.d.ts +0 -22
  39. package/dist/types/Explorer.d.ts +0 -21
  40. package/dist/types/fonts.d.ts +0 -1
  41. package/dist/types/icons/index.d.ts +0 -11
  42. package/dist/types/index.d.ts +0 -29
  43. package/dist/types/theme.d.ts +0 -296
  44. package/dist/types/utils.d.ts +0 -23
@@ -1,1512 +0,0 @@
1
- import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount, } from 'solid-js';
2
- import { rankItem } from '@tanstack/match-sorter-utils';
3
- import { css, cx } from '@emotion/css';
4
- import { TransitionGroup } from 'solid-transition-group';
5
- import { Key } from '@solid-primitives/keyed';
6
- import { createLocalStorage } from '@solid-primitives/storage';
7
- import { createResizeObserver } from '@solid-primitives/resize-observer';
8
- import { tokens } from './theme';
9
- import { convertRemToPixels, displayValue, getQueryStatusColor, getQueryStatusColorByLabel, getQueryStatusLabel, getSidedProp, sortFns, } from './utils';
10
- import { ArrowDown, ArrowUp, ChevronDown, Offline, Search, Settings, TanstackLogo, Wifi, } from './icons';
11
- import Explorer from './Explorer';
12
- import { QueryDevtoolsContext, useQueryDevtoolsContext } from './Context';
13
- import { loadFonts } from './fonts';
14
- const firstBreakpoint = 1024;
15
- const secondBreakpoint = 796;
16
- const thirdBreakpoint = 700;
17
- const BUTTON_POSITION = 'bottom-right';
18
- const POSITION = 'bottom';
19
- const INITIAL_IS_OPEN = false;
20
- const DEFAULT_HEIGHT = 500;
21
- const DEFAULT_WIDTH = 500;
22
- const DEFAULT_SORT_FN_NAME = Object.keys(sortFns)[0];
23
- const DEFAULT_SORT_ORDER = 1;
24
- const [selectedQueryHash, setSelectedQueryHash] = createSignal(null);
25
- const [panelWidth, setPanelWidth] = createSignal(0);
26
- export const DevtoolsComponent = (props) => {
27
- return (<QueryDevtoolsContext.Provider value={props}>
28
- <Devtools />
29
- </QueryDevtoolsContext.Provider>);
30
- };
31
- export default DevtoolsComponent;
32
- export const Devtools = () => {
33
- loadFonts();
34
- const styles = getStyles();
35
- const [localStore, setLocalStore] = createLocalStorage({
36
- prefix: 'TanstackQueryDevtools',
37
- });
38
- const buttonPosition = createMemo(() => {
39
- return useQueryDevtoolsContext().buttonPosition || BUTTON_POSITION;
40
- });
41
- const isOpen = createMemo(() => {
42
- return localStore.open === 'true'
43
- ? true
44
- : localStore.open === 'false'
45
- ? false
46
- : useQueryDevtoolsContext().initialIsOpen || INITIAL_IS_OPEN;
47
- });
48
- const position = createMemo(() => {
49
- return localStore.position || useQueryDevtoolsContext().position || POSITION;
50
- });
51
- return (<div
52
- // styles for animating the panel in and out
53
- class={css `
54
- & .TSQD-panel-exit-active,
55
- & .TSQD-panel-enter-active {
56
- transition: opacity 0.3s, transform 0.3s;
57
- }
58
-
59
- & .TSQD-panel-exit-to,
60
- & .TSQD-panel-enter {
61
- ${position() === 'top'
62
- ? `transform: translateY(-${Number(localStore.height || DEFAULT_HEIGHT)}px);`
63
- : position() === 'left'
64
- ? `transform: translateX(-${Number(localStore.width || DEFAULT_WIDTH)}px);`
65
- : position() === 'right'
66
- ? `transform: translateX(${Number(localStore.width || DEFAULT_WIDTH)}px);`
67
- : `transform: translateY(${Number(localStore.height || DEFAULT_HEIGHT)}px);`}
68
- }
69
-
70
- & .TSQD-button-exit-active,
71
- & .TSQD-button-enter-active {
72
- transition: opacity 0.3s, transform 0.3s;
73
- }
74
-
75
- & .TSQD-button-exit-to,
76
- & .TSQD-button-enter {
77
- transform: ${buttonPosition() === 'top-left'
78
- ? `translateX(-72px);`
79
- : buttonPosition() === 'top-right'
80
- ? `translateX(72px);`
81
- : `translateY(72px);`};
82
- }
83
- `}>
84
- <TransitionGroup name="TSQD-panel">
85
- <Show when={isOpen()}>
86
- <DevtoolsPanel localStore={localStore} setLocalStore={setLocalStore}/>
87
- </Show>
88
- </TransitionGroup>
89
- <TransitionGroup name="TSQD-button">
90
- <Show when={!isOpen()}>
91
- <div class={cx(styles.devtoolsBtn, styles[`devtoolsBtn-position-${buttonPosition()}`])}>
92
- <div aria-hidden="true">
93
- <TanstackLogo />
94
- </div>
95
- <button aria-label="Open Tanstack query devtools" onClick={() => setLocalStore('open', 'true')}>
96
- <TanstackLogo />
97
- </button>
98
- </div>
99
- </Show>
100
- </TransitionGroup>
101
- </div>);
102
- };
103
- export const DevtoolsPanel = (props) => {
104
- const styles = getStyles();
105
- const [isResizing, setIsResizing] = createSignal(false);
106
- const sort = createMemo(() => props.localStore.sort || DEFAULT_SORT_FN_NAME);
107
- const sortOrder = createMemo(() => Number(props.localStore.sortOrder) || DEFAULT_SORT_ORDER);
108
- const [offline, setOffline] = createSignal(false);
109
- const [settingsOpen, setSettingsOpen] = createSignal(false);
110
- const position = createMemo(() => (props.localStore.position ||
111
- useQueryDevtoolsContext().position ||
112
- POSITION));
113
- const sortFn = createMemo(() => sortFns[sort()]);
114
- const onlineManager = createMemo(() => useQueryDevtoolsContext().onlineManager);
115
- const cache = createMemo(() => {
116
- return useQueryDevtoolsContext().client.getQueryCache();
117
- });
118
- const queryCount = createSubscribeToQueryCacheBatcher((queryCache) => {
119
- return queryCache().getAll().length;
120
- }, false);
121
- const queries = createMemo(on(() => [queryCount(), props.localStore.filter, sort(), sortOrder()], () => {
122
- const curr = cache().getAll();
123
- const filtered = props.localStore.filter
124
- ? curr.filter((item) => rankItem(item.queryHash, props.localStore.filter || '').passed)
125
- : [...curr];
126
- const sorted = sortFn()
127
- ? filtered.sort((a, b) => sortFn()(a, b) * sortOrder())
128
- : filtered;
129
- return sorted;
130
- }));
131
- const handleDragStart = (event) => {
132
- const panelElement = event.currentTarget.parentElement;
133
- if (!panelElement)
134
- return;
135
- setIsResizing(true);
136
- const { height, width } = panelElement.getBoundingClientRect();
137
- const startX = event.clientX;
138
- const startY = event.clientY;
139
- let newSize = 0;
140
- const minHeight = convertRemToPixels(3.5);
141
- const minWidth = convertRemToPixels(12);
142
- const runDrag = (moveEvent) => {
143
- moveEvent.preventDefault();
144
- if (position() === 'left' || position() === 'right') {
145
- const valToAdd = position() === 'right'
146
- ? startX - moveEvent.clientX
147
- : moveEvent.clientX - startX;
148
- newSize = Math.round(width + valToAdd);
149
- if (newSize < minWidth) {
150
- newSize = minWidth;
151
- }
152
- props.setLocalStore('width', String(Math.round(newSize)));
153
- const newWidth = panelElement.getBoundingClientRect().width;
154
- // If the panel size didn't decrease, this means we have reached the minimum width
155
- // of the panel so we restore the original width in local storage
156
- // Restoring the width helps in smooth open/close transitions
157
- if (Number(props.localStore.width) < newWidth) {
158
- props.setLocalStore('width', String(newWidth));
159
- }
160
- }
161
- else {
162
- const valToAdd = position() === 'bottom'
163
- ? startY - moveEvent.clientY
164
- : moveEvent.clientY - startY;
165
- newSize = Math.round(height + valToAdd);
166
- // If the panel size is less than the minimum height,
167
- // we set the size to the minimum height
168
- if (newSize < minHeight) {
169
- newSize = minHeight;
170
- setSelectedQueryHash(null);
171
- }
172
- props.setLocalStore('height', String(Math.round(newSize)));
173
- }
174
- };
175
- const unsub = () => {
176
- if (isResizing()) {
177
- setIsResizing(false);
178
- }
179
- document.removeEventListener('mousemove', runDrag, false);
180
- document.removeEventListener('mouseUp', unsub, false);
181
- };
182
- document.addEventListener('mousemove', runDrag, false);
183
- document.addEventListener('mouseup', unsub, false);
184
- };
185
- setupQueryCacheSubscription();
186
- let queriesContainerRef;
187
- let panelRef;
188
- onMount(() => {
189
- createResizeObserver(panelRef, ({ width }, el) => {
190
- if (el === panelRef) {
191
- setPanelWidth(width);
192
- }
193
- });
194
- });
195
- const setDevtoolsPosition = (pos) => {
196
- props.setLocalStore('position', pos);
197
- setSettingsOpen(false);
198
- };
199
- createEffect(() => {
200
- const rootContainer = panelRef.parentElement?.parentElement?.parentElement;
201
- if (!rootContainer)
202
- return;
203
- const currentPosition = (props.localStore.position ||
204
- POSITION);
205
- const styleProp = getSidedProp('padding', currentPosition);
206
- const isVertical = props.localStore.position === 'left' ||
207
- props.localStore.position === 'right';
208
- const previousPaddings = (({ padding, paddingTop, paddingBottom, paddingLeft, paddingRight, }) => ({
209
- padding,
210
- paddingTop,
211
- paddingBottom,
212
- paddingLeft,
213
- paddingRight,
214
- }))(rootContainer.style);
215
- rootContainer.style[styleProp] = `${isVertical ? props.localStore.width : props.localStore.height}px`;
216
- onCleanup(() => {
217
- Object.entries(previousPaddings).forEach(([property, previousValue]) => {
218
- rootContainer.style[property] =
219
- previousValue;
220
- });
221
- });
222
- });
223
- return (<aside
224
- // Some context for styles here
225
- // background-color - Changes to a lighter color create a harder contrast
226
- // between the queries and query detail panel
227
- // -
228
- // min-width - When the panel is in the left or right position, the panel
229
- // width is set to min-content to allow the panel to shrink to the lowest possible width
230
- class={`${styles.panel} ${styles[`panel-position-${position()}`]} ${css `
231
- flex-direction: ${panelWidth() < secondBreakpoint ? 'column' : 'row'};
232
- background-color: ${panelWidth() < secondBreakpoint
233
- ? tokens.colors.gray[600]
234
- : tokens.colors.darkGray[900]};
235
- ${panelWidth() < thirdBreakpoint &&
236
- (position() === 'right' || position() === 'left')
237
- ? `
238
- min-width: min-content;
239
- `
240
- : ''}
241
- `}`} style={{
242
- height: position() === 'bottom' || position() === 'top'
243
- ? `${props.localStore.height || DEFAULT_HEIGHT}px`
244
- : 'auto',
245
- width: position() === 'right' || position() === 'left'
246
- ? `${props.localStore.width || DEFAULT_WIDTH}px`
247
- : 'auto',
248
- }} ref={panelRef} aria-label="Tanstack query devtools">
249
- <div class={cx(styles.dragHandle, styles[`dragHandle-position-${position()}`])} onMouseDown={handleDragStart}></div>
250
- <button aria-label="Close tanstack query devtools" class={cx(styles.closeBtn, styles[`closeBtn-position-${position()}`])} onClick={() => props.setLocalStore('open', 'false')}>
251
- <ChevronDown />
252
- </button>
253
- <div ref={queriesContainerRef}
254
- // When the panels are stacked we use the height style
255
- // to divide the panels into two equal parts
256
- class={`${styles.queriesContainer} ${css `
257
- ${panelWidth() < secondBreakpoint && selectedQueryHash()
258
- ? `
259
- height: 50%;
260
- max-height: 50%;
261
- `
262
- : ''}
263
- `}`}>
264
- <div class={cx(styles.row)}>
265
- <button class={styles.logo} onClick={() => props.setLocalStore('open', 'false')} aria-label="Close Tanstack query devtools">
266
- <span class={styles.tanstackLogo}>TANSTACK</span>
267
- <span class={styles.queryFlavorLogo}>
268
- {useQueryDevtoolsContext().queryFlavor} v
269
- {useQueryDevtoolsContext().version}
270
- </span>
271
- </button>
272
- <QueryStatusCount />
273
- </div>
274
- <div class={cx(styles.row, css `
275
- gap: ${tokens.size[2.5]};
276
- `)}>
277
- <div class={styles.filtersContainer}>
278
- <div class={styles.filterInput}>
279
- <Search />
280
- <input aria-label="Filter queries by query key" type="text" placeholder="Filter" onInput={(e) => props.setLocalStore('filter', e.currentTarget.value)} value={props.localStore.filter || ''}/>
281
- </div>
282
- <div class={styles.filterSelect}>
283
- <select value={sort()} onChange={(e) => props.setLocalStore('sort', e.currentTarget.value)}>
284
- {Object.keys(sortFns).map((key) => (<option value={key}>Sort by {key}</option>))}
285
- </select>
286
- <ChevronDown />
287
- </div>
288
- <button onClick={() => {
289
- props.setLocalStore('sortOrder', String(sortOrder() * -1));
290
- }} aria-label={`Sort order ${sortOrder() === -1 ? 'descending' : 'ascending'}`} aria-pressed={sortOrder() === -1}>
291
- <Show when={sortOrder() === 1}>
292
- <span>Asc</span>
293
- <ArrowUp />
294
- </Show>
295
- <Show when={sortOrder() === -1}>
296
- <span>Desc</span>
297
- <ArrowDown />
298
- </Show>
299
- </button>
300
- </div>
301
-
302
- <div class={styles.actionsContainer}>
303
- <button onClick={() => {
304
- if (offline()) {
305
- onlineManager().setOnline(undefined);
306
- setOffline(false);
307
- window.dispatchEvent(new Event('online'));
308
- }
309
- else {
310
- onlineManager().setOnline(false);
311
- setOffline(true);
312
- window.dispatchEvent(new Event('offline'));
313
- }
314
- }} class={styles.actionsBtn} aria-label={`${offline()
315
- ? 'Unset offline mocking behavior'
316
- : 'Mock offline behavior'}`} aria-pressed={offline()}>
317
- {offline() ? <Offline /> : <Wifi />}
318
- </button>
319
- <div style={{ position: 'relative' }}>
320
- <button onClick={() => setSettingsOpen((prev) => !prev)} class={styles.actionsBtn} id="TSQD-settings-menu-btn" aria-label={`${settingsOpen() ? 'Close' : 'Open'} settings menu`} aria-haspopup="true" aria-controls="TSQD-settings-menu">
321
- <Settings />
322
- </button>
323
- <Show when={settingsOpen()}>
324
- <div role="menu" tabindex="-1" aria-labelledby="TSQD-settings-menu-btn" id="TSQD-settings-menu" class={styles.settingsMenu}>
325
- <div class={styles.settingsMenuHeader}>Position</div>
326
- <div class={styles.settingsMenuSection}>
327
- <button onClick={() => {
328
- setDevtoolsPosition('top');
329
- }} aria-label="Position top">
330
- <ArrowUp />
331
- <span>Top</span>
332
- </button>
333
- <button onClick={() => {
334
- setDevtoolsPosition('bottom');
335
- }} aria-label="Position bottom">
336
- <ArrowDown />
337
- <span>Bottom</span>
338
- </button>
339
- <button onClick={() => {
340
- setDevtoolsPosition('left');
341
- }} aria-label="Position left">
342
- <ArrowDown />
343
- <span>Left</span>
344
- </button>
345
- <button onClick={() => {
346
- setDevtoolsPosition('right');
347
- }} aria-label="Position right">
348
- <ArrowDown />
349
- <span>Right</span>
350
- </button>
351
- </div>
352
- </div>
353
- </Show>
354
- </div>
355
- </div>
356
- </div>
357
- <div class={styles.overflowQueryContainer}>
358
- <div>
359
- <Key by={(q) => q.queryHash} each={queries()}>
360
- {(query) => <QueryRow query={query()}/>}
361
- </Key>
362
- </div>
363
- </div>
364
- </div>
365
- <Show when={selectedQueryHash()}>
366
- <QueryDetails />
367
- </Show>
368
- </aside>);
369
- };
370
- export const QueryRow = (props) => {
371
- const styles = getStyles();
372
- const queryState = createSubscribeToQueryCacheBatcher((queryCache) => queryCache().find({
373
- queryKey: props.query.queryKey,
374
- })?.state);
375
- const isDisabled = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
376
- .find({
377
- queryKey: props.query.queryKey,
378
- })
379
- ?.isDisabled() ?? false);
380
- const isStale = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
381
- .find({
382
- queryKey: props.query.queryKey,
383
- })
384
- ?.isStale() ?? false);
385
- const observers = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
386
- .find({
387
- queryKey: props.query.queryKey,
388
- })
389
- ?.getObserversCount() ?? 0);
390
- const color = createMemo(() => getQueryStatusColor({
391
- queryState: queryState(),
392
- observerCount: observers(),
393
- isStale: isStale(),
394
- }));
395
- return (<Show when={queryState()}>
396
- <button onClick={() => setSelectedQueryHash(props.query.queryHash === selectedQueryHash()
397
- ? null
398
- : props.query.queryHash)} class={cx(styles.queryRow, selectedQueryHash() === props.query.queryHash &&
399
- styles.selectedQueryRow)} aria-label={`Query key ${props.query.queryHash}`}>
400
- <div class={cx('TSQDObserverCount', color() === 'gray'
401
- ? css `
402
- background-color: ${tokens.colors[color()][700]};
403
- color: ${tokens.colors[color()][300]};
404
- `
405
- : css `
406
- background-color: ${tokens.colors[color()][900]};
407
- color: ${tokens.colors[color()][300]} !important;
408
- `)}>
409
- {observers()}
410
- </div>
411
- <code class="TSQDQueryHash">{props.query.queryHash}</code>
412
- <Show when={isDisabled()}>
413
- <div class="TSQDQueryDisabled">disabled</div>
414
- </Show>
415
- </button>
416
- </Show>);
417
- };
418
- export const QueryStatusCount = () => {
419
- const stale = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
420
- .getAll()
421
- .filter((q) => getQueryStatusLabel(q) === 'stale').length);
422
- const fresh = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
423
- .getAll()
424
- .filter((q) => getQueryStatusLabel(q) === 'fresh').length);
425
- const fetching = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
426
- .getAll()
427
- .filter((q) => getQueryStatusLabel(q) === 'fetching').length);
428
- const paused = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
429
- .getAll()
430
- .filter((q) => getQueryStatusLabel(q) === 'paused').length);
431
- const inactive = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
432
- .getAll()
433
- .filter((q) => getQueryStatusLabel(q) === 'inactive').length);
434
- const styles = getStyles();
435
- return (<div class={styles.queryStatusContainer}>
436
- <QueryStatus label="Fresh" color="green" count={fresh()}/>
437
- <QueryStatus label="Fetching" color="blue" count={fetching()}/>
438
- <QueryStatus label="Paused" color="purple" count={paused()}/>
439
- <QueryStatus label="Stale" color="yellow" count={stale()}/>
440
- <QueryStatus label="Inactive" color="gray" count={inactive()}/>
441
- </div>);
442
- };
443
- export const QueryStatus = (props) => {
444
- const styles = getStyles();
445
- let tagRef;
446
- const [mouseOver, setMouseOver] = createSignal(false);
447
- const [focused, setFocused] = createSignal(false);
448
- const showLabel = createMemo(() => {
449
- if (selectedQueryHash()) {
450
- if (panelWidth() < firstBreakpoint && panelWidth() > secondBreakpoint) {
451
- return false;
452
- }
453
- }
454
- if (panelWidth() < thirdBreakpoint) {
455
- return false;
456
- }
457
- return true;
458
- });
459
- return (<button onFocus={() => setFocused(true)} onBlur={() => setFocused(false)} onMouseEnter={() => setMouseOver(true)} onMouseLeave={() => {
460
- setMouseOver(false);
461
- setFocused(false);
462
- }} disabled={showLabel()} ref={tagRef} class={cx(styles.queryStatusTag, !showLabel()
463
- ? css `
464
- cursor: pointer;
465
- &:hover {
466
- background: ${tokens.colors.darkGray[400]}${tokens.alpha[80]};
467
- }
468
- `
469
- : null)} {...(mouseOver() || focused()
470
- ? {
471
- 'aria-describedby': 'TSQD-status-tooltip',
472
- }
473
- : {})}>
474
- <Show when={!showLabel() && (mouseOver() || focused())}>
475
- <div role="tooltip" id="TSQD-status-tooltip" class={cx(styles.statusTooltip)}>
476
- {props.label}
477
- </div>
478
- </Show>
479
- <span class={css `
480
- width: ${tokens.size[2]};
481
- height: ${tokens.size[2]};
482
- border-radius: ${tokens.border.radius.full};
483
- background-color: ${tokens.colors[props.color][500]};
484
- `}/>
485
- <Show when={showLabel()}>
486
- <span>{props.label}</span>
487
- </Show>
488
- <span class={cx(styles.queryStatusCount, props.count > 0 && props.color !== 'gray'
489
- ? css `
490
- background-color: ${tokens.colors[props.color][900]};
491
- color: ${tokens.colors[props.color][300]} !important;
492
- `
493
- : css `
494
- color: ${tokens.colors['gray'][400]} !important;
495
- `)}>
496
- {props.count}
497
- </span>
498
- </button>);
499
- };
500
- const QueryDetails = () => {
501
- const styles = getStyles();
502
- const queryClient = useQueryDevtoolsContext().client;
503
- const [restoringLoading, setRestoringLoading] = createSignal(false);
504
- const errorTypes = createMemo(() => {
505
- return useQueryDevtoolsContext().errorTypes || [];
506
- });
507
- const activeQuery = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
508
- .getAll()
509
- .find((query) => query.queryHash === selectedQueryHash()), false);
510
- const activeQueryFresh = createSubscribeToQueryCacheBatcher((queryCache) => {
511
- return queryCache()
512
- .getAll()
513
- .find((query) => query.queryHash === selectedQueryHash());
514
- }, false);
515
- const activeQueryState = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
516
- .getAll()
517
- .find((query) => query.queryHash === selectedQueryHash())?.state, false);
518
- const activeQueryStateData = createSubscribeToQueryCacheBatcher((queryCache) => {
519
- return queryCache()
520
- .getAll()
521
- .find((query) => query.queryHash === selectedQueryHash())?.state.data;
522
- }, false);
523
- const statusLabel = createSubscribeToQueryCacheBatcher((queryCache) => {
524
- const query = queryCache()
525
- .getAll()
526
- .find((q) => q.queryHash === selectedQueryHash());
527
- if (!query)
528
- return 'inactive';
529
- return getQueryStatusLabel(query);
530
- });
531
- const queryStatus = createSubscribeToQueryCacheBatcher((queryCache) => {
532
- const query = queryCache()
533
- .getAll()
534
- .find((q) => q.queryHash === selectedQueryHash());
535
- if (!query)
536
- return 'pending';
537
- return query.state.status;
538
- });
539
- const observerCount = createSubscribeToQueryCacheBatcher((queryCache) => queryCache()
540
- .getAll()
541
- .find((query) => query.queryHash === selectedQueryHash())
542
- ?.getObserversCount() ?? 0);
543
- const color = createMemo(() => getQueryStatusColorByLabel(statusLabel()));
544
- const handleRefetch = () => {
545
- const promise = activeQuery()?.fetch();
546
- // eslint-disable-next-line @typescript-eslint/no-empty-function
547
- promise?.catch(() => { });
548
- };
549
- const triggerError = (errorType) => {
550
- const error = errorType?.initializer(activeQuery()) ??
551
- new Error('Unknown error from devtools');
552
- const __previousQueryOptions = activeQuery().options;
553
- activeQuery().setState({
554
- status: 'error',
555
- error,
556
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
557
- fetchMeta: {
558
- ...activeQuery().state.fetchMeta,
559
- __previousQueryOptions,
560
- },
561
- });
562
- };
563
- const restoreQueryAfterLoadingOrError = () => {
564
- activeQuery()?.fetch((activeQuery()?.state.fetchMeta).__previousQueryOptions, {
565
- // Make sure this fetch will cancel the previous one
566
- cancelRefetch: true,
567
- });
568
- };
569
- createEffect(() => {
570
- if (statusLabel() !== 'fetching') {
571
- setRestoringLoading(false);
572
- }
573
- });
574
- return (<Show when={activeQuery() && activeQueryState()}>
575
- <div class={styles.detailsContainer}>
576
- <div class={styles.detailsHeader}>Query Details</div>
577
- <div class={styles.detailsBody}>
578
- <div>
579
- <pre>
580
- <code>{displayValue(activeQuery().queryKey, true)}</code>
581
- </pre>
582
- <span class={cx(styles.queryDetailsStatus, color() === 'gray'
583
- ? css `
584
- background-color: ${tokens.colors[color()][700]};
585
- color: ${tokens.colors[color()][300]};
586
- border-color: ${tokens.colors[color()][600]};
587
- `
588
- : css `
589
- background-color: ${tokens.colors[color()][900]};
590
- color: ${tokens.colors[color()][300]};
591
- border-color: ${tokens.colors[color()][600]};
592
- `)}>
593
- {statusLabel()}
594
- </span>
595
- </div>
596
- <div>
597
- <span>Observers:</span>
598
- <span>{observerCount()}</span>
599
- </div>
600
- <div>
601
- <span>Last Updated:</span>
602
- <span>
603
- {new Date(activeQueryState().dataUpdatedAt).toLocaleTimeString()}
604
- </span>
605
- </div>
606
- </div>
607
- <div class={styles.detailsHeader}>Actions</div>
608
- <div class={styles.actionsBody}>
609
- <button class={css `
610
- color: ${tokens.colors.blue[400]};
611
- `} onClick={handleRefetch} disabled={statusLabel() === 'fetching'}>
612
- <span class={css `
613
- background-color: ${tokens.colors.blue[400]};
614
- `}></span>
615
- Refetch
616
- </button>
617
- <button class={css `
618
- color: ${tokens.colors.yellow[400]};
619
- `} onClick={() => queryClient.invalidateQueries(activeQuery())}>
620
- <span class={css `
621
- background-color: ${tokens.colors.yellow[400]};
622
- `}></span>
623
- Invalidate
624
- </button>
625
- <button class={css `
626
- color: ${tokens.colors.gray[300]};
627
- `} onClick={() => queryClient.resetQueries(activeQuery())}>
628
- <span class={css `
629
- background-color: ${tokens.colors.gray[400]};
630
- `}></span>
631
- Reset
632
- </button>
633
- <button class={css `
634
- color: ${tokens.colors.cyan[400]};
635
- `} disabled={restoringLoading()} onClick={() => {
636
- if (activeQuery()?.state.data === undefined) {
637
- setRestoringLoading(true);
638
- restoreQueryAfterLoadingOrError();
639
- }
640
- else {
641
- const activeQueryVal = activeQuery();
642
- if (!activeQueryVal)
643
- return;
644
- const __previousQueryOptions = activeQueryVal.options;
645
- // Trigger a fetch in order to trigger suspense as well.
646
- activeQueryVal.fetch({
647
- ...__previousQueryOptions,
648
- queryFn: () => {
649
- return new Promise(() => {
650
- // Never resolve
651
- });
652
- },
653
- gcTime: -1,
654
- });
655
- activeQueryVal.setState({
656
- data: undefined,
657
- status: 'pending',
658
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
659
- fetchMeta: {
660
- ...activeQueryVal.state.fetchMeta,
661
- __previousQueryOptions,
662
- },
663
- });
664
- }
665
- }}>
666
- <span class={css `
667
- background-color: ${tokens.colors.cyan[400]};
668
- `}></span>
669
- {statusLabel() === 'fetching' ? 'Restore' : 'Trigger'} Loading
670
- </button>
671
- <Show when={errorTypes().length === 0 || queryStatus() === 'error'}>
672
- <button class={css `
673
- color: ${tokens.colors.red[400]};
674
- `} onClick={() => {
675
- if (!activeQuery().state.error) {
676
- triggerError();
677
- }
678
- else {
679
- queryClient.resetQueries(activeQuery());
680
- }
681
- }}>
682
- <span class={css `
683
- background-color: ${tokens.colors.red[400]};
684
- `}></span>
685
- {queryStatus() === 'error' ? 'Restore' : 'Trigger'} Error
686
- </button>
687
- </Show>
688
- <Show when={!(errorTypes().length === 0 || queryStatus() === 'error')}>
689
- <div class={styles.actionsSelect}>
690
- <span class={css `
691
- background-color: ${tokens.colors.red[400]};
692
- `}></span>
693
- Trigger Error
694
- <select disabled={queryStatus() === 'pending'} onChange={(e) => {
695
- const errorType = errorTypes().find((t) => t.name === e.currentTarget.value);
696
- triggerError(errorType);
697
- }}>
698
- <option value="" disabled selected></option>
699
- <For each={errorTypes()}>
700
- {(errorType) => (<option value={errorType.name}>{errorType.name}</option>)}
701
- </For>
702
- </select>
703
- <ChevronDown />
704
- </div>
705
- </Show>
706
- </div>
707
- <div class={styles.detailsHeader}>Data Explorer</div>
708
- <div style={{
709
- padding: '0.5rem',
710
- }}>
711
- <Explorer label="Data" defaultExpanded={['Data']} value={activeQueryStateData()} copyable={true}/>
712
- </div>
713
- <div class={styles.detailsHeader}>Query Explorer</div>
714
- <div style={{
715
- padding: '0.5rem',
716
- }}>
717
- <Explorer label="Query" defaultExpanded={['Query', 'queryKey']} value={activeQueryFresh()}/>
718
- </div>
719
- </div>
720
- </Show>);
721
- };
722
- const signalsMap = new Map();
723
- const setupQueryCacheSubscription = () => {
724
- const queryCache = createMemo(() => {
725
- const client = useQueryDevtoolsContext().client;
726
- return client.getQueryCache();
727
- });
728
- const unsub = queryCache().subscribe(() => {
729
- for (const [callback, setter] of signalsMap.entries()) {
730
- queueMicrotask(() => {
731
- setter(callback(queryCache));
732
- });
733
- }
734
- });
735
- onCleanup(() => {
736
- signalsMap.clear();
737
- unsub();
738
- });
739
- return unsub;
740
- };
741
- const createSubscribeToQueryCacheBatcher = (callback, equalityCheck = true) => {
742
- const queryCache = createMemo(() => {
743
- const client = useQueryDevtoolsContext().client;
744
- return client.getQueryCache();
745
- });
746
- const [value, setValue] = createSignal(callback(queryCache), !equalityCheck ? { equals: false } : undefined);
747
- createEffect(() => {
748
- setValue(callback(queryCache));
749
- });
750
- // @ts-ignore
751
- signalsMap.set(callback, setValue);
752
- onCleanup(() => {
753
- // @ts-ignore
754
- signalsMap.delete(callback);
755
- });
756
- return value;
757
- };
758
- const getStyles = () => {
759
- const { colors, font, size, alpha, shadow, border } = tokens;
760
- return {
761
- devtoolsBtn: css `
762
- z-index: 100000;
763
- position: fixed;
764
- padding: 4px;
765
-
766
- display: flex;
767
- align-items: center;
768
- justify-content: center;
769
- border-radius: 9999px;
770
- box-shadow: ${shadow.md()};
771
- overflow: hidden;
772
-
773
- & div {
774
- position: absolute;
775
- top: -8px;
776
- left: -8px;
777
- right: -8px;
778
- bottom: -8px;
779
- border-radius: 9999px;
780
-
781
- & svg {
782
- position: absolute;
783
- width: 100%;
784
- height: 100%;
785
- }
786
- filter: blur(6px) saturate(1.2) contrast(1.1);
787
- }
788
-
789
- &:focus-within {
790
- outline-offset: 2px;
791
- outline: 3px solid ${colors.green[600]};
792
- }
793
-
794
- & button {
795
- position: relative;
796
- z-index: 1;
797
- padding: 0;
798
- border-radius: 9999px;
799
- background-color: transparent;
800
- border: none;
801
- height: 40px;
802
- display: flex;
803
- width: 40px;
804
- overflow: hidden;
805
- cursor: pointer;
806
- outline: none;
807
- & svg {
808
- position: absolute;
809
- width: 100%;
810
- height: 100%;
811
- }
812
- }
813
- `,
814
- panel: css `
815
- position: fixed;
816
- z-index: 9999;
817
- display: flex;
818
- gap: ${tokens.size[0.5]};
819
- & * {
820
- font-family: 'Inter', sans-serif;
821
- color: ${colors.gray[300]};
822
- box-sizing: border-box;
823
- text-transform: none;
824
- }
825
- `,
826
- 'devtoolsBtn-position-bottom-right': css `
827
- bottom: 12px;
828
- right: 12px;
829
- `,
830
- 'devtoolsBtn-position-bottom-left': css `
831
- bottom: 12px;
832
- left: 12px;
833
- `,
834
- 'devtoolsBtn-position-top-left': css `
835
- top: 12px;
836
- left: 12px;
837
- `,
838
- 'devtoolsBtn-position-top-right': css `
839
- top: 12px;
840
- right: 12px;
841
- `,
842
- 'panel-position-top': css `
843
- top: 0;
844
- right: 0;
845
- left: 0;
846
- max-height: 90%;
847
- min-height: 3.5rem;
848
- border-bottom: ${colors.darkGray[300]} 1px solid;
849
- `,
850
- 'panel-position-bottom': css `
851
- bottom: 0;
852
- right: 0;
853
- left: 0;
854
- max-height: 90%;
855
- min-height: 3.5rem;
856
- border-top: ${colors.darkGray[300]} 1px solid;
857
- `,
858
- 'panel-position-right': css `
859
- bottom: 0;
860
- right: 0;
861
- top: 0;
862
- border-left: ${colors.darkGray[300]} 1px solid;
863
- max-width: 90%;
864
- `,
865
- 'panel-position-left': css `
866
- bottom: 0;
867
- left: 0;
868
- top: 0;
869
- border-right: ${colors.darkGray[300]} 1px solid;
870
- max-width: 90%;
871
- `,
872
- closeBtn: css `
873
- position: absolute;
874
- cursor: pointer;
875
- z-index: 5;
876
- display: flex;
877
- align-items: center;
878
- justify-content: center;
879
- outline: none;
880
- &:hover {
881
- background-color: ${colors.darkGray[500]};
882
- }
883
- &:focus-visible {
884
- outline: 2px solid ${colors.blue[600]};
885
- }
886
- `,
887
- 'closeBtn-position-top': css `
888
- bottom: 0;
889
- right: ${size[3]};
890
- transform: translate(0, 100%);
891
- background-color: ${colors.darkGray[700]};
892
- border-right: ${colors.darkGray[300]} 1px solid;
893
- border-left: ${colors.darkGray[300]} 1px solid;
894
- border-top: none;
895
- border-bottom: ${colors.darkGray[300]} 1px solid;
896
- border-radius: 0px 0px ${border.radius.sm} ${border.radius.sm};
897
- padding: ${size[1.5]} ${size[2.5]} ${size[2]} ${size[2.5]};
898
-
899
- &::after {
900
- content: ' ';
901
- position: absolute;
902
- bottom: 100%;
903
- left: -${size[2.5]};
904
- height: ${size[1.5]};
905
- width: calc(100% + ${size[5]});
906
- }
907
-
908
- & svg {
909
- transform: rotate(180deg);
910
- }
911
- `,
912
- 'closeBtn-position-bottom': css `
913
- top: 0;
914
- right: ${size[3]};
915
- transform: translate(0, -100%);
916
- background-color: ${colors.darkGray[700]};
917
- border-right: ${colors.darkGray[300]} 1px solid;
918
- border-left: ${colors.darkGray[300]} 1px solid;
919
- border-top: ${colors.darkGray[300]} 1px solid;
920
- border-bottom: none;
921
- border-radius: ${border.radius.sm} ${border.radius.sm} 0px 0px;
922
- padding: ${size[2]} ${size[2.5]} ${size[1.5]} ${size[2.5]};
923
-
924
- &::after {
925
- content: ' ';
926
- position: absolute;
927
- top: 100%;
928
- left: -${size[2.5]};
929
- height: ${size[1.5]};
930
- width: calc(100% + ${size[5]});
931
- }
932
- `,
933
- 'closeBtn-position-right': css `
934
- bottom: ${size[3]};
935
- left: 0;
936
- transform: translate(-100%, 0);
937
- background-color: ${colors.darkGray[700]};
938
- border-right: none;
939
- border-left: ${colors.darkGray[300]} 1px solid;
940
- border-top: ${colors.darkGray[300]} 1px solid;
941
- border-bottom: ${colors.darkGray[300]} 1px solid;
942
- border-radius: ${border.radius.sm} 0px 0px ${border.radius.sm};
943
- padding: ${size[2.5]} ${size[1]} ${size[2.5]} ${size[1.5]};
944
-
945
- &::after {
946
- content: ' ';
947
- position: absolute;
948
- left: 100%;
949
- height: calc(100% + ${size[5]});
950
- width: ${size[1.5]};
951
- }
952
-
953
- & svg {
954
- transform: rotate(-90deg);
955
- }
956
- `,
957
- 'closeBtn-position-left': css `
958
- bottom: ${size[3]};
959
- right: 0;
960
- transform: translate(100%, 0);
961
- background-color: ${colors.darkGray[700]};
962
- border-left: none;
963
- border-right: ${colors.darkGray[300]} 1px solid;
964
- border-top: ${colors.darkGray[300]} 1px solid;
965
- border-bottom: ${colors.darkGray[300]} 1px solid;
966
- border-radius: 0px ${border.radius.sm} ${border.radius.sm} 0px;
967
- padding: ${size[2.5]} ${size[1.5]} ${size[2.5]} ${size[1]};
968
-
969
- &::after {
970
- content: ' ';
971
- position: absolute;
972
- right: 100%;
973
- height: calc(100% + ${size[5]});
974
- width: ${size[1.5]};
975
- }
976
-
977
- & svg {
978
- transform: rotate(90deg);
979
- }
980
- `,
981
- queriesContainer: css `
982
- flex: 1 1 700px;
983
- background-color: ${colors.darkGray[700]};
984
- display: flex;
985
- flex-direction: column;
986
- `,
987
- dragHandle: css `
988
- position: absolute;
989
- transition: background-color 0.125s ease;
990
- &:hover {
991
- background-color: ${colors.gray[400]}${alpha[90]};
992
- }
993
- z-index: 4;
994
- `,
995
- 'dragHandle-position-top': css `
996
- bottom: 0;
997
- width: 100%;
998
- height: ${tokens.size[1]};
999
- cursor: ns-resize;
1000
- `,
1001
- 'dragHandle-position-bottom': css `
1002
- top: 0;
1003
- width: 100%;
1004
- height: ${tokens.size[1]};
1005
- cursor: ns-resize;
1006
- `,
1007
- 'dragHandle-position-right': css `
1008
- left: 0;
1009
- width: ${tokens.size[1]};
1010
- height: 100%;
1011
- cursor: ew-resize;
1012
- `,
1013
- 'dragHandle-position-left': css `
1014
- right: 0;
1015
- width: ${tokens.size[1]};
1016
- height: 100%;
1017
- cursor: ew-resize;
1018
- `,
1019
- row: css `
1020
- display: flex;
1021
- justify-content: space-between;
1022
- padding: ${tokens.size[2.5]} ${tokens.size[3]};
1023
- gap: ${tokens.size[4]};
1024
- border-bottom: ${colors.darkGray[500]} 1px solid;
1025
- align-items: center;
1026
- & > button {
1027
- padding: 0;
1028
- background: transparent;
1029
- border: none;
1030
- display: flex;
1031
- flex-direction: column;
1032
- }
1033
- `,
1034
- logo: css `
1035
- cursor: pointer;
1036
- &:hover {
1037
- opacity: 0.7;
1038
- }
1039
- &:focus-visible {
1040
- outline-offset: 4px;
1041
- border-radius: ${border.radius.xs};
1042
- outline: 2px solid ${colors.blue[800]};
1043
- }
1044
- `,
1045
- tanstackLogo: css `
1046
- font-size: ${font.size.lg};
1047
- font-weight: ${font.weight.extrabold};
1048
- line-height: ${font.lineHeight.sm};
1049
- white-space: nowrap;
1050
- `,
1051
- queryFlavorLogo: css `
1052
- font-weight: ${font.weight.semibold};
1053
- font-size: ${font.size.sm};
1054
- background: linear-gradient(to right, #dd524b, #e9a03b);
1055
- background-clip: text;
1056
- line-height: ${font.lineHeight.xs};
1057
- -webkit-text-fill-color: transparent;
1058
- white-space: nowrap;
1059
- `,
1060
- queryStatusContainer: css `
1061
- display: flex;
1062
- gap: ${tokens.size[2]};
1063
- height: min-content;
1064
- `,
1065
- queryStatusTag: css `
1066
- display: flex;
1067
- gap: ${tokens.size[1.5]};
1068
- background: ${colors.darkGray[500]};
1069
- border-radius: ${tokens.border.radius.md};
1070
- font-size: ${font.size.sm};
1071
- padding: ${tokens.size[1]};
1072
- padding-left: ${tokens.size[2.5]};
1073
- align-items: center;
1074
- line-height: ${font.lineHeight.md};
1075
- font-weight: ${font.weight.medium};
1076
- border: none;
1077
- user-select: none;
1078
- position: relative;
1079
- &:focus-visible {
1080
- outline-offset: 2px;
1081
- outline: 2px solid ${colors.blue[800]};
1082
- }
1083
- & span:nth-child(2) {
1084
- color: ${colors.gray[300]}${alpha[80]};
1085
- }
1086
- `,
1087
- statusTooltip: css `
1088
- position: absolute;
1089
- z-index: 1;
1090
- background-color: ${colors.darkGray[500]};
1091
- top: 100%;
1092
- left: 50%;
1093
- transform: translate(-50%, calc(${tokens.size[2]}));
1094
- padding: ${tokens.size[0.5]} ${tokens.size[3]};
1095
- border-radius: ${tokens.border.radius.md};
1096
- font-size: ${font.size.sm};
1097
- border: 2px solid ${colors.gray[600]};
1098
- color: ${tokens.colors['gray'][300]};
1099
-
1100
- &::before {
1101
- top: 0px;
1102
- content: ' ';
1103
- display: block;
1104
- left: 50%;
1105
- transform: translate(-50%, -100%);
1106
- position: absolute;
1107
- border-color: transparent transparent ${colors.gray[600]} transparent;
1108
- border-style: solid;
1109
- border-width: 7px;
1110
- /* transform: rotate(180deg); */
1111
- }
1112
-
1113
- &::after {
1114
- top: 0px;
1115
- content: ' ';
1116
- display: block;
1117
- left: 50%;
1118
- transform: translate(-50%, calc(-100% + 2.5px));
1119
- position: absolute;
1120
- border-color: transparent transparent ${colors.darkGray[500]}
1121
- transparent;
1122
- border-style: solid;
1123
- border-width: 7px;
1124
- }
1125
- `,
1126
- selectedQueryRow: css `
1127
- background-color: ${colors.darkGray[500]};
1128
- `,
1129
- queryStatusCount: css `
1130
- padding: 0 8px;
1131
- display: flex;
1132
- align-items: center;
1133
- justify-content: center;
1134
- color: ${colors.gray[400]};
1135
- background-color: ${colors.darkGray[300]};
1136
- border-radius: 3px;
1137
- font-variant-numeric: tabular-nums;
1138
- `,
1139
- filtersContainer: css `
1140
- display: flex;
1141
- gap: ${tokens.size[2.5]};
1142
- & > button {
1143
- cursor: pointer;
1144
- padding: ${tokens.size[1.5]} ${tokens.size[2.5]};
1145
- padding-right: ${tokens.size[1.5]};
1146
- border-radius: ${tokens.border.radius.md};
1147
- background-color: ${colors.darkGray[400]};
1148
- font-size: ${font.size.sm};
1149
- display: flex;
1150
- align-items: center;
1151
- line-height: ${font.lineHeight.sm};
1152
- gap: ${tokens.size[1.5]};
1153
- max-width: 160px;
1154
- border: 1px solid ${colors.darkGray[200]};
1155
- &:focus-visible {
1156
- outline-offset: 2px;
1157
- border-radius: ${border.radius.xs};
1158
- outline: 2px solid ${colors.blue[800]};
1159
- }
1160
- }
1161
- `,
1162
- filterInput: css `
1163
- padding: ${tokens.size[1.5]} ${tokens.size[2.5]};
1164
- border-radius: ${tokens.border.radius.md};
1165
- background-color: ${colors.darkGray[400]};
1166
- display: flex;
1167
- box-sizing: content-box;
1168
- align-items: center;
1169
- gap: ${tokens.size[1.5]};
1170
- max-width: 160px;
1171
- min-width: 100px;
1172
- border: 1px solid ${colors.darkGray[200]};
1173
- height: min-content;
1174
- & > svg {
1175
- width: ${tokens.size[3.5]};
1176
- height: ${tokens.size[3.5]};
1177
- }
1178
- & input {
1179
- font-size: ${font.size.sm};
1180
- width: 100%;
1181
- background-color: ${colors.darkGray[400]};
1182
- border: none;
1183
- padding: 0;
1184
- line-height: ${font.lineHeight.sm};
1185
- color: ${colors.gray[300]};
1186
- &::placeholder {
1187
- color: ${colors.gray[300]};
1188
- }
1189
- &:focus {
1190
- outline: none;
1191
- }
1192
- }
1193
-
1194
- &:focus-within {
1195
- outline-offset: 2px;
1196
- border-radius: ${border.radius.xs};
1197
- outline: 2px solid ${colors.blue[800]};
1198
- }
1199
- `,
1200
- filterSelect: css `
1201
- padding: ${tokens.size[1.5]} ${tokens.size[2.5]};
1202
- border-radius: ${tokens.border.radius.md};
1203
- background-color: ${colors.darkGray[400]};
1204
- display: flex;
1205
- align-items: center;
1206
- gap: ${tokens.size[1.5]};
1207
- box-sizing: content-box;
1208
- max-width: 160px;
1209
- border: 1px solid ${colors.darkGray[200]};
1210
- height: min-content;
1211
- & > svg {
1212
- width: ${tokens.size[3]};
1213
- height: ${tokens.size[3]};
1214
- }
1215
- & > select {
1216
- appearance: none;
1217
- min-width: 100px;
1218
- line-height: ${font.lineHeight.sm};
1219
- font-size: ${font.size.sm};
1220
- background-color: ${colors.darkGray[400]};
1221
- border: none;
1222
- &:focus {
1223
- outline: none;
1224
- }
1225
- }
1226
- &:focus-within {
1227
- outline-offset: 2px;
1228
- border-radius: ${border.radius.xs};
1229
- outline: 2px solid ${colors.blue[800]};
1230
- }
1231
- `,
1232
- actionsContainer: css `
1233
- display: flex;
1234
- gap: ${tokens.size[2.5]};
1235
- `,
1236
- actionsBtn: css `
1237
- border-radius: ${tokens.border.radius.md};
1238
- background-color: ${colors.darkGray[400]};
1239
- width: 2.125rem; // 34px
1240
- height: 2.125rem; // 34px
1241
- justify-content: center;
1242
- display: flex;
1243
- align-items: center;
1244
- gap: ${tokens.size[1.5]};
1245
- max-width: 160px;
1246
- border: 1px solid ${colors.darkGray[200]};
1247
- cursor: pointer;
1248
- padding: 0;
1249
- &:hover {
1250
- background-color: ${colors.darkGray[500]};
1251
- }
1252
- & svg {
1253
- width: ${tokens.size[4]};
1254
- height: ${tokens.size[4]};
1255
- }
1256
- &:focus-visible {
1257
- outline-offset: 2px;
1258
- border-radius: ${border.radius.xs};
1259
- outline: 2px solid ${colors.blue[800]};
1260
- }
1261
- `,
1262
- overflowQueryContainer: css `
1263
- flex: 1;
1264
- overflow-y: auto;
1265
- & > div {
1266
- display: flex;
1267
- flex-direction: column;
1268
- }
1269
- `,
1270
- queryRow: css `
1271
- display: flex;
1272
- align-items: center;
1273
- padding: 0;
1274
- background-color: inherit;
1275
- border: none;
1276
- cursor: pointer;
1277
- &:focus-visible {
1278
- outline-offset: -2px;
1279
- border-radius: ${border.radius.xs};
1280
- outline: 2px solid ${colors.blue[800]};
1281
- }
1282
- &:hover .TSQDQueryHash {
1283
- background-color: ${colors.darkGray[600]};
1284
- }
1285
-
1286
- & .TSQDObserverCount {
1287
- padding: 0 ${tokens.size[1]};
1288
- user-select: none;
1289
- min-width: ${tokens.size[8]};
1290
- align-self: stretch !important;
1291
- display: flex;
1292
- align-items: center;
1293
- justify-content: center;
1294
- font-size: ${font.size.sm};
1295
- font-weight: ${font.weight.medium};
1296
- border-bottom: 1px solid ${colors.darkGray[700]};
1297
- }
1298
- & .TSQDQueryHash {
1299
- user-select: text;
1300
- font-size: ${font.size.sm};
1301
- display: flex;
1302
- align-items: center;
1303
- min-height: ${tokens.size[8]};
1304
- flex: 1;
1305
- padding: ${tokens.size[1]} ${tokens.size[2]};
1306
- font-family: 'Menlo', 'Fira Code', monospace !important;
1307
- border-bottom: 1px solid ${colors.darkGray[400]};
1308
- text-align: left;
1309
- text-overflow: clip;
1310
- word-break: break-word;
1311
- }
1312
-
1313
- & .TSQDQueryDisabled {
1314
- align-self: stretch;
1315
- align-self: stretch !important;
1316
- display: flex;
1317
- align-items: center;
1318
- padding: 0 ${tokens.size[3]};
1319
- color: ${colors.gray[300]};
1320
- background-color: ${colors.darkGray[600]};
1321
- border-bottom: 1px solid ${colors.darkGray[400]};
1322
- font-size: ${font.size.sm};
1323
- }
1324
- `,
1325
- detailsContainer: css `
1326
- flex: 1 1 700px;
1327
- background-color: ${colors.darkGray[700]};
1328
- display: flex;
1329
- flex-direction: column;
1330
- overflow-y: auto;
1331
- display: flex;
1332
- `,
1333
- detailsHeader: css `
1334
- position: sticky;
1335
- top: 0;
1336
- z-index: 2;
1337
- background-color: ${colors.darkGray[600]};
1338
- padding: ${tokens.size[2]} ${tokens.size[2]};
1339
- font-weight: ${font.weight.medium};
1340
- font-size: ${font.size.sm};
1341
- `,
1342
- detailsBody: css `
1343
- margin: ${tokens.size[2]} 0px ${tokens.size[3]} 0px;
1344
- & > div {
1345
- display: flex;
1346
- align-items: stretch;
1347
- padding: 0 ${tokens.size[2]};
1348
- line-height: ${font.lineHeight.sm};
1349
- justify-content: space-between;
1350
- & > span {
1351
- font-size: ${font.size.sm};
1352
- }
1353
- & > span:nth-child(2) {
1354
- font-variant-numeric: tabular-nums;
1355
- }
1356
- }
1357
-
1358
- & > div:first-child {
1359
- margin-bottom: ${tokens.size[2]};
1360
- }
1361
-
1362
- & code {
1363
- font-family: 'Menlo', 'Fira Code', monospace !important;
1364
- margin: 0;
1365
- font-size: ${font.size.sm};
1366
- line-height: ${font.lineHeight.sm};
1367
- }
1368
- `,
1369
- queryDetailsStatus: css `
1370
- border: 1px solid ${colors.darkGray[200]};
1371
- border-radius: ${tokens.border.radius.md};
1372
- font-weight: ${font.weight.medium};
1373
- padding: ${tokens.size[1]} ${tokens.size[2.5]};
1374
- `,
1375
- actionsBody: css `
1376
- flex-wrap: wrap;
1377
- margin: ${tokens.size[3]} 0px ${tokens.size[3]} 0px;
1378
- display: flex;
1379
- gap: ${tokens.size[2]};
1380
- padding: 0px ${tokens.size[2]};
1381
- & > button {
1382
- font-size: ${font.size.sm};
1383
- padding: ${tokens.size[2]} ${tokens.size[2]};
1384
- display: flex;
1385
- border-radius: ${tokens.border.radius.md};
1386
- border: 1px solid ${colors.darkGray[400]};
1387
- background-color: ${colors.darkGray[600]};
1388
- align-items: center;
1389
- gap: ${tokens.size[2]};
1390
- font-weight: ${font.weight.medium};
1391
- line-height: ${font.lineHeight.sm};
1392
- cursor: pointer;
1393
- &:focus-visible {
1394
- outline-offset: 2px;
1395
- border-radius: ${border.radius.xs};
1396
- outline: 2px solid ${colors.blue[800]};
1397
- }
1398
- &:hover {
1399
- background-color: ${colors.darkGray[500]};
1400
- }
1401
-
1402
- &:disabled {
1403
- opacity: 0.6;
1404
- cursor: not-allowed;
1405
- }
1406
-
1407
- & > span {
1408
- width: ${size[2]};
1409
- height: ${size[2]};
1410
- border-radius: ${tokens.border.radius.full};
1411
- }
1412
- }
1413
- `,
1414
- actionsSelect: css `
1415
- font-size: ${font.size.sm};
1416
- padding: ${tokens.size[2]} ${tokens.size[2]};
1417
- display: flex;
1418
- border-radius: ${tokens.border.radius.md};
1419
- overflow: hidden;
1420
- border: 1px solid ${colors.darkGray[400]};
1421
- background-color: ${colors.darkGray[600]};
1422
- align-items: center;
1423
- gap: ${tokens.size[2]};
1424
- font-weight: ${font.weight.medium};
1425
- line-height: ${font.lineHeight.sm};
1426
- color: ${tokens.colors.red[400]};
1427
- cursor: pointer;
1428
- position: relative;
1429
- &:hover {
1430
- background-color: ${colors.darkGray[500]};
1431
- }
1432
- & > span {
1433
- width: ${size[2]};
1434
- height: ${size[2]};
1435
- border-radius: ${tokens.border.radius.full};
1436
- }
1437
- &:focus-within {
1438
- outline-offset: 2px;
1439
- border-radius: ${border.radius.xs};
1440
- outline: 2px solid ${colors.blue[800]};
1441
- }
1442
- & select {
1443
- position: absolute;
1444
- top: 0;
1445
- left: 0;
1446
- width: 100%;
1447
- height: 100%;
1448
- appearance: none;
1449
- background-color: transparent;
1450
- border: none;
1451
- color: transparent;
1452
- outline: none;
1453
- }
1454
-
1455
- & svg path {
1456
- stroke: ${tokens.colors.red[400]} !important;
1457
- }
1458
- `,
1459
- settingsMenu: css `
1460
- position: absolute;
1461
- top: calc(100% + ${tokens.size[2]});
1462
- border-radius: ${tokens.border.radius.lg};
1463
- border: 1px solid ${colors.gray[600]};
1464
- right: 0;
1465
- min-width: ${tokens.size[44]};
1466
- background-color: ${colors.darkGray[400]};
1467
- font-size: ${font.size.sm};
1468
- color: ${colors.gray[500]};
1469
- z-index: 7;
1470
- `,
1471
- settingsMenuHeader: css `
1472
- padding: ${tokens.size[1.5]} ${tokens.size[2.5]};
1473
- color: ${colors.gray[300]};
1474
- font-weight: ${font.weight.medium};
1475
- `,
1476
- settingsMenuSection: css `
1477
- border-top: 1px solid ${colors.gray[600]};
1478
- display: flex;
1479
- flex-direction: column;
1480
- padding: ${tokens.size[1]} ${tokens.size[1]};
1481
-
1482
- & > button {
1483
- cursor: pointer;
1484
- background-color: transparent;
1485
- border: none;
1486
- padding: ${tokens.size[2]} ${tokens.size[1.5]};
1487
- font-size: ${font.size.sm};
1488
- display: flex;
1489
- align-items: center;
1490
- justify-content: flex-start;
1491
- gap: ${tokens.size[2]};
1492
- border-radius: ${tokens.border.radius.md};
1493
- &:hover {
1494
- background-color: ${colors.darkGray[500]};
1495
- }
1496
-
1497
- &:focus-visible {
1498
- outline-offset: 2px;
1499
- outline: 2px solid ${colors.blue[800]};
1500
- }
1501
- }
1502
-
1503
- & button:nth-child(4) svg {
1504
- transform: rotate(-90deg);
1505
- }
1506
-
1507
- & button:nth-child(3) svg {
1508
- transform: rotate(90deg);
1509
- }
1510
- `,
1511
- };
1512
- };