@ethlete/query-devtools 1.0.0-next.14 → 1.0.0-next.16

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.
@@ -1,13 +1,184 @@
1
+ import { HttpHeaders, HttpErrorResponse } from '@angular/common/http';
2
+ import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
1
3
  import * as i0 from '@angular/core';
2
- import { signal, inject, ElementRef, ViewEncapsulation, Component, input, output, computed, viewChild, effect, numberAttribute, linkedSignal, InjectionToken, untracked, NgZone, DestroyRef, booleanAttribute } from '@angular/core';
3
- import { queryDevtoolsAbout, hasQueryDevtoolsOverridesAtPath, detectPaginationShape, isDateShapedLeaf, generateQueryDevtoolsStringPreset, generateQueryDevtoolsNumberPreset, collectLeafPaths, armAllQueryDevtoolsMocks, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsFaults, queryDevtoolsResponseHistory, queryDevtoolsMocks, queryDevtoolsAuthSessions, queryDevtoolsArmedMocks, clearQueryDevtoolsAuthSessions, queryDevtoolsApiEnvs, queryDevtoolsApiEnvValues, setQueryDevtoolsApiEnv, queryDevtoolsSettings, queryDevtoolsAllowsLocalAuthSessions, setQueryDevtoolsOverridesScope, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFaultsScope, setQueryDevtoolsSettings, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, queryDevtoolsApiEnvIsProduction, queryDevtoolsAuthSessionsFor, queryDevtoolsAuthAccountsFor, queryDevtoolsAuthOtherScopeCount, queryDevtoolsAuthActive, queryDevtoolsAuthTabLocal, switchQueryDevtoolsAuthSession, renameQueryDevtoolsAuthSession, forgetQueryDevtoolsAuthSession, forgetQueryDevtoolsAuthSessionsFor, logoutQueryDevtoolsAuthSession, setQueryDevtoolsAuthTabLocal, loginQueryDevtoolsAuthAccount, setQueryDevtoolsAuthCredentials, clearQueryDevtoolsAuthCredentials, removeQueryDevtoolsAuthAccount, queryDevtoolsAuthFieldsFor, addQueryDevtoolsAuthAccount, setQueryDevtoolsTokenTtl, queryDevtoolsTokenTtls, clearQueryDevtoolsTokenTtl, serializeQueryDevtoolsOverrideTransfer, parseQueryDevtoolsOverrideTransfer, armQueryDevtoolsOverrideTransfer, countUnresolvedQueryDevtoolsOverrides, createQueryDevtoolsOverrides, applyQueryDevtoolsOverrides, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, measureQueryDevtoolsPayload, seedQueryDevtoolsSchemaBody, loadQueryDevtoolsSchema, queryDevtoolsMockId, saveQueryDevtoolsMock, armQueryDevtoolsMock, deleteQueryDevtoolsMock, collectQueryDevtoolsSchemaComponents, seedQueryDevtoolsSchemaRoute, QUERY_DEVTOOLS_FAULT_STATUSES, setQueryDevtoolsFault, clearQueryDevtoolsTombstones, readQueryDevtoolsStore, createQueryKeyLockManager, queryDevtoolsEntries, isQueryDevtoolsRepositoryLive, queryDevtoolsFaults, EMPTY_QUERY_DEVTOOLS_FAULT, isQueryDevtoolsFaultArmed, queryDevtoolsFaultsRestored, queryDevtoolsArmedMocksRestored, restoredQueryDevtoolsOverrides, queryDevtoolsRestoredOverridesScope, clearRestoredQueryDevtoolsOverrides, setQueryDevtoolsUiMounted, clearQueryDevtoolsStore, writeQueryDevtoolsStore, registerEthleteVersion, queryDevtoolsOverridePersistence, setQueryDevtoolsOverridePersistence, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsMockStore, createQueryErrorResponse, applyQueryDevtoolsTokenTtl, canOverrideQueryDevtoolsTokenTtl, resolveQueryHeaders, sumQueryDevtoolsStats } from '@ethlete/query';
4
+ import { input, ViewEncapsulation, Component, InjectionToken, inject, signal, output, computed, Directive, ElementRef, viewChild, effect, numberAttribute, linkedSignal, untracked, NgZone, DestroyRef, Injector, booleanAttribute, viewChildren, afterNextRender } from '@angular/core';
4
5
  import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
6
+ import { injectStyleManager, injectSemanticColorTheme, ProvideColorDirective, clamp, injectRenderer, injectFileDownload, injectViewportSize, injectIsDocumentVisible, injectBreakpointObserver, signalElementDimensions, randomId, reserveOverlayViewportSpace, createObjectUrlHandle, DragHandleDirective, ResizeHandlesComponent } from '@ethlete/core';
7
+ import { setQueryDevtoolsTokenTtl, clearQueryDevtoolsTokenTtl, createQueryKeyLockManager, QueryFeatureType, setQueryDevtoolsUiMounted, createQueryErrorResponse, resolveQueryHeaders } from '@ethlete/query';
8
+ import { hasQueryDevtoolsOverridesAtPath, detectPaginationShape, isDateShapedLeaf, generateQueryDevtoolsStringPreset, generateQueryDevtoolsNumberPreset, collectLeafPaths, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, queryDevtoolsApiEnvIsProduction, queryDevtoolsSettings, queryDevtoolsAuthSessionsFor, queryDevtoolsAuthAccountsFor, queryDevtoolsAuthOtherScopeCount, queryDevtoolsAuthActive, queryDevtoolsAuthTabLocal, switchQueryDevtoolsAuthSession, renameQueryDevtoolsAuthSession, forgetQueryDevtoolsAuthSession, forgetQueryDevtoolsAuthSessionsFor, logoutQueryDevtoolsAuthSession, setQueryDevtoolsAuthTabLocal, loginQueryDevtoolsAuthAccount, setQueryDevtoolsAuthCredentials, clearQueryDevtoolsAuthCredentials, removeQueryDevtoolsAuthAccount, queryDevtoolsAuthFieldsFor, addQueryDevtoolsAuthAccount, setQueryDevtoolsSettings, clearQueryDevtoolsAuthSessions, queryDevtoolsTokenTtls, serializeQueryDevtoolsOverrideTransfer, parseQueryDevtoolsOverrideTransfer, armQueryDevtoolsOverrideTransfer, countUnresolvedQueryDevtoolsOverrides, queryDevtoolsAbout, createQueryDevtoolsOverrides, applyQueryDevtoolsOverrides, armAllQueryDevtoolsMocks, clearQueryDevtoolsArmedMocks, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, queryDevtoolsMocks, measureQueryDevtoolsPayload, queryDevtoolsArmedMocks, seedQueryDevtoolsSchemaBody, loadQueryDevtoolsSchema, queryDevtoolsMockId, saveQueryDevtoolsMock, armQueryDevtoolsMock, deleteQueryDevtoolsMock, collectQueryDevtoolsSchemaComponents, seedQueryDevtoolsSchemaRoute, clearQueryDevtoolsFaults, queryDevtoolsResponseHistory, queryDevtoolsAuthSessions, queryDevtoolsApiEnvs, queryDevtoolsApiEnvValues, setQueryDevtoolsApiEnv, queryDevtoolsAllowsLocalAuthSessions, setQueryDevtoolsOverridesScope, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFaultsScope, QUERY_DEVTOOLS_FAULT_STATUSES, setQueryDevtoolsFault, isQueryDevtoolsEnabled, clearQueryDevtoolsTombstones, readQueryDevtoolsStore, queryDevtoolsEntries, isQueryDevtoolsRepositoryLive, queryDevtoolsFaults, EMPTY_QUERY_DEVTOOLS_FAULT, isQueryDevtoolsFaultArmed, queryDevtoolsFaultsRestored, queryDevtoolsArmedMocksRestored, restoredQueryDevtoolsOverrides, queryDevtoolsRestoredOverridesScope, clearRestoredQueryDevtoolsOverrides, clearQueryDevtoolsStore, writeQueryDevtoolsStore, registerEthleteVersion, queryDevtoolsOverridePersistence, setQueryDevtoolsOverridePersistence, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsMockStore, applyQueryDevtoolsTokenTtl, canOverrideQueryDevtoolsTokenTtl, sumQueryDevtoolsStats } from '@ethlete/query/devtools-contract';
5
9
  import { Subject, switchMap, timer, tap, EMPTY, interval, scan, animationFrames, NEVER, takeUntil, finalize as finalize$1, startWith, merge, map, fromEvent, filter, take } from 'rxjs';
6
- import { injectStyleManager, injectErrorTheme, ProvideColorDirective, clamp, injectRenderer, injectFileDownload, injectViewportSize, injectIsDocumentVisible, injectBreakpointObserver, signalElementDimensions, randomId, reserveOverlayViewportSpace, createObjectUrlHandle, DragHandleDirective, ResizeHandlesComponent } from '@ethlete/core';
7
10
  import { MenuDirective, MenuTriggerDirective, MenuSurfaceDirective, MenuComponent, MenuItemComponent, MenuSearchDirective, MenuSeparatorComponent, MenuItemShortcutComponent, SelectComponent, SelectSearchDirective, COMPONENTS_VERSION, MenuCheckboxItemComponent, MenuRadioGroupComponent, MenuRadioItemComponent } from '@ethlete/components';
8
- import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
9
- import { HttpHeaders, HttpErrorResponse } from '@angular/common/http';
10
- import { QUERY_DEVTOOLS_VIEW_STATE_KEY, queryDevtoolsShortcutLabel, isQueryDevtoolsShortcut, QueryDevtoolsToggleComponent } from '@ethlete/query-devtools/toggle';
11
+ import { ɵQUERY_DEVTOOLS_VIEW_STATE_KEY as _QUERY_DEVTOOLS_VIEW_STATE_KEY, QueryDevtoolsToggleComponent, queryDevtoolsShortcutLabel, isQueryDevtoolsShortcut } from '@ethlete/query-devtools/toggle';
12
+
13
+ /** Duck-typed rather than `instanceof HttpHeaders`, so a second copy of `@angular/common/http` still reads. */
14
+ const isHeadersValue = (value) => !!value &&
15
+ typeof value === 'object' &&
16
+ 'keys' in value &&
17
+ typeof value.keys === 'function' &&
18
+ 'getAll' in value &&
19
+ typeof value.getAll === 'function' &&
20
+ 'lazyInit' in value;
21
+ const HEADERS_KEY = 'headers';
22
+ /**
23
+ * How to render `value` if it is one of the built-ins the explorer knows, or `null` for anything it
24
+ * should keep treating as a plain object or array. `key` is the name the value sits under; a
25
+ * `headers` function is called so the row shows the headers it hands the request.
26
+ */
27
+ const exoticOf = (value, key) => {
28
+ if (typeof value === 'function') {
29
+ const provided = key === HEADERS_KEY && value.length === 0 ? providedHeaders(value) : null;
30
+ if (provided)
31
+ return { typeName: 'HttpHeaders', entries: headerEntries(provided) };
32
+ // `String(fn)` would dump the whole source of the function into the row.
33
+ return { typeName: 'fn', display: value.name || 'anonymous' };
34
+ }
35
+ if (!value || typeof value !== 'object')
36
+ return null;
37
+ if (value instanceof Date) {
38
+ return { typeName: 'Date', display: Number.isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString() };
39
+ }
40
+ if (typeof File !== 'undefined' && value instanceof File) {
41
+ return {
42
+ typeName: 'File',
43
+ entries: [
44
+ { k: 'name', v: value.name },
45
+ { k: 'size', v: value.size },
46
+ { k: 'type', v: value.type },
47
+ { k: 'lastModified', v: new Date(value.lastModified) },
48
+ ],
49
+ };
50
+ }
51
+ if (typeof Blob !== 'undefined' && value instanceof Blob) {
52
+ return {
53
+ typeName: 'Blob',
54
+ entries: [
55
+ { k: 'size', v: value.size },
56
+ { k: 'type', v: value.type },
57
+ ],
58
+ };
59
+ }
60
+ if (value instanceof Map) {
61
+ return { typeName: 'Map', entries: [...value].map(([k, v]) => ({ k: String(k), v })) };
62
+ }
63
+ if (value instanceof Set) {
64
+ return { typeName: 'Set', entries: [...value].map((v, i) => ({ k: String(i), v })) };
65
+ }
66
+ if (typeof FormData !== 'undefined' && value instanceof FormData) {
67
+ return { typeName: 'FormData', entries: [...value].map(([k, v]) => ({ k, v })) };
68
+ }
69
+ if (isHeadersValue(value)) {
70
+ return { typeName: 'HttpHeaders', entries: headerEntries(value) };
71
+ }
72
+ return null;
73
+ };
74
+ /**
75
+ * The headers a `headers` provider hands the request, or `null` if it hands anything else. A secure
76
+ * query resolves its access token inside such a provider and throws while no token is available yet -
77
+ * both cases keep the plain `fn` row.
78
+ */
79
+ const providedHeaders = (provider) => {
80
+ try {
81
+ const value = provider();
82
+ return isHeadersValue(value) ? value : null;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ };
88
+ /**
89
+ * The headers an `HttpHeaders` actually holds, as `name: value` pairs. A header set more than once
90
+ * joins on `, ` the way the wire format does.
91
+ */
92
+ const headerEntries = (headers) => {
93
+ try {
94
+ return headers.keys().map((name) => ({ k: name, v: headers.getAll(name)?.join(', ') ?? '' }));
95
+ }
96
+ catch {
97
+ return [];
98
+ }
99
+ };
100
+ /** Past this a description stops fitting the diff cell and the form-field row it is written for. */
101
+ const MAX_INLINE_LENGTH = 80;
102
+ /**
103
+ * A one-line description of a value {@link exoticOf} knows, for a place with no room to expand it - a
104
+ * diff cell, a form field's value column. `null` for anything the caller should render itself.
105
+ */
106
+ const inlineExoticOf = (value) => {
107
+ const exotic = exoticOf(value);
108
+ if (!exotic)
109
+ return null;
110
+ const inner = exotic.display ?? exotic.entries.map(({ k, v }) => `${k}: ${safeJson(v)}`).join(', ');
111
+ const rendered = `${exotic.typeName}(${inner})`;
112
+ return rendered.length > MAX_INLINE_LENGTH ? `${rendered.slice(0, MAX_INLINE_LENGTH)}…` : rendered;
113
+ };
114
+ const safeJson = (value) => {
115
+ try {
116
+ return JSON.stringify(value) ?? 'undefined';
117
+ }
118
+ catch {
119
+ return '[unserializable]';
120
+ }
121
+ };
122
+
123
+ /** A feature list: the feature's name, followed by the options it was configured with. */
124
+ class QueryDevtoolsFeaturesComponent {
125
+ constructor() {
126
+ this.features = input.required(/* @ts-ignore */
127
+ ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
128
+ }
129
+ featureLabel(type) {
130
+ return type
131
+ .replace(/^WITH_/, '')
132
+ .replace(/_/g, ' ')
133
+ .toLowerCase();
134
+ }
135
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsFeaturesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
136
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsFeaturesComponent, isStandalone: true, selector: "et-query-devtools-features", inputs: { features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
137
+ <ul class="et-query-devtools-features">
138
+ @for (feature of features(); track feature.type) {
139
+ <li class="et-query-devtools-feature">
140
+ <span class="et-query-devtools-chip">{{ featureLabel(feature.type) }}</span>
141
+ <!-- Always rendered: the list is one grid, so a feature without options still needs its cell
142
+ for the next row's chip to stay in the same column. -->
143
+ <span class="et-query-devtools-feature-details">
144
+ @for (detail of feature.details; track detail.label) {
145
+ <span class="et-query-devtools-feature-detail">
146
+ <span class="et-query-devtools-feature-label">{{ detail.label }}</span>
147
+ <span class="et-query-devtools-feature-value">{{ detail.value }}</span>
148
+ </span>
149
+ }
150
+ </span>
151
+ </li>
152
+ }
153
+ </ul>
154
+ `, isInline: true, styles: ["@layer components{.et-query-devtools-features{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:.4rem .8rem;margin:0 0 .8rem;padding:0;list-style:none}.et-query-devtools-meta .et-query-devtools-features{margin-block-end:0}.et-query-devtools-feature{display:contents}.et-query-devtools-feature>.et-query-devtools-chip{justify-self:start}.et-query-devtools-feature-details{display:flex;flex-wrap:wrap;gap:.3rem}.et-query-devtools-feature-detail{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent);font-size:1.1rem}.et-query-devtools-feature-label{color:var(--_et-qdt-muted)}.et-query-devtools-feature-value{color:var(--_et-qdt-fg);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
155
+ }
156
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsFeaturesComponent, decorators: [{
157
+ type: Component,
158
+ args: [{ selector: 'et-query-devtools-features', template: `
159
+ <ul class="et-query-devtools-features">
160
+ @for (feature of features(); track feature.type) {
161
+ <li class="et-query-devtools-feature">
162
+ <span class="et-query-devtools-chip">{{ featureLabel(feature.type) }}</span>
163
+ <!-- Always rendered: the list is one grid, so a feature without options still needs its cell
164
+ for the next row's chip to stay in the same column. -->
165
+ <span class="et-query-devtools-feature-details">
166
+ @for (detail of feature.details; track detail.label) {
167
+ <span class="et-query-devtools-feature-detail">
168
+ <span class="et-query-devtools-feature-label">{{ detail.label }}</span>
169
+ <span class="et-query-devtools-feature-value">{{ detail.value }}</span>
170
+ </span>
171
+ }
172
+ </span>
173
+ </li>
174
+ }
175
+ </ul>
176
+ `, encapsulation: ViewEncapsulation.None, styles: ["@layer components{.et-query-devtools-features{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:.4rem .8rem;margin:0 0 .8rem;padding:0;list-style:none}.et-query-devtools-meta .et-query-devtools-features{margin-block-end:0}.et-query-devtools-feature{display:contents}.et-query-devtools-feature>.et-query-devtools-chip{justify-self:start}.et-query-devtools-feature-details{display:flex;flex-wrap:wrap;gap:.3rem}.et-query-devtools-feature-detail{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent);font-size:1.1rem}.et-query-devtools-feature-label{color:var(--_et-qdt-muted)}.et-query-devtools-feature-value{color:var(--_et-qdt-fg);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}}\n"] }]
177
+ }], propDecorators: { features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: true }] }] } });
178
+
179
+ const QUERY_DEVTOOLS_HOST = new InjectionToken('QUERY_DEVTOOLS_HOST');
180
+ /** Injects the panel a tab or the detail drawer is rendered inside of. @see QueryDevtoolsHost */
181
+ const injectQueryDevtoolsHost = () => inject(QUERY_DEVTOOLS_HOST);
11
182
 
12
183
  /**
13
184
  * Reads the clipboard, distinguishing "this browser has no `readText`" from "the user or the permission
@@ -145,47 +316,6 @@ const createQueryDevtoolsCopiedTick = (idle) => {
145
316
  };
146
317
  };
147
318
 
148
- const groupsOf = () => {
149
- const about = queryDevtoolsAbout();
150
- const groups = [
151
- {
152
- title: 'Ethlete',
153
- rows: Object.entries(about.ethlete).map(([name, version]) => ({ label: `@ethlete/${name}`, value: version })),
154
- },
155
- { title: 'Runtime', rows: [{ label: 'Angular', value: about.angular }] },
156
- ];
157
- if (about.app) {
158
- groups.push({
159
- title: 'Application',
160
- rows: Object.entries(about.app).map(([label, value]) => ({ label, value: String(value) })),
161
- });
162
- }
163
- return groups;
164
- };
165
- /**
166
- * What is running: the loaded `@ethlete/*` versions, the Angular version and whatever the app handed to
167
- * `provideQueryDevtools({ about })`. A section rather than a tab body, so it can be shown anywhere.
168
- */
169
- class QueryDevtoolsAboutComponent {
170
- constructor() {
171
- this.hostEl = inject(ElementRef);
172
- this.groups = groupsOf();
173
- this.copied = createQueryDevtoolsCopiedTick(false);
174
- }
175
- copy() {
176
- const text = this.groups
177
- .map((group) => [group.title, ...group.rows.map((row) => ` ${row.label}: ${row.value}`)].join('\n'))
178
- .join('\n\n');
179
- writeQueryDevtoolsClipboard({ text }, this.hostEl.nativeElement.ownerDocument).then((result) => this.copied.mark(result.ok));
180
- }
181
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsAboutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
182
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsAboutComponent, isStandalone: true, selector: "et-query-devtools-about", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-about-toolbar\">\n <p class=\"et-query-devtools-hint\">\n What is running, and what a bug report should carry. Also in the <strong>\u2913 Session</strong> export and on\n <code class=\"et-query-devtools-mono\">window.ethlete</code>.\n </p>\n <button (click)=\"copy()\" class=\"et-query-devtools-btn\" type=\"button\">\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copied.value() ? 'Copied' : 'Copy' }}\n </button>\n </div>\n\n @for (group of groups; track group.title) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>{{ group.title }}</strong>\n </div>\n <dl class=\"et-query-devtools-about-list\">\n @for (row of group.rows; track row.label) {\n <div class=\"et-query-devtools-about-row\">\n <dt class=\"et-query-devtools-mono\">{{ row.label }}</dt>\n <dd class=\"et-query-devtools-mono\">{{ row.value }}</dd>\n </div>\n }\n </dl>\n </div>\n }\n</div>\n", styles: ["@layer components{.et-query-devtools-about-toolbar{align-items:flex-start}.et-query-devtools-about-list{display:flex;flex-direction:column;gap:.2rem;margin:0;padding:.6rem .8rem}.et-query-devtools-about-row{display:flex;align-items:baseline;gap:.8rem}.et-query-devtools-about-row dt{flex:0 0 auto;color:var(--_et-qdt-muted)}.et-query-devtools-about-row dd{flex:1 1 auto;margin:0;border-block-end:1px dotted color-mix(in srgb,var(--_et-qdt-interaction) 25%,transparent);text-align:end}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
183
- }
184
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsAboutComponent, decorators: [{
185
- type: Component,
186
- args: [{ selector: 'et-query-devtools-about', encapsulation: ViewEncapsulation.None, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-about-toolbar\">\n <p class=\"et-query-devtools-hint\">\n What is running, and what a bug report should carry. Also in the <strong>\u2913 Session</strong> export and on\n <code class=\"et-query-devtools-mono\">window.ethlete</code>.\n </p>\n <button (click)=\"copy()\" class=\"et-query-devtools-btn\" type=\"button\">\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copied.value() ? 'Copied' : 'Copy' }}\n </button>\n </div>\n\n @for (group of groups; track group.title) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>{{ group.title }}</strong>\n </div>\n <dl class=\"et-query-devtools-about-list\">\n @for (row of group.rows; track row.label) {\n <div class=\"et-query-devtools-about-row\">\n <dt class=\"et-query-devtools-mono\">{{ row.label }}</dt>\n <dd class=\"et-query-devtools-mono\">{{ row.value }}</dd>\n </div>\n }\n </dl>\n </div>\n }\n</div>\n", styles: ["@layer components{.et-query-devtools-about-toolbar{align-items:flex-start}.et-query-devtools-about-list{display:flex;flex-direction:column;gap:.2rem;margin:0;padding:.6rem .8rem}.et-query-devtools-about-row{display:flex;align-items:baseline;gap:.8rem}.et-query-devtools-about-row dt{flex:0 0 auto;color:var(--_et-qdt-muted)}.et-query-devtools-about-row dd{flex:1 1 auto;margin:0;border-block-end:1px dotted color-mix(in srgb,var(--_et-qdt-interaction) 25%,transparent);text-align:end}}\n"] }]
187
- }] });
188
-
189
319
  /**
190
320
  * The copy menu's caret chrome, as a styles-only component the menu mounts itself - a session that
191
321
  * never opens a value explorer does not inject it.
@@ -474,121 +604,11 @@ const diffQueryDevtoolsResponses = (before, after) => {
474
604
  return acc;
475
605
  };
476
606
 
477
- /** Duck-typed rather than `instanceof HttpHeaders`, so a second copy of `@angular/common/http` still reads. */
478
- const isHeadersValue = (value) => !!value &&
479
- typeof value === 'object' &&
480
- 'keys' in value &&
481
- typeof value.keys === 'function' &&
482
- 'getAll' in value &&
483
- typeof value.getAll === 'function' &&
484
- 'lazyInit' in value;
485
- const HEADERS_KEY = 'headers';
486
607
  /**
487
- * How to render `value` if it is one of the built-ins the explorer knows, or `null` for anything it
488
- * should keep treating as a plain object or array. `key` is the name the value sits under; a
489
- * `headers` function is called so the row shows the headers it hands the request.
490
- */
491
- const exoticOf = (value, key) => {
492
- if (typeof value === 'function') {
493
- const provided = key === HEADERS_KEY && value.length === 0 ? providedHeaders(value) : null;
494
- if (provided)
495
- return { typeName: 'HttpHeaders', entries: headerEntries(provided) };
496
- // `String(fn)` would dump the whole source of the function into the row.
497
- return { typeName: 'fn', display: value.name || 'anonymous' };
498
- }
499
- if (!value || typeof value !== 'object')
500
- return null;
501
- if (value instanceof Date) {
502
- return { typeName: 'Date', display: Number.isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString() };
503
- }
504
- if (typeof File !== 'undefined' && value instanceof File) {
505
- return {
506
- typeName: 'File',
507
- entries: [
508
- { k: 'name', v: value.name },
509
- { k: 'size', v: value.size },
510
- { k: 'type', v: value.type },
511
- { k: 'lastModified', v: new Date(value.lastModified) },
512
- ],
513
- };
514
- }
515
- if (typeof Blob !== 'undefined' && value instanceof Blob) {
516
- return {
517
- typeName: 'Blob',
518
- entries: [
519
- { k: 'size', v: value.size },
520
- { k: 'type', v: value.type },
521
- ],
522
- };
523
- }
524
- if (value instanceof Map) {
525
- return { typeName: 'Map', entries: [...value].map(([k, v]) => ({ k: String(k), v })) };
526
- }
527
- if (value instanceof Set) {
528
- return { typeName: 'Set', entries: [...value].map((v, i) => ({ k: String(i), v })) };
529
- }
530
- if (typeof FormData !== 'undefined' && value instanceof FormData) {
531
- return { typeName: 'FormData', entries: [...value].map(([k, v]) => ({ k, v })) };
532
- }
533
- if (isHeadersValue(value)) {
534
- return { typeName: 'HttpHeaders', entries: headerEntries(value) };
535
- }
536
- return null;
537
- };
538
- /**
539
- * The headers a `headers` provider hands the request, or `null` if it hands anything else. A secure
540
- * query resolves its access token inside such a provider and throws while no token is available yet -
541
- * both cases keep the plain `fn` row.
542
- */
543
- const providedHeaders = (provider) => {
544
- try {
545
- const value = provider();
546
- return isHeadersValue(value) ? value : null;
547
- }
548
- catch {
549
- return null;
550
- }
551
- };
552
- /**
553
- * The headers an `HttpHeaders` actually holds, as `name: value` pairs. A header set more than once
554
- * joins on `, ` the way the wire format does.
555
- */
556
- const headerEntries = (headers) => {
557
- try {
558
- return headers.keys().map((name) => ({ k: name, v: headers.getAll(name)?.join(', ') ?? '' }));
559
- }
560
- catch {
561
- return [];
562
- }
563
- };
564
- /** Past this a description stops fitting the diff cell and the form-field row it is written for. */
565
- const MAX_INLINE_LENGTH = 80;
566
- /**
567
- * A one-line description of a value {@link exoticOf} knows, for a place with no room to expand it - a
568
- * diff cell, a form field's value column. `null` for anything the caller should render itself.
569
- */
570
- const inlineExoticOf = (value) => {
571
- const exotic = exoticOf(value);
572
- if (!exotic)
573
- return null;
574
- const inner = exotic.display ?? exotic.entries.map(({ k, v }) => `${k}: ${safeJson(v)}`).join(', ');
575
- const rendered = `${exotic.typeName}(${inner})`;
576
- return rendered.length > MAX_INLINE_LENGTH ? `${rendered.slice(0, MAX_INLINE_LENGTH)}…` : rendered;
577
- };
578
- const safeJson = (value) => {
579
- try {
580
- return JSON.stringify(value) ?? 'undefined';
581
- }
582
- catch {
583
- return '[unserializable]';
584
- }
585
- };
586
-
587
- /**
588
- * The value explorer's tree chrome, as a styles-only component the tree mounts itself - a session that
589
- * never opens a JSON view does not inject it.
590
- *
591
- * @internal
608
+ * The value explorer's tree chrome, as a styles-only component the tree mounts itself - a session that
609
+ * never opens a JSON view does not inject it.
610
+ *
611
+ * @internal
592
612
  */
593
613
  class QueryDevtoolsJsonStylesComponent {
594
614
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsJsonStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -614,6 +634,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
614
634
  args: [{ selector: 'et-query-devtools-override-menu-styles', template: '', encapsulation: ViewEncapsulation.None, styles: ["@layer components{et-query-devtools-override-menu{display:contents}.et-query-devtools-override-menu{display:contents}.et-query-devtools-override-trigger{appearance:none;display:inline-flex;align-items:center;justify-content:center;align-self:center;flex:0 0 auto;inline-size:2.2rem;block-size:2.2rem;margin-block:-.4rem;border:none;border-radius:var(--_et-qdt-radius-sm, .3rem);background:transparent;color:var(--_et-qdt-subtle, currentColor);cursor:pointer;opacity:0;font:inherit;font-size:1.3rem;line-height:1}@media(hover:hover){.et-query-devtools-override-trigger:hover{background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-override-trigger:focus-visible,.et-query-devtools-override-trigger[data-menu-open]{opacity:1}@media(hover:hover){.et-query-devtools-json-row:hover .et-query-devtools-override-trigger{opacity:1}}@media(hover:none){.et-query-devtools-override-trigger{opacity:1}}.et-query-devtools-override-error,.et-query-devtools-override-note{margin:4px var(--et-menu-item-padding-inline, 10px) 2px;max-inline-size:240px;font-size:12px}.et-query-devtools-override-error{color:var(--_et-qdt-error, rgb(239 68 68))}.et-query-devtools-override-note{color:var(--_et-qdt-subtle, currentColor)}.et-query-devtools-override-set-menu{display:contents}}\n"] }]
615
635
  }] });
616
636
 
637
+ /**
638
+ * The error theme of the surface this element renders on. A menu's content is declared by the component that owns
639
+ * the trigger, so it must read the theme here, inside the detached menu panel, and not from that component.
640
+ *
641
+ * @internal
642
+ */
643
+ class QueryDevtoolsErrorThemeDirective {
644
+ constructor() {
645
+ this.theme = injectSemanticColorTheme('error');
646
+ }
647
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsErrorThemeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
648
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: QueryDevtoolsErrorThemeDirective, isStandalone: true, selector: "[etQueryDevtoolsErrorTheme]", exportAs: ["etQueryDevtoolsErrorTheme"], ngImport: i0 }); }
649
+ }
650
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsErrorThemeDirective, decorators: [{
651
+ type: Directive,
652
+ args: [{
653
+ selector: '[etQueryDevtoolsErrorTheme]',
654
+ exportAs: 'etQueryDevtoolsErrorTheme',
655
+ }]
656
+ }] });
657
+
617
658
  /**
618
659
  * The per-value action menu of the query devtools value explorer: arms a path-addressed
619
660
  * {@link OverrideOp} on the query's response so it replays on every future fetch, instead of the
@@ -623,7 +664,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
623
664
  */
624
665
  class QueryDevtoolsOverrideMenuComponent {
625
666
  constructor() {
626
- this.errorColorTheme = injectErrorTheme();
627
667
  this.hostEl = inject(ElementRef);
628
668
  this.value = input(/* @ts-ignore */
629
669
  ...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
@@ -888,7 +928,7 @@ class QueryDevtoolsOverrideMenuComponent {
888
928
  this.rootMenu().closeAll();
889
929
  }
890
930
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsOverrideMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
891
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsOverrideMenuComponent, isStandalone: true, selector: "et-query-devtools-override-menu", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: false, transformFunction: null }, parentKind: { classPropertyName: "parentKind", publicName: "parentKind", isSignal: true, isRequired: false, transformFunction: null }, overrides: { classPropertyName: "overrides", publicName: "overrides", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "rootMenu", first: true, predicate: ["rootMenu"], descendants: true, isSignal: true }, { propertyName: "customInput", first: true, predicate: ["customValueInput"], descendants: true, isSignal: true }, { propertyName: "pasteInput", first: true, predicate: ["pasteBox"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #rootMenu=\"etMenu\" (openChange)=\"resetEditingState($event)\" class=\"et-query-devtools-override-menu\" etMenu>\n <button\n class=\"et-query-devtools-override-trigger\"\n aria-label=\"Override this value\"\n title=\"Override this value\"\n etMenuTrigger\n type=\"button\"\n >\n \u270E\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (customMode()) {\n <input\n #customValueInput\n [error]=\"menuError()\"\n [placeholder]=\"customPlaceholder()\"\n (keydown.enter)=\"commitCustomValue()\"\n etMenuSearch\n type=\"text\"\n />\n } @else if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"menuError()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste here\"\n />\n }\n </ng-container>\n\n @if (customMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitCustomValue()\" et-menu-item type=\"button\">Apply</button>\n } @else if (pendingPaste(); as pending) {\n <p class=\"et-query-devtools-override-note\">\n This replaces {{ kind() === 'undefined' ? 'a missing value' : 'the ' + kind() }} with {{ pending.kind }}.\n </p>\n <button (activate)=\"confirmKindChange()\" et-menu-item type=\"button\">Replace anyway</button>\n <button (activate)=\"cancelKindChange()\" et-menu-item type=\"button\">Cancel</button>\n } @else if (pasteMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitPasteBox()\" et-menu-item type=\"button\">Apply</button>\n\n @if (menuNote(); as note) {\n <p class=\"et-query-devtools-override-note\">{{ note }}</p>\n }\n } @else {\n @switch (kind()) {\n @case ('string') {\n @if (isDate()) {\n <button (activate)=\"applyDatePreset('now')\" et-menu-item type=\"button\">Now</button>\n <button (activate)=\"applyDatePreset('plusDay')\" et-menu-item type=\"button\">+1 day</button>\n <button (activate)=\"applyDatePreset('minusDay')\" et-menu-item type=\"button\">-1 day</button>\n <button (activate)=\"applyDatePreset('farFuture')\" et-menu-item type=\"button\">Far future</button>\n <button (activate)=\"applyDatePreset('farPast')\" et-menu-item type=\"button\">Far past</button>\n <button (activate)=\"applyDatePreset('invalid')\" et-menu-item type=\"button\">Invalid date</button>\n } @else {\n <button (activate)=\"applyStringPreset('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"applyStringPreset('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"applyStringPreset('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"applyStringPreset('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n }\n }\n @case ('number') {\n <button (activate)=\"applyNumberPreset('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"applyNumberPreset('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"applyNumberPreset('huge')\" et-menu-item type=\"button\">Huge</button>\n }\n @case ('boolean') {\n <button (activate)=\"flipBoolean()\" et-menu-item type=\"button\">Flip</button>\n }\n @case ('array') {\n <button (activate)=\"duplicateArray()\" et-menu-item type=\"button\">Duplicate array</button>\n\n @if (hasArrayItems()) {\n <button (activate)=\"emptyArray()\" et-menu-item type=\"button\">Empty this array</button>\n }\n }\n }\n\n @if (supportsNull()) {\n <button (activate)=\"setValue(null)\" et-menu-item type=\"button\">Set to null</button>\n }\n\n @if (isEmptyValue()) {\n <button (activate)=\"setValue('Ab')\" et-menu-item type=\"button\">Set to text</button>\n <button (activate)=\"setValue(0)\" et-menu-item type=\"button\">Set to number</button>\n <button (activate)=\"setValue(true)\" et-menu-item type=\"button\">Set to true</button>\n <button (activate)=\"setValue({})\" et-menu-item type=\"button\">Set to empty object</button>\n <button (activate)=\"setValue([])\" et-menu-item type=\"button\">Set to empty array</button>\n }\n\n @if (supportsCustomValue()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"startCustomEdit()\" et-menu-item type=\"button\">Custom\u2026</button>\n }\n\n @if (isArrayElement()) {\n <button (activate)=\"duplicateThisItem()\" et-menu-item type=\"button\">Duplicate this item</button>\n }\n\n @if (paginationShape()) {\n <button (activate)=\"resizePagination('shrink')\" et-menu-item type=\"button\">Shrink page by 1</button>\n <button (activate)=\"resizePagination('extend')\" et-menu-item type=\"button\">Extend page by 1</button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteValue()\" et-menu-item type=\"button\">Paste value</button>\n\n @if (kind() === 'array') {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteArrayItem()\" et-menu-item type=\"button\">\n Paste as new item\n </button>\n }\n\n @if (isContainer()) {\n <et-menu-separator />\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every string</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillStrings('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"fillStrings('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"fillStrings('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"fillStrings('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n </et-menu>\n </ng-template>\n </div>\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every number</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillNumbers('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"fillNumbers('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"fillNumbers('huge')\" et-menu-item type=\"button\">Huge</button>\n </et-menu>\n </ng-template>\n </div>\n\n <button (activate)=\"fillBooleans()\" et-menu-item type=\"button\">Flip every boolean</button>\n }\n\n @if (isRemovable()) {\n <et-menu-separator />\n\n <button (activate)=\"deleteThis()\" et-menu-item variant=\"destructive\" type=\"button\">\n {{ isInArray() ? 'Delete this item' : 'Delete this key' }}\n </button>\n }\n\n @if (menuError(); as err) {\n <p [etProvideColor]=\"errorColorTheme\" class=\"et-query-devtools-override-error\" role=\"alert\">{{ err }}</p>\n }\n\n @if (hasArmedOverrides()) {\n <et-menu-separator />\n\n <button (activate)=\"reset()\" et-menu-item variant=\"destructive\" type=\"button\">Reset</button>\n }\n }\n </et-menu>\n </ng-template>\n</div>\n", dependencies: [{ kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuSearchDirective, selector: "input[etMenuSearch]", inputs: ["query", "loading", "error"], outputs: ["queryChange"], exportAs: ["etMenuSearch"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "component", type: MenuSeparatorComponent, selector: "et-menu-separator" }, { kind: "directive", type: ProvideColorDirective, selector: "[etProvideColor]", inputs: ["etProvideColor"] }], encapsulation: i0.ViewEncapsulation.None }); }
931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsOverrideMenuComponent, isStandalone: true, selector: "et-query-devtools-override-menu", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: false, transformFunction: null }, parentKind: { classPropertyName: "parentKind", publicName: "parentKind", isSignal: true, isRequired: false, transformFunction: null }, overrides: { classPropertyName: "overrides", publicName: "overrides", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "rootMenu", first: true, predicate: ["rootMenu"], descendants: true, isSignal: true }, { propertyName: "customInput", first: true, predicate: ["customValueInput"], descendants: true, isSignal: true }, { propertyName: "pasteInput", first: true, predicate: ["pasteBox"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #rootMenu=\"etMenu\" (openChange)=\"resetEditingState($event)\" class=\"et-query-devtools-override-menu\" etMenu>\n <button\n class=\"et-query-devtools-override-trigger\"\n aria-label=\"Override this value\"\n title=\"Override this value\"\n etMenuTrigger\n type=\"button\"\n >\n \u270E\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (customMode()) {\n <input\n #customValueInput\n [error]=\"menuError()\"\n [placeholder]=\"customPlaceholder()\"\n (keydown.enter)=\"commitCustomValue()\"\n etMenuSearch\n type=\"text\"\n />\n } @else if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"menuError()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste here\"\n />\n }\n </ng-container>\n\n @if (customMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitCustomValue()\" et-menu-item type=\"button\">Apply</button>\n } @else if (pendingPaste(); as pending) {\n <p class=\"et-query-devtools-override-note\">\n This replaces {{ kind() === 'undefined' ? 'a missing value' : 'the ' + kind() }} with {{ pending.kind }}.\n </p>\n <button (activate)=\"confirmKindChange()\" et-menu-item type=\"button\">Replace anyway</button>\n <button (activate)=\"cancelKindChange()\" et-menu-item type=\"button\">Cancel</button>\n } @else if (pasteMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitPasteBox()\" et-menu-item type=\"button\">Apply</button>\n\n @if (menuNote(); as note) {\n <p class=\"et-query-devtools-override-note\">{{ note }}</p>\n }\n } @else {\n @switch (kind()) {\n @case ('string') {\n @if (isDate()) {\n <button (activate)=\"applyDatePreset('now')\" et-menu-item type=\"button\">Now</button>\n <button (activate)=\"applyDatePreset('plusDay')\" et-menu-item type=\"button\">+1 day</button>\n <button (activate)=\"applyDatePreset('minusDay')\" et-menu-item type=\"button\">-1 day</button>\n <button (activate)=\"applyDatePreset('farFuture')\" et-menu-item type=\"button\">Far future</button>\n <button (activate)=\"applyDatePreset('farPast')\" et-menu-item type=\"button\">Far past</button>\n <button (activate)=\"applyDatePreset('invalid')\" et-menu-item type=\"button\">Invalid date</button>\n } @else {\n <button (activate)=\"applyStringPreset('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"applyStringPreset('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"applyStringPreset('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"applyStringPreset('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n }\n }\n @case ('number') {\n <button (activate)=\"applyNumberPreset('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"applyNumberPreset('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"applyNumberPreset('huge')\" et-menu-item type=\"button\">Huge</button>\n }\n @case ('boolean') {\n <button (activate)=\"flipBoolean()\" et-menu-item type=\"button\">Flip</button>\n }\n @case ('array') {\n <button (activate)=\"duplicateArray()\" et-menu-item type=\"button\">Duplicate array</button>\n\n @if (hasArrayItems()) {\n <button (activate)=\"emptyArray()\" et-menu-item type=\"button\">Empty this array</button>\n }\n }\n }\n\n @if (supportsNull()) {\n <button (activate)=\"setValue(null)\" et-menu-item type=\"button\">Set to null</button>\n }\n\n @if (isEmptyValue()) {\n <button (activate)=\"setValue('Ab')\" et-menu-item type=\"button\">Set to text</button>\n <button (activate)=\"setValue(0)\" et-menu-item type=\"button\">Set to number</button>\n <button (activate)=\"setValue(true)\" et-menu-item type=\"button\">Set to true</button>\n <button (activate)=\"setValue({})\" et-menu-item type=\"button\">Set to empty object</button>\n <button (activate)=\"setValue([])\" et-menu-item type=\"button\">Set to empty array</button>\n }\n\n @if (supportsCustomValue()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"startCustomEdit()\" et-menu-item type=\"button\">Custom\u2026</button>\n }\n\n @if (isArrayElement()) {\n <button (activate)=\"duplicateThisItem()\" et-menu-item type=\"button\">Duplicate this item</button>\n }\n\n @if (paginationShape()) {\n <button (activate)=\"resizePagination('shrink')\" et-menu-item type=\"button\">Shrink page by 1</button>\n <button (activate)=\"resizePagination('extend')\" et-menu-item type=\"button\">Extend page by 1</button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteValue()\" et-menu-item type=\"button\">Paste value</button>\n\n @if (kind() === 'array') {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteArrayItem()\" et-menu-item type=\"button\">\n Paste as new item\n </button>\n }\n\n @if (isContainer()) {\n <et-menu-separator />\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every string</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillStrings('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"fillStrings('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"fillStrings('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"fillStrings('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n </et-menu>\n </ng-template>\n </div>\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every number</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillNumbers('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"fillNumbers('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"fillNumbers('huge')\" et-menu-item type=\"button\">Huge</button>\n </et-menu>\n </ng-template>\n </div>\n\n <button (activate)=\"fillBooleans()\" et-menu-item type=\"button\">Flip every boolean</button>\n }\n\n @if (isRemovable()) {\n <et-menu-separator />\n\n <button (activate)=\"deleteThis()\" et-menu-item variant=\"destructive\" type=\"button\">\n {{ isInArray() ? 'Delete this item' : 'Delete this key' }}\n </button>\n }\n\n @if (menuError(); as err) {\n <p\n #errorTheme=\"etQueryDevtoolsErrorTheme\"\n [etProvideColor]=\"errorTheme.theme()\"\n class=\"et-query-devtools-override-error\"\n role=\"alert\"\n etQueryDevtoolsErrorTheme\n >\n {{ err }}\n </p>\n }\n\n @if (hasArmedOverrides()) {\n <et-menu-separator />\n\n <button (activate)=\"reset()\" et-menu-item variant=\"destructive\" type=\"button\">Reset</button>\n }\n }\n </et-menu>\n </ng-template>\n</div>\n", dependencies: [{ kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuSearchDirective, selector: "input[etMenuSearch]", inputs: ["query", "loading", "error"], outputs: ["queryChange"], exportAs: ["etMenuSearch"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "component", type: MenuSeparatorComponent, selector: "et-menu-separator" }, { kind: "directive", type: ProvideColorDirective, selector: "[etProvideColor]", inputs: ["etProvideColor"] }, { kind: "directive", type: QueryDevtoolsErrorThemeDirective, selector: "[etQueryDevtoolsErrorTheme]", exportAs: ["etQueryDevtoolsErrorTheme"] }], encapsulation: i0.ViewEncapsulation.None }); }
892
932
  }
893
933
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsOverrideMenuComponent, decorators: [{
894
934
  type: Component,
@@ -902,7 +942,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
902
942
  MenuItemShortcutComponent,
903
943
  MenuSeparatorComponent,
904
944
  ProvideColorDirective,
905
- ], template: "<div #rootMenu=\"etMenu\" (openChange)=\"resetEditingState($event)\" class=\"et-query-devtools-override-menu\" etMenu>\n <button\n class=\"et-query-devtools-override-trigger\"\n aria-label=\"Override this value\"\n title=\"Override this value\"\n etMenuTrigger\n type=\"button\"\n >\n \u270E\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (customMode()) {\n <input\n #customValueInput\n [error]=\"menuError()\"\n [placeholder]=\"customPlaceholder()\"\n (keydown.enter)=\"commitCustomValue()\"\n etMenuSearch\n type=\"text\"\n />\n } @else if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"menuError()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste here\"\n />\n }\n </ng-container>\n\n @if (customMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitCustomValue()\" et-menu-item type=\"button\">Apply</button>\n } @else if (pendingPaste(); as pending) {\n <p class=\"et-query-devtools-override-note\">\n This replaces {{ kind() === 'undefined' ? 'a missing value' : 'the ' + kind() }} with {{ pending.kind }}.\n </p>\n <button (activate)=\"confirmKindChange()\" et-menu-item type=\"button\">Replace anyway</button>\n <button (activate)=\"cancelKindChange()\" et-menu-item type=\"button\">Cancel</button>\n } @else if (pasteMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitPasteBox()\" et-menu-item type=\"button\">Apply</button>\n\n @if (menuNote(); as note) {\n <p class=\"et-query-devtools-override-note\">{{ note }}</p>\n }\n } @else {\n @switch (kind()) {\n @case ('string') {\n @if (isDate()) {\n <button (activate)=\"applyDatePreset('now')\" et-menu-item type=\"button\">Now</button>\n <button (activate)=\"applyDatePreset('plusDay')\" et-menu-item type=\"button\">+1 day</button>\n <button (activate)=\"applyDatePreset('minusDay')\" et-menu-item type=\"button\">-1 day</button>\n <button (activate)=\"applyDatePreset('farFuture')\" et-menu-item type=\"button\">Far future</button>\n <button (activate)=\"applyDatePreset('farPast')\" et-menu-item type=\"button\">Far past</button>\n <button (activate)=\"applyDatePreset('invalid')\" et-menu-item type=\"button\">Invalid date</button>\n } @else {\n <button (activate)=\"applyStringPreset('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"applyStringPreset('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"applyStringPreset('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"applyStringPreset('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n }\n }\n @case ('number') {\n <button (activate)=\"applyNumberPreset('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"applyNumberPreset('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"applyNumberPreset('huge')\" et-menu-item type=\"button\">Huge</button>\n }\n @case ('boolean') {\n <button (activate)=\"flipBoolean()\" et-menu-item type=\"button\">Flip</button>\n }\n @case ('array') {\n <button (activate)=\"duplicateArray()\" et-menu-item type=\"button\">Duplicate array</button>\n\n @if (hasArrayItems()) {\n <button (activate)=\"emptyArray()\" et-menu-item type=\"button\">Empty this array</button>\n }\n }\n }\n\n @if (supportsNull()) {\n <button (activate)=\"setValue(null)\" et-menu-item type=\"button\">Set to null</button>\n }\n\n @if (isEmptyValue()) {\n <button (activate)=\"setValue('Ab')\" et-menu-item type=\"button\">Set to text</button>\n <button (activate)=\"setValue(0)\" et-menu-item type=\"button\">Set to number</button>\n <button (activate)=\"setValue(true)\" et-menu-item type=\"button\">Set to true</button>\n <button (activate)=\"setValue({})\" et-menu-item type=\"button\">Set to empty object</button>\n <button (activate)=\"setValue([])\" et-menu-item type=\"button\">Set to empty array</button>\n }\n\n @if (supportsCustomValue()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"startCustomEdit()\" et-menu-item type=\"button\">Custom\u2026</button>\n }\n\n @if (isArrayElement()) {\n <button (activate)=\"duplicateThisItem()\" et-menu-item type=\"button\">Duplicate this item</button>\n }\n\n @if (paginationShape()) {\n <button (activate)=\"resizePagination('shrink')\" et-menu-item type=\"button\">Shrink page by 1</button>\n <button (activate)=\"resizePagination('extend')\" et-menu-item type=\"button\">Extend page by 1</button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteValue()\" et-menu-item type=\"button\">Paste value</button>\n\n @if (kind() === 'array') {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteArrayItem()\" et-menu-item type=\"button\">\n Paste as new item\n </button>\n }\n\n @if (isContainer()) {\n <et-menu-separator />\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every string</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillStrings('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"fillStrings('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"fillStrings('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"fillStrings('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n </et-menu>\n </ng-template>\n </div>\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every number</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillNumbers('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"fillNumbers('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"fillNumbers('huge')\" et-menu-item type=\"button\">Huge</button>\n </et-menu>\n </ng-template>\n </div>\n\n <button (activate)=\"fillBooleans()\" et-menu-item type=\"button\">Flip every boolean</button>\n }\n\n @if (isRemovable()) {\n <et-menu-separator />\n\n <button (activate)=\"deleteThis()\" et-menu-item variant=\"destructive\" type=\"button\">\n {{ isInArray() ? 'Delete this item' : 'Delete this key' }}\n </button>\n }\n\n @if (menuError(); as err) {\n <p [etProvideColor]=\"errorColorTheme\" class=\"et-query-devtools-override-error\" role=\"alert\">{{ err }}</p>\n }\n\n @if (hasArmedOverrides()) {\n <et-menu-separator />\n\n <button (activate)=\"reset()\" et-menu-item variant=\"destructive\" type=\"button\">Reset</button>\n }\n }\n </et-menu>\n </ng-template>\n</div>\n" }]
945
+ QueryDevtoolsErrorThemeDirective,
946
+ ], template: "<div #rootMenu=\"etMenu\" (openChange)=\"resetEditingState($event)\" class=\"et-query-devtools-override-menu\" etMenu>\n <button\n class=\"et-query-devtools-override-trigger\"\n aria-label=\"Override this value\"\n title=\"Override this value\"\n etMenuTrigger\n type=\"button\"\n >\n \u270E\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (customMode()) {\n <input\n #customValueInput\n [error]=\"menuError()\"\n [placeholder]=\"customPlaceholder()\"\n (keydown.enter)=\"commitCustomValue()\"\n etMenuSearch\n type=\"text\"\n />\n } @else if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"menuError()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste here\"\n />\n }\n </ng-container>\n\n @if (customMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitCustomValue()\" et-menu-item type=\"button\">Apply</button>\n } @else if (pendingPaste(); as pending) {\n <p class=\"et-query-devtools-override-note\">\n This replaces {{ kind() === 'undefined' ? 'a missing value' : 'the ' + kind() }} with {{ pending.kind }}.\n </p>\n <button (activate)=\"confirmKindChange()\" et-menu-item type=\"button\">Replace anyway</button>\n <button (activate)=\"cancelKindChange()\" et-menu-item type=\"button\">Cancel</button>\n } @else if (pasteMode()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"commitPasteBox()\" et-menu-item type=\"button\">Apply</button>\n\n @if (menuNote(); as note) {\n <p class=\"et-query-devtools-override-note\">{{ note }}</p>\n }\n } @else {\n @switch (kind()) {\n @case ('string') {\n @if (isDate()) {\n <button (activate)=\"applyDatePreset('now')\" et-menu-item type=\"button\">Now</button>\n <button (activate)=\"applyDatePreset('plusDay')\" et-menu-item type=\"button\">+1 day</button>\n <button (activate)=\"applyDatePreset('minusDay')\" et-menu-item type=\"button\">-1 day</button>\n <button (activate)=\"applyDatePreset('farFuture')\" et-menu-item type=\"button\">Far future</button>\n <button (activate)=\"applyDatePreset('farPast')\" et-menu-item type=\"button\">Far past</button>\n <button (activate)=\"applyDatePreset('invalid')\" et-menu-item type=\"button\">Invalid date</button>\n } @else {\n <button (activate)=\"applyStringPreset('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"applyStringPreset('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"applyStringPreset('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"applyStringPreset('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n }\n }\n @case ('number') {\n <button (activate)=\"applyNumberPreset('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"applyNumberPreset('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"applyNumberPreset('huge')\" et-menu-item type=\"button\">Huge</button>\n }\n @case ('boolean') {\n <button (activate)=\"flipBoolean()\" et-menu-item type=\"button\">Flip</button>\n }\n @case ('array') {\n <button (activate)=\"duplicateArray()\" et-menu-item type=\"button\">Duplicate array</button>\n\n @if (hasArrayItems()) {\n <button (activate)=\"emptyArray()\" et-menu-item type=\"button\">Empty this array</button>\n }\n }\n }\n\n @if (supportsNull()) {\n <button (activate)=\"setValue(null)\" et-menu-item type=\"button\">Set to null</button>\n }\n\n @if (isEmptyValue()) {\n <button (activate)=\"setValue('Ab')\" et-menu-item type=\"button\">Set to text</button>\n <button (activate)=\"setValue(0)\" et-menu-item type=\"button\">Set to number</button>\n <button (activate)=\"setValue(true)\" et-menu-item type=\"button\">Set to true</button>\n <button (activate)=\"setValue({})\" et-menu-item type=\"button\">Set to empty object</button>\n <button (activate)=\"setValue([])\" et-menu-item type=\"button\">Set to empty array</button>\n }\n\n @if (supportsCustomValue()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"startCustomEdit()\" et-menu-item type=\"button\">Custom\u2026</button>\n }\n\n @if (isArrayElement()) {\n <button (activate)=\"duplicateThisItem()\" et-menu-item type=\"button\">Duplicate this item</button>\n }\n\n @if (paginationShape()) {\n <button (activate)=\"resizePagination('shrink')\" et-menu-item type=\"button\">Shrink page by 1</button>\n <button (activate)=\"resizePagination('extend')\" et-menu-item type=\"button\">Extend page by 1</button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteValue()\" et-menu-item type=\"button\">Paste value</button>\n\n @if (kind() === 'array') {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteArrayItem()\" et-menu-item type=\"button\">\n Paste as new item\n </button>\n }\n\n @if (isContainer()) {\n <et-menu-separator />\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every string</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillStrings('short')\" et-menu-item type=\"button\">Short text</button>\n <button (activate)=\"fillStrings('long')\" et-menu-item type=\"button\">Long text</button>\n <button (activate)=\"fillStrings('longWord')\" et-menu-item type=\"button\">Long word</button>\n <button (activate)=\"fillStrings('unicode')\" et-menu-item type=\"button\">Unicode / RTL sample</button>\n </et-menu>\n </ng-template>\n </div>\n\n <div etMenu>\n <button et-menu-item etMenuTrigger type=\"button\">Fill every number</button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"fillNumbers('zero')\" et-menu-item type=\"button\">Zero</button>\n <button (activate)=\"fillNumbers('negative')\" et-menu-item type=\"button\">Negative</button>\n <button (activate)=\"fillNumbers('huge')\" et-menu-item type=\"button\">Huge</button>\n </et-menu>\n </ng-template>\n </div>\n\n <button (activate)=\"fillBooleans()\" et-menu-item type=\"button\">Flip every boolean</button>\n }\n\n @if (isRemovable()) {\n <et-menu-separator />\n\n <button (activate)=\"deleteThis()\" et-menu-item variant=\"destructive\" type=\"button\">\n {{ isInArray() ? 'Delete this item' : 'Delete this key' }}\n </button>\n }\n\n @if (menuError(); as err) {\n <p\n #errorTheme=\"etQueryDevtoolsErrorTheme\"\n [etProvideColor]=\"errorTheme.theme()\"\n class=\"et-query-devtools-override-error\"\n role=\"alert\"\n etQueryDevtoolsErrorTheme\n >\n {{ err }}\n </p>\n }\n\n @if (hasArmedOverrides()) {\n <et-menu-separator />\n\n <button (activate)=\"reset()\" et-menu-item variant=\"destructive\" type=\"button\">Reset</button>\n }\n }\n </et-menu>\n </ng-template>\n</div>\n" }]
906
947
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], path: [{ type: i0.Input, args: [{ isSignal: true, alias: "path", required: false }] }], parentKind: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentKind", required: false }] }], overrides: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrides", required: true }] }], rootMenu: [{ type: i0.ViewChild, args: ['rootMenu', { isSignal: true }] }], customInput: [{ type: i0.ViewChild, args: ['customValueInput', { isSignal: true }] }], pasteInput: [{ type: i0.ViewChild, args: ['pasteBox', { isSignal: true }] }] } });
907
948
  const parseLooseJson = (raw) => {
908
949
  try {
@@ -1514,336 +1555,33 @@ const matchesDeep = (entry, term) => {
1514
1555
  return walk(entry);
1515
1556
  };
1516
1557
 
1517
- const QUERY_DEVTOOLS_HOST = new InjectionToken('QUERY_DEVTOOLS_HOST');
1518
- /** Injects the panel a tab or the detail drawer is rendered inside of. @see QueryDevtoolsHost */
1519
- const injectQueryDevtoolsHost = () => inject(QUERY_DEVTOOLS_HOST);
1520
-
1521
- const isAbsoluteHttpUrl = (value) => {
1522
- try {
1523
- return ['http:', 'https:'].includes(new URL(value).protocol);
1524
- }
1525
- catch {
1526
- return false;
1527
- }
1528
- };
1529
- const SCOPE_ROWS = [
1530
- {
1531
- key: 'viewState',
1532
- label: 'Panel view state',
1533
- hint: 'Where the panel sits, how big it is, the open tab, every filter and the selected query. Set none to forget all of it on each reload.',
1534
- },
1535
- {
1536
- key: 'pins',
1537
- label: 'Pinned queries',
1538
- hint: 'Which queries sort to the top of the list. Local outlives the tab, because a pin says what you are working on rather than what you are looking at.',
1539
- },
1540
- {
1541
- key: 'overrides',
1542
- label: 'Response overrides',
1543
- hint: 'Armed edits, replayed as queries register - before their first fetch. None is the default: a reload is how the app stops being lied to.',
1544
- warn: {
1545
- scopes: ['local'],
1546
- text: 'Armed overrides now outlive closing the tab. An app that stays tampered with across days is hours of debugging the wrong thing - the bar above the tabs says when they came back.',
1547
- },
1548
- },
1549
- {
1550
- key: 'mocks',
1551
- label: 'Designed mocks',
1552
- hint: 'The library you authored, not whether any of it is armed - arming has its own scope below.',
1553
- },
1554
- {
1555
- key: 'armedMocks',
1556
- label: 'Armed mocks',
1557
- hint: 'Which of the library is served. None is the default: a reload is how the app goes back to talking to the API.',
1558
- warn: {
1559
- scopes: ['session', 'local'],
1560
- text: 'The next page load starts serving these routes from the panel, before anyone opens it. The bar above the tabs says when they came back.',
1561
- },
1562
- },
1563
- {
1564
- key: 'authSessions',
1565
- label: 'Sessions and accounts',
1566
- hint: 'The token pairs the Auth tab switches between, and the credentials it logs in with. Local is the default in a development build: a vault that forgets the other user on every reload is not one. None keeps nothing at all.',
1567
- warn: {
1568
- scopes: ['local'],
1569
- text: 'Access and refresh tokens for every user you logged in as, plus what you typed into the account fields, stay in this browser until you forget them. They are never kept for an API env marked production.',
1570
- },
1571
- },
1572
- {
1573
- key: 'armedFaults',
1574
- label: 'Armed faults',
1575
- hint: 'The latency and failures injected per client, budgets included. None is the default, for the same reason as armed mocks.',
1576
- warn: {
1577
- scopes: ['session', 'local'],
1578
- text: 'The next page load starts injecting these failures on its own, so an app that looks broken may only be armed. The bar above the tabs says when they came back.',
1579
- },
1580
- },
1581
- ];
1582
- const SCOPES = [
1583
- { value: 'none', label: 'none' },
1584
- { value: 'session', label: 'session' },
1585
- { value: 'local', label: 'local' },
1586
- ];
1587
- /**
1588
- * Why IndexedDB - the one store with the quota for a large library of designed data - is not on offer.
1589
- * These are read synchronously: view state and pins in a field initializer of the panel, and overrides
1590
- * inside query registration, before the first request. An async store cannot answer either in time, and a
1591
- * scope that silently arrives late is worse than one that is missing. The mock library is the one that
1592
- * could tolerate arriving late, since nothing is served until a mock is armed by hand.
1593
- */
1594
- const INDEXED_DB_TITLE = 'Unavailable: these are read synchronously - view state before the first render, overrides before the first fetch - and IndexedDB cannot answer in time. Only the mock library could tolerate an async store, and it is not wired to one yet.';
1595
- const LIMIT_ROWS = [
1596
- {
1597
- key: 'maxEvents',
1598
- label: 'Events log',
1599
- min: 10,
1600
- max: 1000,
1601
- step: 10,
1602
- hint: 'rows the Events tab keeps. Lowering it trims the log now.',
1603
- },
1604
- {
1605
- key: 'maxDroppedCacheEntries',
1606
- label: 'Dropped cache entries',
1607
- min: 0,
1608
- max: 200,
1609
- step: 5,
1610
- hint: 'per client, remembered so the Cache tab can say why an entry went away. Applies as entries are dropped.',
1611
- },
1612
- ];
1613
- /**
1614
- * Every panel-wide switch in one place - the storage each kind of state uses, the limits the panel would
1615
- * otherwise hold as constants, and the toggles their own tabs also carry.
1616
- */
1617
- class QueryDevtoolsSettingsComponent {
1558
+ /** `username, password` as typed in the add row, into the fields the login args are built from. */
1559
+ const parseAuthFields = (value) => [...new Set(value.split(/[\s,]+/).filter(Boolean))].map((name) => ({
1560
+ name,
1561
+ type: /pass|secret|token/i.test(name) ? 'password' : 'text',
1562
+ }));
1563
+ /** The Auth tab: registered bearer auth providers, their tokens, their sessions and their queries. */
1564
+ class QueryDevtoolsAuthTabComponent {
1618
1565
  constructor() {
1619
- this.document = inject(DOCUMENT);
1620
1566
  this.host = injectQueryDevtoolsHost();
1621
- this.SCOPE_ROWS = SCOPE_ROWS;
1622
- this.SCOPES = SCOPES;
1623
- this.INDEXED_DB_TITLE = INDEXED_DB_TITLE;
1624
- this.LIMIT_ROWS = LIMIT_ROWS;
1625
- this.ARM_ALL_MOCKS = armAllQueryDevtoolsMocks;
1626
- this.DISARM_ALL_MOCKS = clearQueryDevtoolsArmedMocks;
1627
- this.DISARM_ALL_FAULTS = clearQueryDevtoolsFaults;
1628
- /** What queries actually retain, which is the application's value unless this panel raised it. */
1629
- this.responseHistory = computed(queryDevtoolsResponseHistory, /* @ts-ignore */
1630
- ...(ngDevMode ? [{ debugName: "responseHistory" }] : /* istanbul ignore next */ []));
1631
- this.mockCount = computed(() => queryDevtoolsMocks().length, /* @ts-ignore */
1632
- ...(ngDevMode ? [{ debugName: "mockCount" }] : /* istanbul ignore next */ []));
1633
- this.sessionCount = computed(() => queryDevtoolsAuthSessions().length, /* @ts-ignore */
1634
- ...(ngDevMode ? [{ debugName: "sessionCount" }] : /* istanbul ignore next */ []));
1635
- this.armedMockCount = computed(() => queryDevtoolsArmedMocks().size, /* @ts-ignore */
1636
- ...(ngDevMode ? [{ debugName: "armedMockCount" }] : /* istanbul ignore next */ []));
1637
- this.armedFaultCount = computed(() => this.host.faultClients().filter((client) => client.armed).length, /* @ts-ignore */
1638
- ...(ngDevMode ? [{ debugName: "armedFaultCount" }] : /* istanbul ignore next */ []));
1639
- /** The same keys the Events tab's own picker offers - see {@link queryDevtoolsEventClients}. */
1640
- this.eventClients = computed(() => queryDevtoolsEventClients(this.host.eventLog(), this.host.eventClient()), /* @ts-ignore */
1641
- ...(ngDevMode ? [{ debugName: "eventClients" }] : /* istanbul ignore next */ []));
1642
- this.resetConfirming = signal(false, /* @ts-ignore */
1643
- ...(ngDevMode ? [{ debugName: "resetConfirming" }] : /* istanbul ignore next */ []));
1644
- this.FORGET_SESSIONS = clearQueryDevtoolsAuthSessions;
1645
- /** The backends the application declared, or an empty list - the card renders only for a declared one. */
1646
- this.apiEnvs = computed(queryDevtoolsApiEnvs, /* @ts-ignore */
1647
- ...(ngDevMode ? [{ debugName: "apiEnvs" }] : /* istanbul ignore next */ []));
1648
- }
1649
- /** The env id (or typed URL) a switch's key holds, or `null` while the application picks for itself. */
1650
- apiEnvValue(apiSwitch) {
1651
- return queryDevtoolsApiEnvValues()[apiSwitch.storageKey] ?? null;
1567
+ this.TTL_LIMIT = QUERY_DEVTOOLS_TOKEN_TTL_LIMIT;
1568
+ /** Which accounts show their credential fields. Nothing is expanded until somebody asks for it. */
1569
+ this.expandedAccounts = signal(new Set(), /* @ts-ignore */
1570
+ ...(ngDevMode ? [{ debugName: "expandedAccounts" }] : /* istanbul ignore next */ []));
1571
+ /** Which providers show the form that adds an account of your own. */
1572
+ this.addingFor = signal(new Set(), /* @ts-ignore */
1573
+ ...(ngDevMode ? [{ debugName: "addingFor" }] : /* istanbul ignore next */ []));
1574
+ /** Nothing of a real user is ever kept on this machine, so the whole vault stands down. */
1575
+ this.production = computed(queryDevtoolsApiEnvIsProduction, /* @ts-ignore */
1576
+ ...(ngDevMode ? [{ debugName: "production" }] : /* istanbul ignore next */ []));
1577
+ this.reloadOnSwitch = computed(() => queryDevtoolsSettings().reloadOnAuthSwitch, /* @ts-ignore */
1578
+ ...(ngDevMode ? [{ debugName: "reloadOnSwitch" }] : /* istanbul ignore next */ []));
1652
1579
  }
1653
- /** The env a switch falls back to with nothing stored, described for the default button. */
1654
- apiEnvFallback(apiSwitch) {
1655
- const fallback = apiSwitch.envs.find((env) => env.id === apiSwitch.fallback);
1656
- return {
1657
- label: fallback ? `default (${fallback.label ?? fallback.id})` : 'default',
1658
- production: fallback?.production === true,
1659
- };
1580
+ sessionsFor(entry) {
1581
+ return queryDevtoolsAuthSessionsFor(this.providerName(entry));
1660
1582
  }
1661
- /** Whether the pick in force - the stored env, or the fallback behind an unwritten key - is production. */
1662
- apiEnvIsProduction(apiSwitch) {
1663
- const stored = this.apiEnvValue(apiSwitch);
1664
- return apiSwitch.envs.find((env) => env.id === (stored ?? apiSwitch.fallback))?.production === true;
1665
- }
1666
- /** A stored value no declared env carries, which is a URL somebody typed in below. */
1667
- apiEnvCustomUrl(apiSwitch) {
1668
- const stored = this.apiEnvValue(apiSwitch);
1669
- return stored && !apiSwitch.envs.some((env) => env.id === stored) ? stored : '';
1670
- }
1671
- /** Writes the application's own key and reloads - it is read before Angular boots, so nothing else can. */
1672
- pickApiEnv(apiSwitch, value) {
1673
- setQueryDevtoolsApiEnv(apiSwitch.storageKey, value);
1674
- this.document.defaultView?.location.reload();
1675
- }
1676
- setCustomApiUrl(apiSwitch, value) {
1677
- const url = value.trim();
1678
- if (url === this.apiEnvCustomUrl(apiSwitch))
1679
- return;
1680
- if (url && !isAbsoluteHttpUrl(url))
1681
- return;
1682
- this.pickApiEnv(apiSwitch, url || null);
1683
- }
1684
- settings() {
1685
- return queryDevtoolsSettings();
1686
- }
1687
- scopeOf(key) {
1688
- return this.settings()[key];
1689
- }
1690
- limitOf(key) {
1691
- return this.settings()[key];
1692
- }
1693
- /** What the picked scope means beyond where the state is kept, or `null` while it means nothing extra. */
1694
- warningFor(row, scope) {
1695
- return row.warn?.scopes.includes(scope) ? row.warn.text : null;
1696
- }
1697
- /** Why one scope is not on offer for a row, for the button's title, or `null` while it is. */
1698
- unavailableReason(row, scope) {
1699
- if (row.key !== 'authSessions' || scope !== 'local' || queryDevtoolsAllowsLocalAuthSessions())
1700
- return null;
1701
- return 'Unavailable outside a development build: live access and refresh tokens, and the credentials you typed in, must not outlive this tab on a deployed origin. The vault keeps nothing here unless you pick Session, which keeps it for as long as the tab.';
1702
- }
1703
- setScope(key, scope) {
1704
- // Everything armed goes through its own module: changing the scope moves an existing store and
1705
- // captures whatever is armed right now, so the choice reads as "keep these".
1706
- if (key === 'overrides')
1707
- return setQueryDevtoolsOverridesScope(scope);
1708
- if (key === 'armedMocks')
1709
- return setQueryDevtoolsArmedMocksScope(scope);
1710
- if (key === 'armedFaults')
1711
- return setQueryDevtoolsFaultsScope(scope);
1712
- setQueryDevtoolsSettings(key === 'viewState'
1713
- ? { viewState: scope }
1714
- : key === 'pins'
1715
- ? { pins: scope }
1716
- : key === 'authSessions'
1717
- ? { authSessions: scope }
1718
- : { mocks: scope });
1719
- }
1720
- setLimit(key, value) {
1721
- const count = Number(value);
1722
- setQueryDevtoolsSettings(key === 'maxEvents' ? { maxEvents: count } : { maxDroppedCacheEntries: count });
1723
- }
1724
- setResponseHistory(value) {
1725
- setQueryDevtoolsSettings({ responseHistory: Number(value) });
1726
- }
1727
- /** Hands retention back to `provideQueryDevtools({ responseHistory })`. */
1728
- clearResponseHistory() {
1729
- setQueryDevtoolsSettings({ responseHistory: null });
1730
- }
1731
- reset() {
1732
- this.host.resetDevtools();
1733
- this.resetConfirming.set(false);
1734
- }
1735
- toggleGoneQueries() {
1736
- this.host.toggleFacet('gone');
1737
- }
1738
- showsGoneQueries() {
1739
- return this.host.queryFacets().has('gone');
1740
- }
1741
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1742
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsSettingsComponent, isStandalone: true, selector: "et-query-devtools-settings", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-settings-toolbar\">\n <p class=\"et-query-devtools-hint\">\n Panel-wide, and kept in <code class=\"et-query-devtools-mono\">localStorage</code> whatever the scopes below say -\n so a scope of <em>none</em> does not erase the choice that set it. Every switch under <strong>Mirrored</strong> is\n the same one its own tab carries.\n </p>\n </div>\n\n @if (apiEnvs().length) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>API environment</strong>\n <span class=\"et-query-devtools-count\">the app's own key, not the panel's - picking reloads the page</span>\n </div>\n\n @for (apiSwitch of apiEnvs(); track apiSwitch.storageKey) {\n @let value = apiEnvValue(apiSwitch);\n @let custom = apiEnvCustomUrl(apiSwitch);\n @let fallback = apiEnvFallback(apiSwitch);\n @let production = apiEnvIsProduction(apiSwitch);\n <div [class.et-query-devtools-settings-api--production]=\"production\" class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ apiSwitch.name }}</span>\n <div class=\"et-query-devtools-btn-group\">\n <button\n [class.et-query-devtools-btn--active]=\"value === null\"\n [class.et-query-devtools-btn--danger]=\"fallback.production\"\n [attr.aria-pressed]=\"value === null\"\n (click)=\"pickApiEnv(apiSwitch, null)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ fallback.production ? '\u26A0 ' : '' }}{{ fallback.label }}\n </button>\n @for (env of apiSwitch.envs; track env.id) {\n <button\n [class.et-query-devtools-btn--active]=\"value === env.id\"\n [class.et-query-devtools-btn--danger]=\"env.production\"\n [attr.aria-pressed]=\"value === env.id\"\n [title]=\"env.url ?? env.id\"\n (click)=\"pickApiEnv(apiSwitch, env.id)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ env.production ? '\u26A0 ' : '' }}{{ env.label ?? env.id }}\n </button>\n }\n </div>\n </div>\n @if (production) {\n <strong class=\"et-query-devtools-settings-api-live\">\n Live data. Every request from this app reaches the real backend.\n </strong>\n }\n <small>\n Written to <span class=\"et-query-devtools-mono\">{{ apiSwitch.storageKey }}</span> in\n <code class=\"et-query-devtools-mono\">localStorage</code>, which the app reads before it boots.\n </small>\n @if (apiSwitch.custom) {\n <label class=\"et-query-devtools-field et-query-devtools-settings-api-url\">\n <span>Base URL</span>\n <input\n #customUrlInput\n [value]=\"custom\"\n (change)=\"setCustomApiUrl(apiSwitch, customUrlInput.value)\"\n class=\"et-query-devtools-input\"\n type=\"url\"\n placeholder=\"http://localhost:8040\"\n />\n <small>A backend none of the buttons above name. Empty goes back to the app's own default.</small>\n </label>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Storage</strong>\n <span class=\"et-query-devtools-count\">what survives a reload, and how long</span>\n </div>\n\n @for (row of SCOPE_ROWS; track row.key) {\n @let scope = scopeOf(row.key);\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ row.label }}</span>\n <div class=\"et-query-devtools-btn-group\">\n @for (option of SCOPES; track option.value) {\n @let unavailable = unavailableReason(row, option.value);\n <button\n [class.et-query-devtools-btn--active]=\"scope === option.value\"\n [attr.aria-pressed]=\"scope === option.value\"\n [disabled]=\"!!unavailable\"\n [title]=\"unavailable\"\n (click)=\"setScope(row.key, option.value)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ option.label }}\n </button>\n }\n <button [title]=\"INDEXED_DB_TITLE\" class=\"et-query-devtools-btn\" type=\"button\" disabled>IndexedDB</button>\n </div>\n </div>\n <small>{{ row.hint }}</small>\n @if (warningFor(row, scope); as warning) {\n <p class=\"et-query-devtools-settings-warn\">\n <span aria-hidden=\"true\">\u26A0</span>\n {{ warning }}\n </p>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Reset devtools</span>\n @if (resetConfirming()) {\n <div class=\"et-query-devtools-btn-group\">\n <button (click)=\"reset()\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Reset everything\n </button>\n <button (click)=\"resetConfirming.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <button (click)=\"resetConfirming.set(true)\" class=\"et-query-devtools-btn\" type=\"button\">Reset\u2026</button>\n }\n </div>\n <small>\n Clears every one of these keys from both stores, whatever the scopes above say, and puts the panel back where it\n ships - layout, filters, selections and pins. The settings on this tab stay.\n </small>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Limits</strong>\n <span class=\"et-query-devtools-count\">how much the panel keeps in memory</span>\n </div>\n\n <div class=\"et-query-devtools-settings-fields\">\n @for (row of LIMIT_ROWS; track row.key) {\n <label class=\"et-query-devtools-field\">\n <span>{{ row.label }}</span>\n <input\n #limitInput\n [value]=\"limitOf(row.key)\"\n [min]=\"row.min\"\n [max]=\"row.max\"\n [step]=\"row.step\"\n (change)=\"setLimit(row.key, limitInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n />\n <small>{{ row.hint }}</small>\n </label>\n }\n\n <label class=\"et-query-devtools-field\">\n <span>Response history</span>\n <input\n #responseHistoryInput\n [value]=\"responseHistory()\"\n (change)=\"setResponseHistory(responseHistoryInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"1\"\n max=\"50\"\n step=\"1\"\n />\n <small>\n bodies each query keeps, which is how far back a response diff can reach. Bodies dominate what the run buffer\n retains, so this is the one limit that costs real memory. Applies to runs from now on.\n @if (settings().responseHistory !== null) {\n <button (click)=\"clearResponseHistory()\" class=\"et-query-devtools-btn\" type=\"button\">\n Back to the app's own value\n </button>\n }\n </small>\n </label>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Mirrored</strong>\n <span class=\"et-query-devtools-count\">the same switches their tabs carry</span>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Queries</span>\n <div class=\"et-query-devtools-btn-group\">\n @let recentFirst = host.queryRecentFirst();\n <button\n [class.et-query-devtools-btn--active]=\"recentFirst\"\n [attr.aria-pressed]=\"recentFirst\"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n recent first\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n tree view\n </button>\n @let gone = showsGoneQueries();\n <button\n [class.et-query-devtools-btn--active]=\"gone\"\n [attr.aria-pressed]=\"gone\"\n (click)=\"toggleGoneQueries()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n list gone\n </button>\n </div>\n </div>\n <small>Sort order, whether the list groups by route path, and whether destroyed queries are listed at all.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Sessions</span>\n <div class=\"et-query-devtools-settings-controls\">\n <span class=\"et-query-devtools-count\">{{ sessionCount() }} stored</span>\n <button\n [disabled]=\"!sessionCount()\"\n (click)=\"FORGET_SESSIONS()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n >\n Forget every session\n </button>\n </div>\n </div>\n <small>\n Drops every stored token pair, every account added in the panel and every credential typed into one. The live\n session is left alone - the Auth tab switches between them.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Events</span>\n <div class=\"et-query-devtools-settings-controls\">\n @let errorsOnly = host.eventErrorsOnly();\n <button\n [class.et-query-devtools-btn--active]=\"errorsOnly\"\n [attr.aria-pressed]=\"errorsOnly\"\n (click)=\"host.eventErrorsOnly.set(!errorsOnly)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n failures only\n </button>\n @let pickedClient = host.eventClient();\n <select\n #eventClientSelect\n (change)=\"host.eventClient.set(eventClientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Event log client\"\n >\n <option [selected]=\"!pickedClient\" value=\"\">All clients</option>\n @for (name of eventClients(); track name) {\n <option [value]=\"name\" [selected]=\"name === pickedClient\">{{ name }}</option>\n }\n </select>\n </div>\n </div>\n <small>What the event log is narrowed to. The log itself always holds every client's traffic.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Response overrides</span>\n @let persist = host.overridesPersist();\n <button\n [class.et-query-devtools-btn--active]=\"persist\"\n [attr.aria-pressed]=\"persist\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Keep across reloads\n </button>\n </div>\n <small>\n The drawer's own toggle, which is the Storage scope above - currently\n <span class=\"et-query-devtools-mono\">{{ host.overridesScopeLabel() }}</span\n >.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Armed</span>\n <div class=\"et-query-devtools-settings-controls\">\n <button\n [disabled]=\"!mockCount() || armedMockCount() === mockCount()\"\n (click)=\"ARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Arm every mock ({{ mockCount() }})\n </button>\n <button\n [disabled]=\"!armedMockCount()\"\n (click)=\"DISARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm mocks ({{ armedMockCount() }})\n </button>\n <button\n [disabled]=\"!armedFaultCount()\"\n (click)=\"DISARM_ALL_FAULTS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm faults ({{ armedFaultCount() }})\n </button>\n </div>\n </div>\n <small>\n The Mocks and Faults tabs' own buttons. Whether either survives a reload is the two <em>Armed</em> scopes above,\n both <em>none</em> unless they were changed.\n </small>\n </div>\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-settings-toolbar{align-items:flex-start}.et-query-devtools-settings-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-settings-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-settings-row-head{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem}.et-query-devtools-settings-controls{display:flex;align-items:center;gap:.5rem}.et-query-devtools-settings-row>small{display:block;max-inline-size:60rem;margin-block-start:.3rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-warn{margin:.4rem 0 0;color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-settings-api--production{background:color-mix(in srgb,var(--_et-qdt-error) 8%,transparent);box-shadow:inset .3rem 0 0 var(--_et-qdt-error);padding-inline-start:.8rem}.et-query-devtools-settings-api-live{display:block;margin-block-start:.4rem;color:var(--_et-qdt-error);font-size:1.2rem}.et-query-devtools-btn--danger.et-query-devtools-btn--active{background:color-mix(in srgb,var(--_et-qdt-error) 28%,transparent);border-color:var(--_et-qdt-error);color:var(--_et-qdt-fg)}@media(prefers-reduced-motion:no-preference){.et-query-devtools-settings-api-live{animation:et-qdt-settings-api-live 1.6s ease-in-out infinite}}@keyframes et-qdt-settings-api-live{0%,to{opacity:.55}50%{opacity:1}}.et-query-devtools-settings-api-url{display:grid;grid-template-columns:auto minmax(0,32rem);align-items:center;margin-block-start:.5rem;gap:.2rem .6rem}.et-query-devtools-settings-api-url small{grid-column:1 / -1;max-inline-size:60rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(24rem,1fr));align-items:start;gap:.8rem 1.6rem}.et-query-devtools-settings-fields .et-query-devtools-field{display:grid;grid-template-columns:11rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-settings-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
1743
- }
1744
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsSettingsComponent, decorators: [{
1745
- type: Component,
1746
- args: [{ selector: 'et-query-devtools-settings', encapsulation: ViewEncapsulation.None, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-settings-toolbar\">\n <p class=\"et-query-devtools-hint\">\n Panel-wide, and kept in <code class=\"et-query-devtools-mono\">localStorage</code> whatever the scopes below say -\n so a scope of <em>none</em> does not erase the choice that set it. Every switch under <strong>Mirrored</strong> is\n the same one its own tab carries.\n </p>\n </div>\n\n @if (apiEnvs().length) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>API environment</strong>\n <span class=\"et-query-devtools-count\">the app's own key, not the panel's - picking reloads the page</span>\n </div>\n\n @for (apiSwitch of apiEnvs(); track apiSwitch.storageKey) {\n @let value = apiEnvValue(apiSwitch);\n @let custom = apiEnvCustomUrl(apiSwitch);\n @let fallback = apiEnvFallback(apiSwitch);\n @let production = apiEnvIsProduction(apiSwitch);\n <div [class.et-query-devtools-settings-api--production]=\"production\" class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ apiSwitch.name }}</span>\n <div class=\"et-query-devtools-btn-group\">\n <button\n [class.et-query-devtools-btn--active]=\"value === null\"\n [class.et-query-devtools-btn--danger]=\"fallback.production\"\n [attr.aria-pressed]=\"value === null\"\n (click)=\"pickApiEnv(apiSwitch, null)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ fallback.production ? '\u26A0 ' : '' }}{{ fallback.label }}\n </button>\n @for (env of apiSwitch.envs; track env.id) {\n <button\n [class.et-query-devtools-btn--active]=\"value === env.id\"\n [class.et-query-devtools-btn--danger]=\"env.production\"\n [attr.aria-pressed]=\"value === env.id\"\n [title]=\"env.url ?? env.id\"\n (click)=\"pickApiEnv(apiSwitch, env.id)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ env.production ? '\u26A0 ' : '' }}{{ env.label ?? env.id }}\n </button>\n }\n </div>\n </div>\n @if (production) {\n <strong class=\"et-query-devtools-settings-api-live\">\n Live data. Every request from this app reaches the real backend.\n </strong>\n }\n <small>\n Written to <span class=\"et-query-devtools-mono\">{{ apiSwitch.storageKey }}</span> in\n <code class=\"et-query-devtools-mono\">localStorage</code>, which the app reads before it boots.\n </small>\n @if (apiSwitch.custom) {\n <label class=\"et-query-devtools-field et-query-devtools-settings-api-url\">\n <span>Base URL</span>\n <input\n #customUrlInput\n [value]=\"custom\"\n (change)=\"setCustomApiUrl(apiSwitch, customUrlInput.value)\"\n class=\"et-query-devtools-input\"\n type=\"url\"\n placeholder=\"http://localhost:8040\"\n />\n <small>A backend none of the buttons above name. Empty goes back to the app's own default.</small>\n </label>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Storage</strong>\n <span class=\"et-query-devtools-count\">what survives a reload, and how long</span>\n </div>\n\n @for (row of SCOPE_ROWS; track row.key) {\n @let scope = scopeOf(row.key);\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ row.label }}</span>\n <div class=\"et-query-devtools-btn-group\">\n @for (option of SCOPES; track option.value) {\n @let unavailable = unavailableReason(row, option.value);\n <button\n [class.et-query-devtools-btn--active]=\"scope === option.value\"\n [attr.aria-pressed]=\"scope === option.value\"\n [disabled]=\"!!unavailable\"\n [title]=\"unavailable\"\n (click)=\"setScope(row.key, option.value)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ option.label }}\n </button>\n }\n <button [title]=\"INDEXED_DB_TITLE\" class=\"et-query-devtools-btn\" type=\"button\" disabled>IndexedDB</button>\n </div>\n </div>\n <small>{{ row.hint }}</small>\n @if (warningFor(row, scope); as warning) {\n <p class=\"et-query-devtools-settings-warn\">\n <span aria-hidden=\"true\">\u26A0</span>\n {{ warning }}\n </p>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Reset devtools</span>\n @if (resetConfirming()) {\n <div class=\"et-query-devtools-btn-group\">\n <button (click)=\"reset()\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Reset everything\n </button>\n <button (click)=\"resetConfirming.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <button (click)=\"resetConfirming.set(true)\" class=\"et-query-devtools-btn\" type=\"button\">Reset\u2026</button>\n }\n </div>\n <small>\n Clears every one of these keys from both stores, whatever the scopes above say, and puts the panel back where it\n ships - layout, filters, selections and pins. The settings on this tab stay.\n </small>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Limits</strong>\n <span class=\"et-query-devtools-count\">how much the panel keeps in memory</span>\n </div>\n\n <div class=\"et-query-devtools-settings-fields\">\n @for (row of LIMIT_ROWS; track row.key) {\n <label class=\"et-query-devtools-field\">\n <span>{{ row.label }}</span>\n <input\n #limitInput\n [value]=\"limitOf(row.key)\"\n [min]=\"row.min\"\n [max]=\"row.max\"\n [step]=\"row.step\"\n (change)=\"setLimit(row.key, limitInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n />\n <small>{{ row.hint }}</small>\n </label>\n }\n\n <label class=\"et-query-devtools-field\">\n <span>Response history</span>\n <input\n #responseHistoryInput\n [value]=\"responseHistory()\"\n (change)=\"setResponseHistory(responseHistoryInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"1\"\n max=\"50\"\n step=\"1\"\n />\n <small>\n bodies each query keeps, which is how far back a response diff can reach. Bodies dominate what the run buffer\n retains, so this is the one limit that costs real memory. Applies to runs from now on.\n @if (settings().responseHistory !== null) {\n <button (click)=\"clearResponseHistory()\" class=\"et-query-devtools-btn\" type=\"button\">\n Back to the app's own value\n </button>\n }\n </small>\n </label>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Mirrored</strong>\n <span class=\"et-query-devtools-count\">the same switches their tabs carry</span>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Queries</span>\n <div class=\"et-query-devtools-btn-group\">\n @let recentFirst = host.queryRecentFirst();\n <button\n [class.et-query-devtools-btn--active]=\"recentFirst\"\n [attr.aria-pressed]=\"recentFirst\"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n recent first\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n tree view\n </button>\n @let gone = showsGoneQueries();\n <button\n [class.et-query-devtools-btn--active]=\"gone\"\n [attr.aria-pressed]=\"gone\"\n (click)=\"toggleGoneQueries()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n list gone\n </button>\n </div>\n </div>\n <small>Sort order, whether the list groups by route path, and whether destroyed queries are listed at all.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Sessions</span>\n <div class=\"et-query-devtools-settings-controls\">\n <span class=\"et-query-devtools-count\">{{ sessionCount() }} stored</span>\n <button\n [disabled]=\"!sessionCount()\"\n (click)=\"FORGET_SESSIONS()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n >\n Forget every session\n </button>\n </div>\n </div>\n <small>\n Drops every stored token pair, every account added in the panel and every credential typed into one. The live\n session is left alone - the Auth tab switches between them.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Events</span>\n <div class=\"et-query-devtools-settings-controls\">\n @let errorsOnly = host.eventErrorsOnly();\n <button\n [class.et-query-devtools-btn--active]=\"errorsOnly\"\n [attr.aria-pressed]=\"errorsOnly\"\n (click)=\"host.eventErrorsOnly.set(!errorsOnly)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n failures only\n </button>\n @let pickedClient = host.eventClient();\n <select\n #eventClientSelect\n (change)=\"host.eventClient.set(eventClientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Event log client\"\n >\n <option [selected]=\"!pickedClient\" value=\"\">All clients</option>\n @for (name of eventClients(); track name) {\n <option [value]=\"name\" [selected]=\"name === pickedClient\">{{ name }}</option>\n }\n </select>\n </div>\n </div>\n <small>What the event log is narrowed to. The log itself always holds every client's traffic.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Response overrides</span>\n @let persist = host.overridesPersist();\n <button\n [class.et-query-devtools-btn--active]=\"persist\"\n [attr.aria-pressed]=\"persist\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Keep across reloads\n </button>\n </div>\n <small>\n The drawer's own toggle, which is the Storage scope above - currently\n <span class=\"et-query-devtools-mono\">{{ host.overridesScopeLabel() }}</span\n >.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Armed</span>\n <div class=\"et-query-devtools-settings-controls\">\n <button\n [disabled]=\"!mockCount() || armedMockCount() === mockCount()\"\n (click)=\"ARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Arm every mock ({{ mockCount() }})\n </button>\n <button\n [disabled]=\"!armedMockCount()\"\n (click)=\"DISARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm mocks ({{ armedMockCount() }})\n </button>\n <button\n [disabled]=\"!armedFaultCount()\"\n (click)=\"DISARM_ALL_FAULTS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm faults ({{ armedFaultCount() }})\n </button>\n </div>\n </div>\n <small>\n The Mocks and Faults tabs' own buttons. Whether either survives a reload is the two <em>Armed</em> scopes above,\n both <em>none</em> unless they were changed.\n </small>\n </div>\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-settings-toolbar{align-items:flex-start}.et-query-devtools-settings-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-settings-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-settings-row-head{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem}.et-query-devtools-settings-controls{display:flex;align-items:center;gap:.5rem}.et-query-devtools-settings-row>small{display:block;max-inline-size:60rem;margin-block-start:.3rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-warn{margin:.4rem 0 0;color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-settings-api--production{background:color-mix(in srgb,var(--_et-qdt-error) 8%,transparent);box-shadow:inset .3rem 0 0 var(--_et-qdt-error);padding-inline-start:.8rem}.et-query-devtools-settings-api-live{display:block;margin-block-start:.4rem;color:var(--_et-qdt-error);font-size:1.2rem}.et-query-devtools-btn--danger.et-query-devtools-btn--active{background:color-mix(in srgb,var(--_et-qdt-error) 28%,transparent);border-color:var(--_et-qdt-error);color:var(--_et-qdt-fg)}@media(prefers-reduced-motion:no-preference){.et-query-devtools-settings-api-live{animation:et-qdt-settings-api-live 1.6s ease-in-out infinite}}@keyframes et-qdt-settings-api-live{0%,to{opacity:.55}50%{opacity:1}}.et-query-devtools-settings-api-url{display:grid;grid-template-columns:auto minmax(0,32rem);align-items:center;margin-block-start:.5rem;gap:.2rem .6rem}.et-query-devtools-settings-api-url small{grid-column:1 / -1;max-inline-size:60rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(24rem,1fr));align-items:start;gap:.8rem 1.6rem}.et-query-devtools-settings-fields .et-query-devtools-field{display:grid;grid-template-columns:11rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-settings-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}}\n"] }]
1747
- }] });
1748
-
1749
- /**
1750
- * The waterfall's grid, axis and bars, as a styles-only component the panel mounts when the Timeline tab
1751
- * is first opened.
1752
- *
1753
- * @internal
1754
- */
1755
- class QueryDevtoolsTimelineStylesComponent {
1756
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsTimelineStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1757
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: QueryDevtoolsTimelineStylesComponent, isStandalone: true, selector: "et-query-devtools-timeline-styles", ngImport: i0, template: '', isInline: true, styles: ["@layer components{.et-query-devtools-timeline{display:grid;grid-template-columns:minmax(10rem,26rem) minmax(14rem,1fr) max-content max-content max-content;gap:.1rem .8rem;padding-inline:.4rem 1rem}.et-query-devtools-timeline-axis,.et-query-devtools-timeline-row{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;align-items:center}.et-query-devtools-timeline-axis{position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border);padding-block-end:.4rem;margin-block-end:.4rem}.et-query-devtools-timeline-ticks{grid-column:2;position:relative;block-size:1.5rem}.et-query-devtools-timeline-tick{position:absolute;inset-block-start:0;transform:translate(-50%);color:var(--_et-qdt-subtle);font-size:1.1rem;white-space:nowrap}.et-query-devtools-timeline-tick:first-child{transform:none}.et-query-devtools-timeline-tick:last-child{transform:translate(-100%)}.et-query-devtools-timeline-row{appearance:none;border:0;background:transparent;color:inherit;font:inherit;text-align:start;padding:.15rem 0;cursor:pointer}@media(hover:hover){.et-query-devtools-timeline-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-timeline-row--active{background:var(--_et-qdt-active)}.et-query-devtools-timeline-label{display:flex;align-items:baseline;gap:.4rem;min-inline-size:0;overflow:hidden}.et-query-devtools-timeline-label .et-query-devtools-url{max-inline-size:none;margin-inline-start:0}.et-query-devtools-timeline-track{position:relative;block-size:1.8rem;border-radius:var(--_et-qdt-radius-sm);overflow:hidden;background-color:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);background-image:repeating-linear-gradient(to right,var(--_et-qdt-border) 0 1px,transparent 1px 25%)}.et-query-devtools-timeline-bar{position:absolute;inset-block:.4rem;min-inline-size:.2rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-subtle)}.et-query-devtools-timeline-bar[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-timeline-bar[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-timeline-bar[data-status=loading]{background:var(--_et-qdt-loading)}.et-query-devtools-timeline-bar[data-status=aborted]{min-inline-size:.5rem;background:color-mix(in srgb,var(--_et-qdt-subtle) 20%,transparent);outline:1px solid color-mix(in srgb,var(--_et-qdt-subtle) 70%,transparent);outline-offset:-1px}.et-query-devtools-timeline-duration,.et-query-devtools-timeline-size{text-align:end;color:var(--_et-qdt-muted);font-size:1.1rem;font-variant-numeric:tabular-nums;white-space:nowrap}.et-query-devtools-timeline-duration{color:var(--_et-qdt-fg)}.et-query-devtools-timeline-flags{display:flex;align-items:center;gap:.3rem;white-space:nowrap}.et-query-devtools-timeline-flags .et-query-devtools-chip{padding:0 .4rem;border-color:transparent;border-radius:var(--_et-qdt-radius-sm);background:color-mix(in srgb,currentcolor 12%,transparent);font-size:1rem;line-height:1.5;font-variant-numeric:tabular-nums}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
1758
- }
1759
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsTimelineStylesComponent, decorators: [{
1760
- type: Component,
1761
- args: [{ selector: 'et-query-devtools-timeline-styles', template: '', encapsulation: ViewEncapsulation.None, styles: ["@layer components{.et-query-devtools-timeline{display:grid;grid-template-columns:minmax(10rem,26rem) minmax(14rem,1fr) max-content max-content max-content;gap:.1rem .8rem;padding-inline:.4rem 1rem}.et-query-devtools-timeline-axis,.et-query-devtools-timeline-row{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;align-items:center}.et-query-devtools-timeline-axis{position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border);padding-block-end:.4rem;margin-block-end:.4rem}.et-query-devtools-timeline-ticks{grid-column:2;position:relative;block-size:1.5rem}.et-query-devtools-timeline-tick{position:absolute;inset-block-start:0;transform:translate(-50%);color:var(--_et-qdt-subtle);font-size:1.1rem;white-space:nowrap}.et-query-devtools-timeline-tick:first-child{transform:none}.et-query-devtools-timeline-tick:last-child{transform:translate(-100%)}.et-query-devtools-timeline-row{appearance:none;border:0;background:transparent;color:inherit;font:inherit;text-align:start;padding:.15rem 0;cursor:pointer}@media(hover:hover){.et-query-devtools-timeline-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-timeline-row--active{background:var(--_et-qdt-active)}.et-query-devtools-timeline-label{display:flex;align-items:baseline;gap:.4rem;min-inline-size:0;overflow:hidden}.et-query-devtools-timeline-label .et-query-devtools-url{max-inline-size:none;margin-inline-start:0}.et-query-devtools-timeline-track{position:relative;block-size:1.8rem;border-radius:var(--_et-qdt-radius-sm);overflow:hidden;background-color:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);background-image:repeating-linear-gradient(to right,var(--_et-qdt-border) 0 1px,transparent 1px 25%)}.et-query-devtools-timeline-bar{position:absolute;inset-block:.4rem;min-inline-size:.2rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-subtle)}.et-query-devtools-timeline-bar[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-timeline-bar[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-timeline-bar[data-status=loading]{background:var(--_et-qdt-loading)}.et-query-devtools-timeline-bar[data-status=aborted]{min-inline-size:.5rem;background:color-mix(in srgb,var(--_et-qdt-subtle) 20%,transparent);outline:1px solid color-mix(in srgb,var(--_et-qdt-subtle) 70%,transparent);outline-offset:-1px}.et-query-devtools-timeline-duration,.et-query-devtools-timeline-size{text-align:end;color:var(--_et-qdt-muted);font-size:1.1rem;font-variant-numeric:tabular-nums;white-space:nowrap}.et-query-devtools-timeline-duration{color:var(--_et-qdt-fg)}.et-query-devtools-timeline-flags{display:flex;align-items:center;gap:.3rem;white-space:nowrap}.et-query-devtools-timeline-flags .et-query-devtools-chip{padding:0 .4rem;border-color:transparent;border-radius:var(--_et-qdt-radius-sm);background:color-mix(in srgb,currentcolor 12%,transparent);font-size:1rem;line-height:1.5;font-variant-numeric:tabular-nums}}\n"] }]
1762
- }] });
1763
-
1764
- /** A feature list: the feature's name, followed by the options it was configured with. */
1765
- class QueryDevtoolsFeaturesComponent {
1766
- constructor() {
1767
- this.features = input.required(/* @ts-ignore */
1768
- ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
1769
- }
1770
- featureLabel(type) {
1771
- return type
1772
- .replace(/^WITH_/, '')
1773
- .replace(/_/g, ' ')
1774
- .toLowerCase();
1775
- }
1776
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsFeaturesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1777
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsFeaturesComponent, isStandalone: true, selector: "et-query-devtools-features", inputs: { features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
1778
- <ul class="et-query-devtools-features">
1779
- @for (feature of features(); track feature.type) {
1780
- <li class="et-query-devtools-feature">
1781
- <span class="et-query-devtools-chip">{{ featureLabel(feature.type) }}</span>
1782
- <!-- Always rendered: the list is one grid, so a feature without options still needs its cell
1783
- for the next row's chip to stay in the same column. -->
1784
- <span class="et-query-devtools-feature-details">
1785
- @for (detail of feature.details; track detail.label) {
1786
- <span class="et-query-devtools-feature-detail">
1787
- <span class="et-query-devtools-feature-label">{{ detail.label }}</span>
1788
- <span class="et-query-devtools-feature-value">{{ detail.value }}</span>
1789
- </span>
1790
- }
1791
- </span>
1792
- </li>
1793
- }
1794
- </ul>
1795
- `, isInline: true, styles: ["@layer components{.et-query-devtools-features{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:.4rem .8rem;margin:0 0 .8rem;padding:0;list-style:none}.et-query-devtools-meta .et-query-devtools-features{margin-block-end:0}.et-query-devtools-feature{display:contents}.et-query-devtools-feature>.et-query-devtools-chip{justify-self:start}.et-query-devtools-feature-details{display:flex;flex-wrap:wrap;gap:.3rem}.et-query-devtools-feature-detail{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent);font-size:1.1rem}.et-query-devtools-feature-label{color:var(--_et-qdt-muted)}.et-query-devtools-feature-value{color:var(--_et-qdt-fg);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
1796
- }
1797
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsFeaturesComponent, decorators: [{
1798
- type: Component,
1799
- args: [{ selector: 'et-query-devtools-features', template: `
1800
- <ul class="et-query-devtools-features">
1801
- @for (feature of features(); track feature.type) {
1802
- <li class="et-query-devtools-feature">
1803
- <span class="et-query-devtools-chip">{{ featureLabel(feature.type) }}</span>
1804
- <!-- Always rendered: the list is one grid, so a feature without options still needs its cell
1805
- for the next row's chip to stay in the same column. -->
1806
- <span class="et-query-devtools-feature-details">
1807
- @for (detail of feature.details; track detail.label) {
1808
- <span class="et-query-devtools-feature-detail">
1809
- <span class="et-query-devtools-feature-label">{{ detail.label }}</span>
1810
- <span class="et-query-devtools-feature-value">{{ detail.value }}</span>
1811
- </span>
1812
- }
1813
- </span>
1814
- </li>
1815
- }
1816
- </ul>
1817
- `, encapsulation: ViewEncapsulation.None, styles: ["@layer components{.et-query-devtools-features{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:.4rem .8rem;margin:0 0 .8rem;padding:0;list-style:none}.et-query-devtools-meta .et-query-devtools-features{margin-block-end:0}.et-query-devtools-feature{display:contents}.et-query-devtools-feature>.et-query-devtools-chip{justify-self:start}.et-query-devtools-feature-details{display:flex;flex-wrap:wrap;gap:.3rem}.et-query-devtools-feature-detail{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent);font-size:1.1rem}.et-query-devtools-feature-label{color:var(--_et-qdt-muted)}.et-query-devtools-feature-value{color:var(--_et-qdt-fg);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}}\n"] }]
1818
- }], propDecorators: { features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: true }] }] } });
1819
-
1820
- /** `username, password` as typed in the add row, into the fields the login args are built from. */
1821
- const parseAuthFields = (value) => [...new Set(value.split(/[\s,]+/).filter(Boolean))].map((name) => ({
1822
- name,
1823
- type: /pass|secret|token/i.test(name) ? 'password' : 'text',
1824
- }));
1825
- /** The Auth tab: registered bearer auth providers, their tokens, their sessions and their queries. */
1826
- class QueryDevtoolsAuthTabComponent {
1827
- constructor() {
1828
- this.host = injectQueryDevtoolsHost();
1829
- this.TTL_LIMIT = QUERY_DEVTOOLS_TOKEN_TTL_LIMIT;
1830
- /** Which accounts show their credential fields. Nothing is expanded until somebody asks for it. */
1831
- this.expandedAccounts = signal(new Set(), /* @ts-ignore */
1832
- ...(ngDevMode ? [{ debugName: "expandedAccounts" }] : /* istanbul ignore next */ []));
1833
- /** Which providers show the form that adds an account of your own. */
1834
- this.addingFor = signal(new Set(), /* @ts-ignore */
1835
- ...(ngDevMode ? [{ debugName: "addingFor" }] : /* istanbul ignore next */ []));
1836
- /** Nothing of a real user is ever kept on this machine, so the whole vault stands down. */
1837
- this.production = computed(queryDevtoolsApiEnvIsProduction, /* @ts-ignore */
1838
- ...(ngDevMode ? [{ debugName: "production" }] : /* istanbul ignore next */ []));
1839
- this.reloadOnSwitch = computed(() => queryDevtoolsSettings().reloadOnAuthSwitch, /* @ts-ignore */
1840
- ...(ngDevMode ? [{ debugName: "reloadOnSwitch" }] : /* istanbul ignore next */ []));
1841
- }
1842
- sessionsFor(entry) {
1843
- return queryDevtoolsAuthSessionsFor(this.providerName(entry));
1844
- }
1845
- accountsFor(entry) {
1846
- return queryDevtoolsAuthAccountsFor(this.providerName(entry));
1583
+ accountsFor(entry) {
1584
+ return queryDevtoolsAuthAccountsFor(this.providerName(entry));
1847
1585
  }
1848
1586
  /** How many sessions this provider holds for a backend the app is not pointed at now. */
1849
1587
  otherScopeCount(entry) {
@@ -2101,7 +1839,6 @@ const buildCurlCommand = (request) => {
2101
1839
  */
2102
1840
  class QueryDevtoolsOverrideSetMenuComponent {
2103
1841
  constructor() {
2104
- this.errorColorTheme = injectErrorTheme();
2105
1842
  this.hostEl = inject(ElementRef);
2106
1843
  this.overrides = input.required(/* @ts-ignore */
2107
1844
  ...(ngDevMode ? [{ debugName: "overrides" }] : /* istanbul ignore next */ []));
@@ -2192,7 +1929,7 @@ class QueryDevtoolsOverrideSetMenuComponent {
2192
1929
  this.note.set(`${parts.join('; ')}.`);
2193
1930
  }
2194
1931
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsOverrideSetMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2195
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsOverrideSetMenuComponent, isStandalone: true, selector: "et-query-devtools-override-set-menu", inputs: { overrides: { classPropertyName: "overrides", publicName: "overrides", isSignal: true, isRequired: true, transformFunction: null }, response: { classPropertyName: "response", publicName: "response", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "pasteInput", first: true, predicate: ["pasteBox"], descendants: true, isSignal: true }], ngImport: i0, template: "<div (openChange)=\"resetOnClose($event)\" class=\"et-query-devtools-override-set-menu\" etMenu>\n <button\n et-menu-item\n title=\"Copy every response override armed on this query, or paste a set copied off another one.\"\n type=\"button\"\n etMenuTrigger\n >\n Override set\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"error()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste a copied set here\"\n />\n }\n </ng-container>\n\n @if (armedCount()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"copySet()\" et-menu-item type=\"button\">\n {{ copied() ? '\u2713 Copied' : 'Copy ' + armedCount() + (armedCount() === 1 ? ' armed op' : ' armed ops') }}\n </button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteSet()\" et-menu-item type=\"button\">\n Paste a set{{ armedCount() ? ' on top' : '' }}\n </button>\n\n @if (error(); as err) {\n <p [etProvideColor]=\"errorColorTheme\" class=\"et-query-devtools-override-error\" role=\"alert\">{{ err }}</p>\n } @else if (note(); as text) {\n <p class=\"et-query-devtools-override-note\" role=\"status\">{{ text }}</p>\n }\n </et-menu>\n </ng-template>\n</div>\n", dependencies: [{ kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuSearchDirective, selector: "input[etMenuSearch]", inputs: ["query", "loading", "error"], outputs: ["queryChange"], exportAs: ["etMenuSearch"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "directive", type: ProvideColorDirective, selector: "[etProvideColor]", inputs: ["etProvideColor"] }], encapsulation: i0.ViewEncapsulation.None }); }
1932
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsOverrideSetMenuComponent, isStandalone: true, selector: "et-query-devtools-override-set-menu", inputs: { overrides: { classPropertyName: "overrides", publicName: "overrides", isSignal: true, isRequired: true, transformFunction: null }, response: { classPropertyName: "response", publicName: "response", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "pasteInput", first: true, predicate: ["pasteBox"], descendants: true, isSignal: true }], ngImport: i0, template: "<div (openChange)=\"resetOnClose($event)\" class=\"et-query-devtools-override-set-menu\" etMenu>\n <button\n et-menu-item\n title=\"Copy every response override armed on this query, or paste a set copied off another one.\"\n type=\"button\"\n etMenuTrigger\n >\n Override set\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"error()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste a copied set here\"\n />\n }\n </ng-container>\n\n @if (armedCount()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"copySet()\" et-menu-item type=\"button\">\n {{ copied() ? '\u2713 Copied' : 'Copy ' + armedCount() + (armedCount() === 1 ? ' armed op' : ' armed ops') }}\n </button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteSet()\" et-menu-item type=\"button\">\n Paste a set{{ armedCount() ? ' on top' : '' }}\n </button>\n\n @if (error(); as err) {\n <p\n #errorTheme=\"etQueryDevtoolsErrorTheme\"\n [etProvideColor]=\"errorTheme.theme()\"\n class=\"et-query-devtools-override-error\"\n role=\"alert\"\n etQueryDevtoolsErrorTheme\n >\n {{ err }}\n </p>\n } @else if (note(); as text) {\n <p class=\"et-query-devtools-override-note\" role=\"status\">{{ text }}</p>\n }\n </et-menu>\n </ng-template>\n</div>\n", dependencies: [{ kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuSearchDirective, selector: "input[etMenuSearch]", inputs: ["query", "loading", "error"], outputs: ["queryChange"], exportAs: ["etMenuSearch"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "directive", type: ProvideColorDirective, selector: "[etProvideColor]", inputs: ["etProvideColor"] }, { kind: "directive", type: QueryDevtoolsErrorThemeDirective, selector: "[etQueryDevtoolsErrorTheme]", exportAs: ["etQueryDevtoolsErrorTheme"] }], encapsulation: i0.ViewEncapsulation.None }); }
2196
1933
  }
2197
1934
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsOverrideSetMenuComponent, decorators: [{
2198
1935
  type: Component,
@@ -2205,7 +1942,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
2205
1942
  MenuItemComponent,
2206
1943
  MenuItemShortcutComponent,
2207
1944
  ProvideColorDirective,
2208
- ], template: "<div (openChange)=\"resetOnClose($event)\" class=\"et-query-devtools-override-set-menu\" etMenu>\n <button\n et-menu-item\n title=\"Copy every response override armed on this query, or paste a set copied off another one.\"\n type=\"button\"\n etMenuTrigger\n >\n Override set\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"error()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste a copied set here\"\n />\n }\n </ng-container>\n\n @if (armedCount()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"copySet()\" et-menu-item type=\"button\">\n {{ copied() ? '\u2713 Copied' : 'Copy ' + armedCount() + (armedCount() === 1 ? ' armed op' : ' armed ops') }}\n </button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteSet()\" et-menu-item type=\"button\">\n Paste a set{{ armedCount() ? ' on top' : '' }}\n </button>\n\n @if (error(); as err) {\n <p [etProvideColor]=\"errorColorTheme\" class=\"et-query-devtools-override-error\" role=\"alert\">{{ err }}</p>\n } @else if (note(); as text) {\n <p class=\"et-query-devtools-override-note\" role=\"status\">{{ text }}</p>\n }\n </et-menu>\n </ng-template>\n</div>\n" }]
1945
+ QueryDevtoolsErrorThemeDirective,
1946
+ ], template: "<div (openChange)=\"resetOnClose($event)\" class=\"et-query-devtools-override-set-menu\" etMenu>\n <button\n et-menu-item\n title=\"Copy every response override armed on this query, or paste a set copied off another one.\"\n type=\"button\"\n etMenuTrigger\n >\n Override set\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <ng-container ngProjectAs=\"input[etMenuSearch]\">\n @if (pasteMode()) {\n <input\n #pasteBox\n [error]=\"error()\"\n (paste)=\"pasteIntoBox($event)\"\n (keydown.enter)=\"commitPasteBox()\"\n etMenuSearch\n type=\"text\"\n placeholder=\"Paste a copied set here\"\n />\n }\n </ng-container>\n\n @if (armedCount()) {\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"copySet()\" et-menu-item type=\"button\">\n {{ copied() ? '\u2713 Copied' : 'Copy ' + armedCount() + (armedCount() === 1 ? ' armed op' : ' armed ops') }}\n </button>\n }\n\n <!-- eslint-disable-next-line ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <button [closeOnActivate]=\"false\" (activate)=\"pasteSet()\" et-menu-item type=\"button\">\n Paste a set{{ armedCount() ? ' on top' : '' }}\n </button>\n\n @if (error(); as err) {\n <p\n #errorTheme=\"etQueryDevtoolsErrorTheme\"\n [etProvideColor]=\"errorTheme.theme()\"\n class=\"et-query-devtools-override-error\"\n role=\"alert\"\n etQueryDevtoolsErrorTheme\n >\n {{ err }}\n </p>\n } @else if (note(); as text) {\n <p class=\"et-query-devtools-override-note\" role=\"status\">{{ text }}</p>\n }\n </et-menu>\n </ng-template>\n</div>\n" }]
2209
1947
  }], ctorParameters: () => [], propDecorators: { overrides: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrides", required: true }] }], response: [{ type: i0.Input, args: [{ isSignal: true, alias: "response", required: false }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], pasteInput: [{ type: i0.ViewChild, args: ['pasteBox', { isSignal: true }] }] } });
2210
1948
 
2211
1949
  /**
@@ -2470,6 +2208,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
2470
2208
  args: [{ selector: 'et-query-devtools-events-tab', encapsulation: ViewEncapsulation.None, imports: [QueryDevtoolsDrawerComponent], template: "<div #panes class=\"et-query-devtools-split\">\n <div class=\"et-query-devtools-pane\">\n <div class=\"et-query-devtools-toolbar\">\n <div class=\"et-query-devtools-toolbar-row\">\n @if (eventClients().length > 1) {\n <label class=\"et-query-devtools-field\">\n <span>Client</span>\n @let pickedClient = host.eventClient();\n <select\n #eventClientSelect\n (change)=\"host.eventClient.set(eventClientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n >\n <option [selected]=\"!pickedClient\" value=\"\">All clients</option>\n @for (name of eventClients(); track name) {\n <option [value]=\"name\" [selected]=\"name === pickedClient\">{{ name }}</option>\n }\n </select>\n </label>\n }\n @let errorsOnly = host.eventErrorsOnly();\n <button\n [class.et-query-devtools-facet--active]=\"errorsOnly\"\n [attr.aria-pressed]=\"errorsOnly\"\n (click)=\"toggleEventErrorsOnly()\"\n class=\"et-query-devtools-chip et-query-devtools-facet\"\n type=\"button\"\n title=\"Show only the requests that failed\"\n >\n Errors only\n <span class=\"et-query-devtools-facet-count\">{{ host.tabBadges().events.errors }}</span>\n </button>\n <span class=\"et-query-devtools-count\">\n @if (isEventLogNarrowed()) {\n {{ filteredEvents().length }} of {{ host.eventLog().length }} events\n } @else {\n {{ host.eventLog().length }} events\n }\n </span>\n @if (isEventLogNarrowed()) {\n <button\n (click)=\"clearEventFilters()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the client scope and the errors-only toggle\"\n aria-label=\"Clear filters\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n }\n <button (click)=\"clearEvents()\" class=\"et-query-devtools-btn et-query-devtools-toolbar-btn\" type=\"button\">\n Clear\n </button>\n </div>\n </div>\n <div class=\"et-query-devtools-scroll\">\n <table class=\"et-query-devtools-table\">\n <thead>\n <tr>\n <th>Time</th>\n <th class=\"et-query-devtools-cell-origin\">Base URL</th>\n <th>Type</th>\n <th>Request</th>\n <th>Duration</th>\n <th>Size</th>\n </tr>\n </thead>\n <tbody>\n @for (event of filteredEvents(); track event.id) {\n @let eventQueryId = host.eventQueryId(event);\n <tr\n [attr.data-status]=\"eventRowStatus(event)\"\n [class.et-query-devtools-row--active]=\"!!eventQueryId && host.eventSelectedQueryId() === eventQueryId\"\n >\n <td>{{ host.formatTime(event.timestamp) }}</td>\n <td [title]=\"event.client\" class=\"et-query-devtools-mono et-query-devtools-cell-origin\">\n {{ event.client }}\n </td>\n <td>\n {{ eventTypeLabel(event) }}\n @if (event.isSecure) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">secure</span>\n }\n </td>\n @if (event.cause; as cause) {\n <td>\n <span class=\"et-query-devtools-url\">{{ host.causeLabel(cause) }}</span>\n @if (event.refreshed?.length) {\n <div class=\"et-query-devtools-chips\">\n @for (refreshed of event.refreshed; track $index) {\n @if (\n canOpenEventRow(refreshed.queryIds[0] ?? null) ? refreshed.queryIds[0] : null;\n as queryId\n ) {\n <button\n (click)=\"host.eventSelectedQueryId.set(queryId)\"\n class=\"et-query-devtools-chip et-query-devtools-chip--button\"\n type=\"button\"\n title=\"Open {{ refreshed.method }} {{ refreshed.path }}\"\n >\n {{ refreshed.method }} {{ refreshed.path }}\n @if (refreshed.queryIds.length > 1) {\n <small>\u00D7{{ refreshed.queryIds.length }}</small>\n }\n </button>\n } @else {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"No registered query holds this cache entry any more\"\n >\n {{ refreshed.method }} {{ refreshed.path }}\n </span>\n }\n }\n </div>\n } @else {\n <span class=\"et-query-devtools-hint\">matched no query in use</span>\n }\n </td>\n } @else if (event.url; as url) {\n <td>\n @if (canOpenEventRow(eventQueryId)) {\n <button\n (click)=\"host.eventSelectedQueryId.set(eventQueryId)\"\n class=\"et-query-devtools-row-link\"\n type=\"button\"\n title=\"Open {{ event.method }} {{ url }}\"\n >\n <span class=\"et-query-devtools-method\">{{ event.method }}</span>\n <span class=\"et-query-devtools-url\">{{ host.requestPath(url) }}</span>\n </button>\n } @else {\n <span [title]=\"event.method + ' ' + url\">\n <span class=\"et-query-devtools-method\">{{ event.method }}</span>\n <span class=\"et-query-devtools-url\">{{ host.requestPath(url) }}</span>\n </span>\n }\n </td>\n } @else {\n <td class=\"et-query-devtools-url\">all secure entries dropped</td>\n }\n <td>{{ host.formatDuration(event.durationMs) }}</td>\n <td>{{ event.bytes === null ? '\u2014' : host.formatTransferred(event.bytes, event.isEstimatedBytes) }}</td>\n </tr>\n } @empty {\n <tr>\n @if (host.eventLog().length) {\n <td class=\"et-query-devtools-empty\" colspan=\"6\">\n No event matches the filter \u00B7 {{ host.eventLog().length }} in the log.\n </td>\n } @else {\n <td class=\"et-query-devtools-empty\" colspan=\"6\">No events captured yet.</td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n\n <et-query-devtools-drawer\n [sel]=\"host.eventSelectedQuery()\"\n [container]=\"panes\"\n (dismiss)=\"host.eventSelectedQueryId.set(null)\"\n />\n</div>\n" }]
2471
2209
  }] });
2472
2210
 
2211
+ const groupsOf = () => {
2212
+ const about = queryDevtoolsAbout();
2213
+ const groups = [
2214
+ {
2215
+ title: 'Ethlete',
2216
+ rows: Object.entries(about.ethlete).map(([name, version]) => ({ label: `@ethlete/${name}`, value: version })),
2217
+ },
2218
+ { title: 'Runtime', rows: [{ label: 'Angular', value: about.angular }] },
2219
+ ];
2220
+ if (about.app) {
2221
+ groups.push({
2222
+ title: 'Application',
2223
+ rows: Object.entries(about.app).map(([label, value]) => ({ label, value: String(value) })),
2224
+ });
2225
+ }
2226
+ return groups;
2227
+ };
2228
+ /**
2229
+ * What is running: the loaded `@ethlete/*` versions, the Angular version and whatever the app handed to
2230
+ * `provideQueryDevtools({ about })`. A section rather than a tab body, so it can be shown anywhere.
2231
+ */
2232
+ class QueryDevtoolsAboutComponent {
2233
+ constructor() {
2234
+ this.hostEl = inject(ElementRef);
2235
+ this.groups = groupsOf();
2236
+ this.copied = createQueryDevtoolsCopiedTick(false);
2237
+ }
2238
+ copy() {
2239
+ const text = this.groups
2240
+ .map((group) => [group.title, ...group.rows.map((row) => ` ${row.label}: ${row.value}`)].join('\n'))
2241
+ .join('\n\n');
2242
+ writeQueryDevtoolsClipboard({ text }, this.hostEl.nativeElement.ownerDocument).then((result) => this.copied.mark(result.ok));
2243
+ }
2244
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsAboutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2245
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsAboutComponent, isStandalone: true, selector: "et-query-devtools-about", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-about-toolbar\">\n <p class=\"et-query-devtools-hint\">\n What is running, and what a bug report should carry. Also in the <strong>\u2913 Session</strong> export and on\n <code class=\"et-query-devtools-mono\">window.ethlete</code>.\n </p>\n <button (click)=\"copy()\" class=\"et-query-devtools-btn\" type=\"button\">\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copied.value() ? 'Copied' : 'Copy' }}\n </button>\n </div>\n\n @for (group of groups; track group.title) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>{{ group.title }}</strong>\n </div>\n <dl class=\"et-query-devtools-about-list\">\n @for (row of group.rows; track row.label) {\n <div class=\"et-query-devtools-about-row\">\n <dt class=\"et-query-devtools-mono\">{{ row.label }}</dt>\n <dd class=\"et-query-devtools-mono\">{{ row.value }}</dd>\n </div>\n }\n </dl>\n </div>\n }\n</div>\n", styles: ["@layer components{.et-query-devtools-about-toolbar{align-items:flex-start}.et-query-devtools-about-list{display:flex;flex-direction:column;gap:.2rem;margin:0;padding:.6rem .8rem}.et-query-devtools-about-row{display:flex;align-items:baseline;gap:.8rem}.et-query-devtools-about-row dt{flex:0 0 auto;color:var(--_et-qdt-muted)}.et-query-devtools-about-row dd{flex:1 1 auto;margin:0;border-block-end:1px dotted color-mix(in srgb,var(--_et-qdt-interaction) 25%,transparent);text-align:end}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
2246
+ }
2247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsAboutComponent, decorators: [{
2248
+ type: Component,
2249
+ args: [{ selector: 'et-query-devtools-about', encapsulation: ViewEncapsulation.None, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-about-toolbar\">\n <p class=\"et-query-devtools-hint\">\n What is running, and what a bug report should carry. Also in the <strong>\u2913 Session</strong> export and on\n <code class=\"et-query-devtools-mono\">window.ethlete</code>.\n </p>\n <button (click)=\"copy()\" class=\"et-query-devtools-btn\" type=\"button\">\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copied.value() ? 'Copied' : 'Copy' }}\n </button>\n </div>\n\n @for (group of groups; track group.title) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>{{ group.title }}</strong>\n </div>\n <dl class=\"et-query-devtools-about-list\">\n @for (row of group.rows; track row.label) {\n <div class=\"et-query-devtools-about-row\">\n <dt class=\"et-query-devtools-mono\">{{ row.label }}</dt>\n <dd class=\"et-query-devtools-mono\">{{ row.value }}</dd>\n </div>\n }\n </dl>\n </div>\n }\n</div>\n", styles: ["@layer components{.et-query-devtools-about-toolbar{align-items:flex-start}.et-query-devtools-about-list{display:flex;flex-direction:column;gap:.2rem;margin:0;padding:.6rem .8rem}.et-query-devtools-about-row{display:flex;align-items:baseline;gap:.8rem}.et-query-devtools-about-row dt{flex:0 0 auto;color:var(--_et-qdt-muted)}.et-query-devtools-about-row dd{flex:1 1 auto;margin:0;border-block-end:1px dotted color-mix(in srgb,var(--_et-qdt-interaction) 25%,transparent);text-align:end}}\n"] }]
2250
+ }] });
2251
+
2473
2252
  /**
2474
2253
  * The body editor of a designed mock: the value explorer's per-node override menu - presets,
2475
2254
  * fill-recursively, duplicate, pagination resize, paste, delete - pointed at a draft instead of at a live
@@ -3416,172 +3195,400 @@ class QueryDevtoolsMocksTabComponent {
3416
3195
  capturedAt: Date.now(),
3417
3196
  });
3418
3197
  }
3419
- pickSpecFormat(value) {
3420
- const format = SPEC_FORMATS.find((entry) => entry.value === value);
3421
- if (format)
3422
- this.specFormat.set(format.value);
3198
+ pickSpecFormat(value) {
3199
+ const format = SPEC_FORMATS.find((entry) => entry.value === value);
3200
+ if (format)
3201
+ this.specFormat.set(format.value);
3202
+ }
3203
+ toggleArmed(row) {
3204
+ armQueryDevtoolsMock(row.mock.id, !row.armed);
3205
+ }
3206
+ remove(row) {
3207
+ deleteQueryDevtoolsMock(row.mock.id);
3208
+ }
3209
+ setStatus(row, value) {
3210
+ saveQueryDevtoolsMock({ ...row.mock, status: this.countOf(value, row.mock.status) });
3211
+ }
3212
+ setLatency(row, value) {
3213
+ saveQueryDevtoolsMock({ ...row.mock, latencyMs: this.countOf(value, row.mock.latencyMs) });
3214
+ }
3215
+ /**
3216
+ * Copies the route as a `@ethlete/query` definition - the response type inferred from the designed body,
3217
+ * the args contract and the creator call - so a mocked route can be pasted into the app it was designed
3218
+ * for.
3219
+ */
3220
+ copyDefinition(row) {
3221
+ const snippet = buildQueryDefinitionSnippet({
3222
+ method: row.mock.method,
3223
+ pattern: row.mock.pattern,
3224
+ query: row.mock.query,
3225
+ body: row.mock.body,
3226
+ });
3227
+ this.copyText(snippet, () => this.copiedDefinition.mark(row.mock.id));
3228
+ }
3229
+ /**
3230
+ * Copies one route as an OpenAPI `paths` entry, ready to be pasted under an existing description's
3231
+ * `paths`. A route seeded from a named schema keeps its `$ref`, since it is merged back into the
3232
+ * document that declares it.
3233
+ */
3234
+ copyPathItem(row) {
3235
+ const schemas = this.schemasFor([row.mock]);
3236
+ const built = buildQueryDevtoolsOpenApiPathItem({ mocks: [row.mock], schemas: schemas.schemas });
3237
+ this.specNotes.set([...schemas.notes, ...built.notes]);
3238
+ this.copyText(this.write(built.document), () => this.copiedPathItem.mark(row.mock.id));
3239
+ }
3240
+ /**
3241
+ * Downloads the whole library as one OpenAPI 3.1 document - the deliverable the API team merges. Every
3242
+ * designed mock is in it, armed or not: the library is the design work, and arming is only what this
3243
+ * page load happens to be serving.
3244
+ */
3245
+ exportLibrary() {
3246
+ const mocks = this.rows().map((row) => row.mock);
3247
+ if (!mocks.length)
3248
+ return;
3249
+ const schemas = this.schemasFor(mocks);
3250
+ const built = buildQueryDevtoolsOpenApiDocument({ mocks, schemas: schemas.schemas, now: Date.now() });
3251
+ const format = this.specFormat();
3252
+ this.specNotes.set([...schemas.notes, ...built.notes]);
3253
+ this.host.downloadTextFile({
3254
+ name: `openapi-designed-mocks-${new Date().toISOString().slice(0, 10)}.${format}`,
3255
+ content: this.write(built.document),
3256
+ type: SPEC_MEDIA_TYPES[format],
3257
+ });
3258
+ }
3259
+ editBody(row) {
3260
+ this.editingId.set(row.mock.id);
3261
+ }
3262
+ cancelBody() {
3263
+ this.editingId.set(null);
3264
+ }
3265
+ saveBody(row, body) {
3266
+ saveQueryDevtoolsMock({ ...row.mock, body });
3267
+ this.cancelBody();
3268
+ }
3269
+ /**
3270
+ * The declared schemas the given mocks were seeded from, so their responses can reference them. Each
3271
+ * client is asked its own description, and a name two of them both declare keeps the first - one
3272
+ * exported document cannot hold two `MatchView`s.
3273
+ */
3274
+ schemasFor(mocks) {
3275
+ const byClient = new Map();
3276
+ for (const mock of mocks) {
3277
+ if (!mock.schemaName)
3278
+ continue;
3279
+ const names = byClient.get(mock.clientName) ?? new Set();
3280
+ names.add(mock.schemaName);
3281
+ byClient.set(mock.clientName, names);
3282
+ }
3283
+ const schemas = {};
3284
+ const notes = new Set();
3285
+ const owners = new Map();
3286
+ for (const [clientName, names] of byClient) {
3287
+ const collected = collectQueryDevtoolsSchemaComponents(clientName, [...names]);
3288
+ for (const note of collected.notes)
3289
+ notes.add(note);
3290
+ for (const [name, schema] of Object.entries(collected.schemas)) {
3291
+ const owner = owners.get(name);
3292
+ if (owner !== undefined) {
3293
+ if (JSON.stringify(schemas[name]) !== JSON.stringify(schema)) {
3294
+ notes.add(`${name} is declared by both ${owner} and ${clientName} - the one from ${owner} was kept.`);
3295
+ }
3296
+ continue;
3297
+ }
3298
+ owners.set(name, clientName);
3299
+ schemas[name] = schema;
3300
+ }
3301
+ }
3302
+ return { schemas, notes: [...notes] };
3303
+ }
3304
+ write(document) {
3305
+ if (this.specFormat() === 'yaml')
3306
+ return toQueryDevtoolsYaml(document);
3307
+ return `${JSON.stringify(document, null, 2)}\n`;
3308
+ }
3309
+ seedFromRoute(target) {
3310
+ if (!target.pattern) {
3311
+ this.draftError.set('Name the path first - the seed comes from what the description says it returns.');
3312
+ return;
3313
+ }
3314
+ this.applySeed({ kind: 'route', ...target });
3315
+ }
3316
+ applySeed(source) {
3317
+ const style = this.seedStyle();
3318
+ const client = this.draftClient();
3319
+ const seed = source.kind === 'schema'
3320
+ ? seedQueryDevtoolsSchemaBody(client, source.name, style)
3321
+ : seedQueryDevtoolsSchemaRoute({ clientName: client, method: source.method, pattern: source.pattern }, style);
3322
+ if (!seed) {
3323
+ this.draftSeed.set(null);
3324
+ this.seedSource.set(null);
3325
+ this.draftError.set(source.kind === 'schema'
3326
+ ? `The description does not name ${source.name}.`
3327
+ : `The description declares no JSON response for ${source.method} ${source.pattern}.`);
3328
+ return;
3329
+ }
3330
+ this.seedSource.set(source);
3331
+ this.draftSeed.set(seed);
3332
+ this.draftError.set(null);
3333
+ this.patchDraft({ body: JSON.stringify(seed.body, null, 2) });
3334
+ }
3335
+ countOf(value, fallback) {
3336
+ const count = Math.trunc(Number(value));
3337
+ return Number.isFinite(count) ? count : fallback;
3338
+ }
3339
+ copyText(text, onCopied) {
3340
+ writeQueryDevtoolsClipboard({ text }, this.hostEl.nativeElement.ownerDocument).then((result) => {
3341
+ if (result.ok)
3342
+ onCopied();
3343
+ });
3344
+ }
3345
+ /**
3346
+ * The mock id a live query would carry. `query` has to be the declared query of the mock being matched
3347
+ * against: it is part of the id, and a registered query carries no declaration of its own.
3348
+ */
3349
+ idOf(entry, query = '') {
3350
+ return queryDevtoolsMockId({
3351
+ clientName: entry.meta.clientName ?? '',
3352
+ method: entry.meta.method ?? 'GET',
3353
+ pattern: entry.meta.route ?? '',
3354
+ query,
3355
+ });
3356
+ }
3357
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsMocksTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3358
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsMocksTabComponent, isStandalone: true, selector: "et-query-devtools-mocks-tab", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-mocks-toolbar\">\n <p class=\"et-query-devtools-hint\">\n A mock replaces the request, so it answers a route that has never run - or does not exist yet. It bypasses the\n interceptor chain by construction, so a mocked secure route never exercises the token flow. The library is kept;\n whether a mock is <strong>armed</strong> is not, so a reload always stops serving them. GraphQL queries are not\n offered: they all POST one route, so matching them needs the document rather than the path.\n </p>\n <div class=\"et-query-devtools-settings-controls\">\n @if (rows().length && armedCount() < rows().length) {\n <button\n (click)=\"ARM_ALL()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Serve every mock in the library - the whole screen off the network at once\"\n >\n Arm all ({{ rows().length }})\n </button>\n }\n @if (armedCount()) {\n <button (click)=\"DISARM_ALL()\" class=\"et-query-devtools-btn\" type=\"button\">\n Disarm all ({{ armedCount() }})\n </button>\n }\n <button (click)=\"openDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n <span aria-hidden=\"true\">\uFF0B</span>\n New mock\n </button>\n </div>\n </div>\n\n @if (draft(); as form) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>New mock</strong>\n <span class=\"et-query-devtools-count\">for any route, whether a query has ever called it or not</span>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Client</span>\n <select #clientSelect (change)=\"pickClient(clientSelect.value)\" class=\"et-query-devtools-select\">\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\" [selected]=\"name === form.clientName\">{{ name }}</option>\n }\n </select>\n <small>a mock answers one client, matched by name</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Method</span>\n <select #methodSelect (change)=\"patchDraft({ method: methodSelect.value })\" class=\"et-query-devtools-select\">\n @for (method of METHODS; track method) {\n <option [value]=\"method\" [selected]=\"method === form.method\">{{ method }}</option>\n }\n </select>\n <small>matched exactly</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Path</span>\n <input\n #patternInput\n [value]=\"form.pattern\"\n (input)=\"patchDraft({ pattern: patternInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"/posts/:id/comments\"\n />\n <small><code>:name</code> matches any one segment, so the route is mocked rather than one URL</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Query</span>\n <input\n #queryInput\n [value]=\"form.query\"\n (input)=\"patchDraft({ query: queryInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"page=2&limit=10\"\n />\n <small>\n parameters the request must carry; anything else it asks for is ignored. Empty answers whatever the query\n string is - and a mock naming parameters wins over one that does not\n </small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusDraftInput\n [value]=\"form.status\"\n (input)=\"patchDraft({ status: statusDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyDraftInput\n [value]=\"form.latencyMs\"\n (input)=\"patchDraft({ latencyMs: latencyDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles</small>\n </label>\n </div>\n\n @if (hasSchema()) {\n <div class=\"et-query-devtools-seed\">\n <span class=\"et-query-devtools-section\">Seed</span>\n @if (isSchemaReady()) {\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [options]=\"routeOptions()\"\n (pickOption)=\"pickRoute($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n pickOnly\n >\n <input etSelectSearch placeholder=\"search the routes it declares\u2026\" />\n </et-select>\n <button\n (click)=\"seedFromDraftRoute()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Generate a body from what the description says this path returns\"\n >\n From this path\n </button>\n </div>\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [value]=\"pickedSchema()\"\n [options]=\"schemaNameOptions()\"\n (valueChange)=\"pickSchema($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n >\n <input etSelectSearch placeholder=\"search its named types\u2026\" />\n </et-select>\n <button\n [disabled]=\"!pickedSchema()\"\n (click)=\"seedFromSchema()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n From this type\n </button>\n </div>\n <select\n #stylePick\n (change)=\"pickSeedStyle(stylePick.value)\"\n class=\"et-query-devtools-select\"\n title=\"How lifelike the generated values are\"\n >\n @for (style of SEED_STYLES; track style.value) {\n <option [value]=\"style.value\" [selected]=\"style.value === seedStyle()\">{{ style.label }}</option>\n }\n </select>\n <small class=\"et-query-devtools-hint et-query-devtools-seed-hint\">{{ seedStyleHint() }}</small>\n } @else if (schemaError(); as error) {\n <span class=\"et-query-devtools-settings-warn\">The API description could not be loaded: {{ error }}</span>\n } @else {\n <span class=\"et-query-devtools-count\">Loading the API description\u2026</span>\n }\n </div>\n }\n\n <label class=\"et-query-devtools-mock-body\">\n <span class=\"et-query-devtools-section\">Body</span>\n <textarea\n #bodyInput\n [value]=\"form.body\"\n (input)=\"patchDraft({ body: bodyInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-mock-textarea\"\n rows=\"8\"\n spellcheck=\"false\"\n ></textarea>\n </label>\n\n @if (draftSeed(); as seed) {\n <p class=\"et-query-devtools-hint\">\n Generated from the API description{{ seed.schemaName ? ' as ' + seed.schemaName : '' }} - a starting point,\n not the contract. Saving opens the designer on it.\n </p>\n @if (seed.notes.length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of seed.notes; track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n }\n\n @if (draftError(); as error) {\n <p class=\"et-query-devtools-settings-warn\">{{ error }}</p>\n }\n\n <div class=\"et-query-devtools-mock-head\">\n <button (click)=\"saveDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n Save to the library\n </button>\n <button (click)=\"closeDraft()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Designed</strong>\n <span class=\"et-query-devtools-count\">{{ rows().length }} in the library</span>\n @if (rows().length) {\n <div class=\"et-query-devtools-spec-export\">\n <select #formatPick (change)=\"pickSpecFormat(formatPick.value)\" class=\"et-query-devtools-select\">\n @for (format of SPEC_FORMATS; track format.value) {\n <option [value]=\"format.value\" [selected]=\"format.value === specFormat()\">{{ format.label }}</option>\n }\n </select>\n <button\n (click)=\"exportLibrary()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every designed route as one OpenAPI 3.1 document - the response schemas inferred from the designed bodies, each body as an example\"\n >\n <span aria-hidden=\"true\">\u21E9</span>\n Export OpenAPI\n </button>\n </div>\n }\n </div>\n\n @for (row of rows(); track row.mock.id) {\n <div [class.et-query-devtools-mock-row--armed]=\"row.armed\" class=\"et-query-devtools-mock-row\">\n <div class=\"et-query-devtools-mock-head\">\n <button\n [class.et-query-devtools-btn--tampered]=\"row.armed\"\n [attr.aria-pressed]=\"row.armed\"\n (click)=\"toggleArmed(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{ row.armed ? 'Stop serving this response' : 'Serve this response instead of the request' }}\"\n >\n {{ row.armed ? 'Armed' : 'Arm' }}\n </button>\n <span class=\"et-query-devtools-method\">{{ row.mock.method }}</span>\n <span class=\"et-query-devtools-route et-query-devtools-mono\">{{ row.mock.pattern }}</span>\n @if (row.mock.query) {\n <span class=\"et-query-devtools-url\">?{{ row.mock.query }}</span>\n }\n <span class=\"et-query-devtools-url\">{{ row.mock.clientName }}</span>\n @if (row.mock.capturedAt) {\n <span class=\"et-query-devtools-chip\">captured</span>\n }\n @if (row.mock.schemaName; as schemaName) {\n <span class=\"et-query-devtools-chip\" title=\"Seeded from the API description\">{{ schemaName }}</span>\n }\n @if (row.isSecure) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"A mock sends nothing, so no token is attached and the auth flow is never exercised\"\n >\n no auth\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"editBody(row)\" class=\"et-query-devtools-btn\" type=\"button\">Body</button>\n <button\n (click)=\"copyDefinition(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as a @ethlete/query definition - the response type inferred from the body, the args contract and the creator call\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedDefinition.value() === row.mock.id ? 'Copied' : 'TS' }}\n </button>\n <button\n (click)=\"copyPathItem(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as an OpenAPI paths entry, ready to paste under an existing description\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedPathItem.value() === row.mock.id ? 'Copied' : 'OAS' }}\n </button>\n <button (click)=\"remove(row)\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Delete\n </button>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusInput\n [value]=\"row.mock.status\"\n (change)=\"setStatus(row, statusInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error, body and all</small>\n </label>\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyInput\n [value]=\"row.mock.latencyMs\"\n (change)=\"setLatency(row, latencyInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles, so the route still has a loading state</small>\n </label>\n </div>\n\n @if (editingId() === row.mock.id) {\n <et-query-devtools-mock-designer\n [body]=\"row.mock.body\"\n [annotations]=\"editingAnnotations()\"\n (save)=\"saveBody(row, $event)\"\n (dismiss)=\"cancelBody()\"\n />\n }\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">\n Nothing designed yet. <strong>New mock</strong> writes one from scratch; capturing below seeds one from\n something that actually happened.\n </p>\n }\n\n @if (specNotes().length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of specNotes(); track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Capture</strong>\n <span class=\"et-query-devtools-count\">live queries holding a response</span>\n </div>\n\n @for (row of captureRows(); track row.entry.id) {\n <div class=\"et-query-devtools-mock-head\">\n <span class=\"et-query-devtools-method\">{{ row.method }}</span>\n <button\n (click)=\"host.selectQuery(row.entry.id)\"\n class=\"et-query-devtools-route et-query-devtools-mono et-query-devtools-row-link\"\n type=\"button\"\n title=\"Open this query\"\n >\n {{ row.pattern }}\n </button>\n <span class=\"et-query-devtools-url\">{{ row.clientName }}</span>\n @if (row.shared > 1) {\n <span class=\"et-query-devtools-count\" title=\"A mock answers the route, so it answers all of them\">\n {{ row.shared }} queries\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"capture(row)\" class=\"et-query-devtools-btn\" type=\"button\">\n {{ row.exists ? 'Re-capture' : 'Capture' }}\n </button>\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">No live query has a response yet.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-mocks-toolbar{align-items:flex-start}.et-query-devtools-mock-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-mock-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-mock-row--armed{background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-mock-head{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-mock-fields,.et-query-devtools-seed,.et-query-devtools-mock-body{max-inline-size:96rem}.et-query-devtools-mock-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(38rem,1fr));align-items:start;gap:.4rem 1.6rem;padding-block-start:.4rem}.et-query-devtools-mock-fields .et-query-devtools-field{display:grid;grid-template-columns:7rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-mock-fields .et-query-devtools-select{justify-self:start;max-inline-size:100%}.et-query-devtools-mock-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-mock-fields .et-query-devtools-field--wide{grid-column:1 / -1;grid-template-columns:7rem minmax(0,1fr)}.et-query-devtools-spec-export{display:flex;align-items:center;gap:.6rem;margin-inline-start:auto}.et-query-devtools-seed{display:flex;align-items:center;flex-wrap:wrap;gap:.4rem 2.4rem;padding-block-start:.4rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-seed-pick{display:flex;align-items:center;gap:.2rem}.et-query-devtools-seed .et-query-devtools-select{max-inline-size:32rem}.et-query-devtools-combobox{flex:0 1 auto;inline-size:32rem;min-block-size:var(--_et-qdt-control-h);box-sizing:border-box;background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .6rem;font-size:1.15rem}.et-query-devtools-combobox input{background:none;border:0;padding:0;color:inherit;font:inherit}.et-query-devtools-seed-hint{flex-basis:100%;margin:0}.et-query-devtools-mock-body{display:block;padding-block-start:.4rem}.et-query-devtools-mock-textarea{display:block;inline-size:100%;resize:vertical;font-family:inherit;font-size:1.15rem;line-height:1.5;tab-size:2}}\n"], dependencies: [{ kind: "component", type: QueryDevtoolsMockDesignerComponent, selector: "et-query-devtools-mock-designer", inputs: ["body", "annotations", "notes"], outputs: ["save", "dismiss"] }, { kind: "component", type: SelectComponent, selector: "et-select", inputs: ["loadMoreLabel", "addNewLabel", "createLabel", "clearable", "clearLabel", "selectAllLabel"] }, { kind: "directive", type: SelectSearchDirective, selector: "input[etSelectSearch]", inputs: ["query"], outputs: ["queryChange"], exportAs: ["etSelectSearch"] }], encapsulation: i0.ViewEncapsulation.None }); }
3359
+ }
3360
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsMocksTabComponent, decorators: [{
3361
+ type: Component,
3362
+ args: [{ selector: 'et-query-devtools-mocks-tab', encapsulation: ViewEncapsulation.None, imports: [QueryDevtoolsMockDesignerComponent, SelectComponent, SelectSearchDirective], template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-mocks-toolbar\">\n <p class=\"et-query-devtools-hint\">\n A mock replaces the request, so it answers a route that has never run - or does not exist yet. It bypasses the\n interceptor chain by construction, so a mocked secure route never exercises the token flow. The library is kept;\n whether a mock is <strong>armed</strong> is not, so a reload always stops serving them. GraphQL queries are not\n offered: they all POST one route, so matching them needs the document rather than the path.\n </p>\n <div class=\"et-query-devtools-settings-controls\">\n @if (rows().length && armedCount() < rows().length) {\n <button\n (click)=\"ARM_ALL()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Serve every mock in the library - the whole screen off the network at once\"\n >\n Arm all ({{ rows().length }})\n </button>\n }\n @if (armedCount()) {\n <button (click)=\"DISARM_ALL()\" class=\"et-query-devtools-btn\" type=\"button\">\n Disarm all ({{ armedCount() }})\n </button>\n }\n <button (click)=\"openDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n <span aria-hidden=\"true\">\uFF0B</span>\n New mock\n </button>\n </div>\n </div>\n\n @if (draft(); as form) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>New mock</strong>\n <span class=\"et-query-devtools-count\">for any route, whether a query has ever called it or not</span>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Client</span>\n <select #clientSelect (change)=\"pickClient(clientSelect.value)\" class=\"et-query-devtools-select\">\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\" [selected]=\"name === form.clientName\">{{ name }}</option>\n }\n </select>\n <small>a mock answers one client, matched by name</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Method</span>\n <select #methodSelect (change)=\"patchDraft({ method: methodSelect.value })\" class=\"et-query-devtools-select\">\n @for (method of METHODS; track method) {\n <option [value]=\"method\" [selected]=\"method === form.method\">{{ method }}</option>\n }\n </select>\n <small>matched exactly</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Path</span>\n <input\n #patternInput\n [value]=\"form.pattern\"\n (input)=\"patchDraft({ pattern: patternInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"/posts/:id/comments\"\n />\n <small><code>:name</code> matches any one segment, so the route is mocked rather than one URL</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Query</span>\n <input\n #queryInput\n [value]=\"form.query\"\n (input)=\"patchDraft({ query: queryInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"page=2&limit=10\"\n />\n <small>\n parameters the request must carry; anything else it asks for is ignored. Empty answers whatever the query\n string is - and a mock naming parameters wins over one that does not\n </small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusDraftInput\n [value]=\"form.status\"\n (input)=\"patchDraft({ status: statusDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyDraftInput\n [value]=\"form.latencyMs\"\n (input)=\"patchDraft({ latencyMs: latencyDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles</small>\n </label>\n </div>\n\n @if (hasSchema()) {\n <div class=\"et-query-devtools-seed\">\n <span class=\"et-query-devtools-section\">Seed</span>\n @if (isSchemaReady()) {\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [options]=\"routeOptions()\"\n (pickOption)=\"pickRoute($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n pickOnly\n >\n <input etSelectSearch placeholder=\"search the routes it declares\u2026\" />\n </et-select>\n <button\n (click)=\"seedFromDraftRoute()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Generate a body from what the description says this path returns\"\n >\n From this path\n </button>\n </div>\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [value]=\"pickedSchema()\"\n [options]=\"schemaNameOptions()\"\n (valueChange)=\"pickSchema($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n >\n <input etSelectSearch placeholder=\"search its named types\u2026\" />\n </et-select>\n <button\n [disabled]=\"!pickedSchema()\"\n (click)=\"seedFromSchema()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n From this type\n </button>\n </div>\n <select\n #stylePick\n (change)=\"pickSeedStyle(stylePick.value)\"\n class=\"et-query-devtools-select\"\n title=\"How lifelike the generated values are\"\n >\n @for (style of SEED_STYLES; track style.value) {\n <option [value]=\"style.value\" [selected]=\"style.value === seedStyle()\">{{ style.label }}</option>\n }\n </select>\n <small class=\"et-query-devtools-hint et-query-devtools-seed-hint\">{{ seedStyleHint() }}</small>\n } @else if (schemaError(); as error) {\n <span class=\"et-query-devtools-settings-warn\">The API description could not be loaded: {{ error }}</span>\n } @else {\n <span class=\"et-query-devtools-count\">Loading the API description\u2026</span>\n }\n </div>\n }\n\n <label class=\"et-query-devtools-mock-body\">\n <span class=\"et-query-devtools-section\">Body</span>\n <textarea\n #bodyInput\n [value]=\"form.body\"\n (input)=\"patchDraft({ body: bodyInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-mock-textarea\"\n rows=\"8\"\n spellcheck=\"false\"\n ></textarea>\n </label>\n\n @if (draftSeed(); as seed) {\n <p class=\"et-query-devtools-hint\">\n Generated from the API description{{ seed.schemaName ? ' as ' + seed.schemaName : '' }} - a starting point,\n not the contract. Saving opens the designer on it.\n </p>\n @if (seed.notes.length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of seed.notes; track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n }\n\n @if (draftError(); as error) {\n <p class=\"et-query-devtools-settings-warn\">{{ error }}</p>\n }\n\n <div class=\"et-query-devtools-mock-head\">\n <button (click)=\"saveDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n Save to the library\n </button>\n <button (click)=\"closeDraft()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Designed</strong>\n <span class=\"et-query-devtools-count\">{{ rows().length }} in the library</span>\n @if (rows().length) {\n <div class=\"et-query-devtools-spec-export\">\n <select #formatPick (change)=\"pickSpecFormat(formatPick.value)\" class=\"et-query-devtools-select\">\n @for (format of SPEC_FORMATS; track format.value) {\n <option [value]=\"format.value\" [selected]=\"format.value === specFormat()\">{{ format.label }}</option>\n }\n </select>\n <button\n (click)=\"exportLibrary()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every designed route as one OpenAPI 3.1 document - the response schemas inferred from the designed bodies, each body as an example\"\n >\n <span aria-hidden=\"true\">\u21E9</span>\n Export OpenAPI\n </button>\n </div>\n }\n </div>\n\n @for (row of rows(); track row.mock.id) {\n <div [class.et-query-devtools-mock-row--armed]=\"row.armed\" class=\"et-query-devtools-mock-row\">\n <div class=\"et-query-devtools-mock-head\">\n <button\n [class.et-query-devtools-btn--tampered]=\"row.armed\"\n [attr.aria-pressed]=\"row.armed\"\n (click)=\"toggleArmed(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{ row.armed ? 'Stop serving this response' : 'Serve this response instead of the request' }}\"\n >\n {{ row.armed ? 'Armed' : 'Arm' }}\n </button>\n <span class=\"et-query-devtools-method\">{{ row.mock.method }}</span>\n <span class=\"et-query-devtools-route et-query-devtools-mono\">{{ row.mock.pattern }}</span>\n @if (row.mock.query) {\n <span class=\"et-query-devtools-url\">?{{ row.mock.query }}</span>\n }\n <span class=\"et-query-devtools-url\">{{ row.mock.clientName }}</span>\n @if (row.mock.capturedAt) {\n <span class=\"et-query-devtools-chip\">captured</span>\n }\n @if (row.mock.schemaName; as schemaName) {\n <span class=\"et-query-devtools-chip\" title=\"Seeded from the API description\">{{ schemaName }}</span>\n }\n @if (row.isSecure) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"A mock sends nothing, so no token is attached and the auth flow is never exercised\"\n >\n no auth\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"editBody(row)\" class=\"et-query-devtools-btn\" type=\"button\">Body</button>\n <button\n (click)=\"copyDefinition(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as a @ethlete/query definition - the response type inferred from the body, the args contract and the creator call\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedDefinition.value() === row.mock.id ? 'Copied' : 'TS' }}\n </button>\n <button\n (click)=\"copyPathItem(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as an OpenAPI paths entry, ready to paste under an existing description\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedPathItem.value() === row.mock.id ? 'Copied' : 'OAS' }}\n </button>\n <button (click)=\"remove(row)\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Delete\n </button>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusInput\n [value]=\"row.mock.status\"\n (change)=\"setStatus(row, statusInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error, body and all</small>\n </label>\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyInput\n [value]=\"row.mock.latencyMs\"\n (change)=\"setLatency(row, latencyInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles, so the route still has a loading state</small>\n </label>\n </div>\n\n @if (editingId() === row.mock.id) {\n <et-query-devtools-mock-designer\n [body]=\"row.mock.body\"\n [annotations]=\"editingAnnotations()\"\n (save)=\"saveBody(row, $event)\"\n (dismiss)=\"cancelBody()\"\n />\n }\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">\n Nothing designed yet. <strong>New mock</strong> writes one from scratch; capturing below seeds one from\n something that actually happened.\n </p>\n }\n\n @if (specNotes().length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of specNotes(); track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Capture</strong>\n <span class=\"et-query-devtools-count\">live queries holding a response</span>\n </div>\n\n @for (row of captureRows(); track row.entry.id) {\n <div class=\"et-query-devtools-mock-head\">\n <span class=\"et-query-devtools-method\">{{ row.method }}</span>\n <button\n (click)=\"host.selectQuery(row.entry.id)\"\n class=\"et-query-devtools-route et-query-devtools-mono et-query-devtools-row-link\"\n type=\"button\"\n title=\"Open this query\"\n >\n {{ row.pattern }}\n </button>\n <span class=\"et-query-devtools-url\">{{ row.clientName }}</span>\n @if (row.shared > 1) {\n <span class=\"et-query-devtools-count\" title=\"A mock answers the route, so it answers all of them\">\n {{ row.shared }} queries\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"capture(row)\" class=\"et-query-devtools-btn\" type=\"button\">\n {{ row.exists ? 'Re-capture' : 'Capture' }}\n </button>\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">No live query has a response yet.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-mocks-toolbar{align-items:flex-start}.et-query-devtools-mock-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-mock-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-mock-row--armed{background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-mock-head{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-mock-fields,.et-query-devtools-seed,.et-query-devtools-mock-body{max-inline-size:96rem}.et-query-devtools-mock-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(38rem,1fr));align-items:start;gap:.4rem 1.6rem;padding-block-start:.4rem}.et-query-devtools-mock-fields .et-query-devtools-field{display:grid;grid-template-columns:7rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-mock-fields .et-query-devtools-select{justify-self:start;max-inline-size:100%}.et-query-devtools-mock-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-mock-fields .et-query-devtools-field--wide{grid-column:1 / -1;grid-template-columns:7rem minmax(0,1fr)}.et-query-devtools-spec-export{display:flex;align-items:center;gap:.6rem;margin-inline-start:auto}.et-query-devtools-seed{display:flex;align-items:center;flex-wrap:wrap;gap:.4rem 2.4rem;padding-block-start:.4rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-seed-pick{display:flex;align-items:center;gap:.2rem}.et-query-devtools-seed .et-query-devtools-select{max-inline-size:32rem}.et-query-devtools-combobox{flex:0 1 auto;inline-size:32rem;min-block-size:var(--_et-qdt-control-h);box-sizing:border-box;background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .6rem;font-size:1.15rem}.et-query-devtools-combobox input{background:none;border:0;padding:0;color:inherit;font:inherit}.et-query-devtools-seed-hint{flex-basis:100%;margin:0}.et-query-devtools-mock-body{display:block;padding-block-start:.4rem}.et-query-devtools-mock-textarea{display:block;inline-size:100%;resize:vertical;font-family:inherit;font-size:1.15rem;line-height:1.5;tab-size:2}}\n"] }]
3363
+ }], ctorParameters: () => [] });
3364
+
3365
+ const isAbsoluteHttpUrl = (value) => {
3366
+ try {
3367
+ return ['http:', 'https:'].includes(new URL(value).protocol);
3368
+ }
3369
+ catch {
3370
+ return false;
3371
+ }
3372
+ };
3373
+ const SCOPE_ROWS = [
3374
+ {
3375
+ key: 'viewState',
3376
+ label: 'Panel view state',
3377
+ hint: 'Where the panel sits, how big it is, the open tab, every filter and the selected query. Set none to forget all of it on each reload.',
3378
+ },
3379
+ {
3380
+ key: 'pins',
3381
+ label: 'Pinned queries',
3382
+ hint: 'Which queries sort to the top of the list. Local outlives the tab, because a pin says what you are working on rather than what you are looking at.',
3383
+ },
3384
+ {
3385
+ key: 'overrides',
3386
+ label: 'Response overrides',
3387
+ hint: 'Armed edits, replayed as queries register - before their first fetch. None is the default: a reload is how the app stops being lied to.',
3388
+ warn: {
3389
+ scopes: ['local'],
3390
+ text: 'Armed overrides now outlive closing the tab. An app that stays tampered with across days is hours of debugging the wrong thing - the bar above the tabs says when they came back.',
3391
+ },
3392
+ },
3393
+ {
3394
+ key: 'mocks',
3395
+ label: 'Designed mocks',
3396
+ hint: 'The library you authored, not whether any of it is armed - arming has its own scope below.',
3397
+ },
3398
+ {
3399
+ key: 'armedMocks',
3400
+ label: 'Armed mocks',
3401
+ hint: 'Which of the library is served. None is the default: a reload is how the app goes back to talking to the API.',
3402
+ warn: {
3403
+ scopes: ['session', 'local'],
3404
+ text: 'The next page load starts serving these routes from the panel, before anyone opens it. The bar above the tabs says when they came back.',
3405
+ },
3406
+ },
3407
+ {
3408
+ key: 'authSessions',
3409
+ label: 'Sessions and accounts',
3410
+ hint: 'The token pairs the Auth tab switches between, and the credentials it logs in with. Local is the default in a development build: a vault that forgets the other user on every reload is not one. None keeps nothing at all.',
3411
+ warn: {
3412
+ scopes: ['local'],
3413
+ text: 'Access and refresh tokens for every user you logged in as, plus what you typed into the account fields, stay in this browser until you forget them. They are never kept for an API env marked production.',
3414
+ },
3415
+ },
3416
+ {
3417
+ key: 'armedFaults',
3418
+ label: 'Armed faults',
3419
+ hint: 'The latency and failures injected per client, budgets included. None is the default, for the same reason as armed mocks.',
3420
+ warn: {
3421
+ scopes: ['session', 'local'],
3422
+ text: 'The next page load starts injecting these failures on its own, so an app that looks broken may only be armed. The bar above the tabs says when they came back.',
3423
+ },
3424
+ },
3425
+ ];
3426
+ const SCOPES = [
3427
+ { value: 'none', label: 'none' },
3428
+ { value: 'session', label: 'session' },
3429
+ { value: 'local', label: 'local' },
3430
+ ];
3431
+ /**
3432
+ * Why IndexedDB - the one store with the quota for a large library of designed data - is not on offer.
3433
+ * These are read synchronously: view state and pins in a field initializer of the panel, and overrides
3434
+ * inside query registration, before the first request. An async store cannot answer either in time, and a
3435
+ * scope that silently arrives late is worse than one that is missing. The mock library is the one that
3436
+ * could tolerate arriving late, since nothing is served until a mock is armed by hand.
3437
+ */
3438
+ const INDEXED_DB_TITLE = 'Unavailable: these are read synchronously - view state before the first render, overrides before the first fetch - and IndexedDB cannot answer in time. Only the mock library could tolerate an async store, and it is not wired to one yet.';
3439
+ const LIMIT_ROWS = [
3440
+ {
3441
+ key: 'maxEvents',
3442
+ label: 'Events log',
3443
+ min: 10,
3444
+ max: 1000,
3445
+ step: 10,
3446
+ hint: 'rows the Events tab keeps. Lowering it trims the log now.',
3447
+ },
3448
+ {
3449
+ key: 'maxDroppedCacheEntries',
3450
+ label: 'Dropped cache entries',
3451
+ min: 0,
3452
+ max: 200,
3453
+ step: 5,
3454
+ hint: 'per client, remembered so the Cache tab can say why an entry went away. Applies as entries are dropped.',
3455
+ },
3456
+ ];
3457
+ /**
3458
+ * Every panel-wide switch in one place - the storage each kind of state uses, the limits the panel would
3459
+ * otherwise hold as constants, and the toggles their own tabs also carry.
3460
+ */
3461
+ class QueryDevtoolsSettingsComponent {
3462
+ constructor() {
3463
+ this.document = inject(DOCUMENT);
3464
+ this.host = injectQueryDevtoolsHost();
3465
+ this.SCOPE_ROWS = SCOPE_ROWS;
3466
+ this.SCOPES = SCOPES;
3467
+ this.INDEXED_DB_TITLE = INDEXED_DB_TITLE;
3468
+ this.LIMIT_ROWS = LIMIT_ROWS;
3469
+ this.ARM_ALL_MOCKS = armAllQueryDevtoolsMocks;
3470
+ this.DISARM_ALL_MOCKS = clearQueryDevtoolsArmedMocks;
3471
+ this.DISARM_ALL_FAULTS = clearQueryDevtoolsFaults;
3472
+ /** What queries actually retain, which is the application's value unless this panel raised it. */
3473
+ this.responseHistory = computed(queryDevtoolsResponseHistory, /* @ts-ignore */
3474
+ ...(ngDevMode ? [{ debugName: "responseHistory" }] : /* istanbul ignore next */ []));
3475
+ this.mockCount = computed(() => queryDevtoolsMocks().length, /* @ts-ignore */
3476
+ ...(ngDevMode ? [{ debugName: "mockCount" }] : /* istanbul ignore next */ []));
3477
+ this.sessionCount = computed(() => queryDevtoolsAuthSessions().length, /* @ts-ignore */
3478
+ ...(ngDevMode ? [{ debugName: "sessionCount" }] : /* istanbul ignore next */ []));
3479
+ this.armedMockCount = computed(() => queryDevtoolsArmedMocks().size, /* @ts-ignore */
3480
+ ...(ngDevMode ? [{ debugName: "armedMockCount" }] : /* istanbul ignore next */ []));
3481
+ this.armedFaultCount = computed(() => this.host.faultClients().filter((client) => client.armed).length, /* @ts-ignore */
3482
+ ...(ngDevMode ? [{ debugName: "armedFaultCount" }] : /* istanbul ignore next */ []));
3483
+ /** The same keys the Events tab's own picker offers - see {@link queryDevtoolsEventClients}. */
3484
+ this.eventClients = computed(() => queryDevtoolsEventClients(this.host.eventLog(), this.host.eventClient()), /* @ts-ignore */
3485
+ ...(ngDevMode ? [{ debugName: "eventClients" }] : /* istanbul ignore next */ []));
3486
+ this.resetConfirming = signal(false, /* @ts-ignore */
3487
+ ...(ngDevMode ? [{ debugName: "resetConfirming" }] : /* istanbul ignore next */ []));
3488
+ this.FORGET_SESSIONS = clearQueryDevtoolsAuthSessions;
3489
+ /** The backends the application declared, or an empty list - the card renders only for a declared one. */
3490
+ this.apiEnvs = computed(queryDevtoolsApiEnvs, /* @ts-ignore */
3491
+ ...(ngDevMode ? [{ debugName: "apiEnvs" }] : /* istanbul ignore next */ []));
3492
+ }
3493
+ /** The env id (or typed URL) a switch's key holds, or `null` while the application picks for itself. */
3494
+ apiEnvValue(apiSwitch) {
3495
+ return queryDevtoolsApiEnvValues()[apiSwitch.storageKey] ?? null;
3423
3496
  }
3424
- toggleArmed(row) {
3425
- armQueryDevtoolsMock(row.mock.id, !row.armed);
3497
+ /** The env a switch falls back to with nothing stored, described for the default button. */
3498
+ apiEnvFallback(apiSwitch) {
3499
+ const fallback = apiSwitch.envs.find((env) => env.id === apiSwitch.fallback);
3500
+ return {
3501
+ label: fallback ? `default (${fallback.label ?? fallback.id})` : 'default',
3502
+ production: fallback?.production === true,
3503
+ };
3426
3504
  }
3427
- remove(row) {
3428
- deleteQueryDevtoolsMock(row.mock.id);
3505
+ /** Whether the pick in force - the stored env, or the fallback behind an unwritten key - is production. */
3506
+ apiEnvIsProduction(apiSwitch) {
3507
+ const stored = this.apiEnvValue(apiSwitch);
3508
+ return apiSwitch.envs.find((env) => env.id === (stored ?? apiSwitch.fallback))?.production === true;
3429
3509
  }
3430
- setStatus(row, value) {
3431
- saveQueryDevtoolsMock({ ...row.mock, status: this.countOf(value, row.mock.status) });
3510
+ /** A stored value no declared env carries, which is a URL somebody typed in below. */
3511
+ apiEnvCustomUrl(apiSwitch) {
3512
+ const stored = this.apiEnvValue(apiSwitch);
3513
+ return stored && !apiSwitch.envs.some((env) => env.id === stored) ? stored : '';
3432
3514
  }
3433
- setLatency(row, value) {
3434
- saveQueryDevtoolsMock({ ...row.mock, latencyMs: this.countOf(value, row.mock.latencyMs) });
3515
+ /** Writes the application's own key and reloads - it is read before Angular boots, so nothing else can. */
3516
+ pickApiEnv(apiSwitch, value) {
3517
+ setQueryDevtoolsApiEnv(apiSwitch.storageKey, value);
3518
+ this.document.defaultView?.location.reload();
3435
3519
  }
3436
- /**
3437
- * Copies the route as a `@ethlete/query` definition - the response type inferred from the designed body,
3438
- * the args contract and the creator call - so a mocked route can be pasted into the app it was designed
3439
- * for.
3440
- */
3441
- copyDefinition(row) {
3442
- const snippet = buildQueryDefinitionSnippet({
3443
- method: row.mock.method,
3444
- pattern: row.mock.pattern,
3445
- query: row.mock.query,
3446
- body: row.mock.body,
3447
- });
3448
- this.copyText(snippet, () => this.copiedDefinition.mark(row.mock.id));
3520
+ setCustomApiUrl(apiSwitch, value) {
3521
+ const url = value.trim();
3522
+ if (url === this.apiEnvCustomUrl(apiSwitch))
3523
+ return;
3524
+ if (url && !isAbsoluteHttpUrl(url))
3525
+ return;
3526
+ this.pickApiEnv(apiSwitch, url || null);
3449
3527
  }
3450
- /**
3451
- * Copies one route as an OpenAPI `paths` entry, ready to be pasted under an existing description's
3452
- * `paths`. A route seeded from a named schema keeps its `$ref`, since it is merged back into the
3453
- * document that declares it.
3454
- */
3455
- copyPathItem(row) {
3456
- const schemas = this.schemasFor([row.mock]);
3457
- const built = buildQueryDevtoolsOpenApiPathItem({ mocks: [row.mock], schemas: schemas.schemas });
3458
- this.specNotes.set([...schemas.notes, ...built.notes]);
3459
- this.copyText(this.write(built.document), () => this.copiedPathItem.mark(row.mock.id));
3528
+ settings() {
3529
+ return queryDevtoolsSettings();
3460
3530
  }
3461
- /**
3462
- * Downloads the whole library as one OpenAPI 3.1 document - the deliverable the API team merges. Every
3463
- * designed mock is in it, armed or not: the library is the design work, and arming is only what this
3464
- * page load happens to be serving.
3465
- */
3466
- exportLibrary() {
3467
- const mocks = this.rows().map((row) => row.mock);
3468
- if (!mocks.length)
3469
- return;
3470
- const schemas = this.schemasFor(mocks);
3471
- const built = buildQueryDevtoolsOpenApiDocument({ mocks, schemas: schemas.schemas, now: Date.now() });
3472
- const format = this.specFormat();
3473
- this.specNotes.set([...schemas.notes, ...built.notes]);
3474
- this.host.downloadTextFile({
3475
- name: `openapi-designed-mocks-${new Date().toISOString().slice(0, 10)}.${format}`,
3476
- content: this.write(built.document),
3477
- type: SPEC_MEDIA_TYPES[format],
3478
- });
3531
+ scopeOf(key) {
3532
+ return this.settings()[key];
3479
3533
  }
3480
- editBody(row) {
3481
- this.editingId.set(row.mock.id);
3534
+ limitOf(key) {
3535
+ return this.settings()[key];
3482
3536
  }
3483
- cancelBody() {
3484
- this.editingId.set(null);
3537
+ /** What the picked scope means beyond where the state is kept, or `null` while it means nothing extra. */
3538
+ warningFor(row, scope) {
3539
+ return row.warn?.scopes.includes(scope) ? row.warn.text : null;
3485
3540
  }
3486
- saveBody(row, body) {
3487
- saveQueryDevtoolsMock({ ...row.mock, body });
3488
- this.cancelBody();
3541
+ /** Why one scope is not on offer for a row, for the button's title, or `null` while it is. */
3542
+ unavailableReason(row, scope) {
3543
+ if (row.key !== 'authSessions' || scope !== 'local' || queryDevtoolsAllowsLocalAuthSessions())
3544
+ return null;
3545
+ return 'Unavailable outside a development build: live access and refresh tokens, and the credentials you typed in, must not outlive this tab on a deployed origin. The vault keeps nothing here unless you pick Session, which keeps it for as long as the tab.';
3489
3546
  }
3490
- /**
3491
- * The declared schemas the given mocks were seeded from, so their responses can reference them. Each
3492
- * client is asked its own description, and a name two of them both declare keeps the first - one
3493
- * exported document cannot hold two `MatchView`s.
3494
- */
3495
- schemasFor(mocks) {
3496
- const byClient = new Map();
3497
- for (const mock of mocks) {
3498
- if (!mock.schemaName)
3499
- continue;
3500
- const names = byClient.get(mock.clientName) ?? new Set();
3501
- names.add(mock.schemaName);
3502
- byClient.set(mock.clientName, names);
3503
- }
3504
- const schemas = {};
3505
- const notes = new Set();
3506
- const owners = new Map();
3507
- for (const [clientName, names] of byClient) {
3508
- const collected = collectQueryDevtoolsSchemaComponents(clientName, [...names]);
3509
- for (const note of collected.notes)
3510
- notes.add(note);
3511
- for (const [name, schema] of Object.entries(collected.schemas)) {
3512
- const owner = owners.get(name);
3513
- if (owner !== undefined) {
3514
- if (JSON.stringify(schemas[name]) !== JSON.stringify(schema)) {
3515
- notes.add(`${name} is declared by both ${owner} and ${clientName} - the one from ${owner} was kept.`);
3516
- }
3517
- continue;
3518
- }
3519
- owners.set(name, clientName);
3520
- schemas[name] = schema;
3521
- }
3522
- }
3523
- return { schemas, notes: [...notes] };
3547
+ setScope(key, scope) {
3548
+ // Everything armed goes through its own module: changing the scope moves an existing store and
3549
+ // captures whatever is armed right now, so the choice reads as "keep these".
3550
+ if (key === 'overrides')
3551
+ return setQueryDevtoolsOverridesScope(scope);
3552
+ if (key === 'armedMocks')
3553
+ return setQueryDevtoolsArmedMocksScope(scope);
3554
+ if (key === 'armedFaults')
3555
+ return setQueryDevtoolsFaultsScope(scope);
3556
+ setQueryDevtoolsSettings(key === 'viewState'
3557
+ ? { viewState: scope }
3558
+ : key === 'pins'
3559
+ ? { pins: scope }
3560
+ : key === 'authSessions'
3561
+ ? { authSessions: scope }
3562
+ : { mocks: scope });
3524
3563
  }
3525
- write(document) {
3526
- if (this.specFormat() === 'yaml')
3527
- return toQueryDevtoolsYaml(document);
3528
- return `${JSON.stringify(document, null, 2)}\n`;
3564
+ setLimit(key, value) {
3565
+ const count = Number(value);
3566
+ setQueryDevtoolsSettings(key === 'maxEvents' ? { maxEvents: count } : { maxDroppedCacheEntries: count });
3529
3567
  }
3530
- seedFromRoute(target) {
3531
- if (!target.pattern) {
3532
- this.draftError.set('Name the path first - the seed comes from what the description says it returns.');
3533
- return;
3534
- }
3535
- this.applySeed({ kind: 'route', ...target });
3568
+ setResponseHistory(value) {
3569
+ setQueryDevtoolsSettings({ responseHistory: Number(value) });
3536
3570
  }
3537
- applySeed(source) {
3538
- const style = this.seedStyle();
3539
- const client = this.draftClient();
3540
- const seed = source.kind === 'schema'
3541
- ? seedQueryDevtoolsSchemaBody(client, source.name, style)
3542
- : seedQueryDevtoolsSchemaRoute({ clientName: client, method: source.method, pattern: source.pattern }, style);
3543
- if (!seed) {
3544
- this.draftSeed.set(null);
3545
- this.seedSource.set(null);
3546
- this.draftError.set(source.kind === 'schema'
3547
- ? `The description does not name ${source.name}.`
3548
- : `The description declares no JSON response for ${source.method} ${source.pattern}.`);
3549
- return;
3550
- }
3551
- this.seedSource.set(source);
3552
- this.draftSeed.set(seed);
3553
- this.draftError.set(null);
3554
- this.patchDraft({ body: JSON.stringify(seed.body, null, 2) });
3571
+ /** Hands retention back to `provideQueryDevtools({ responseHistory })`. */
3572
+ clearResponseHistory() {
3573
+ setQueryDevtoolsSettings({ responseHistory: null });
3555
3574
  }
3556
- countOf(value, fallback) {
3557
- const count = Math.trunc(Number(value));
3558
- return Number.isFinite(count) ? count : fallback;
3575
+ reset() {
3576
+ this.host.resetDevtools();
3577
+ this.resetConfirming.set(false);
3559
3578
  }
3560
- copyText(text, onCopied) {
3561
- writeQueryDevtoolsClipboard({ text }, this.hostEl.nativeElement.ownerDocument).then((result) => {
3562
- if (result.ok)
3563
- onCopied();
3564
- });
3579
+ toggleGoneQueries() {
3580
+ this.host.toggleFacet('gone');
3565
3581
  }
3566
- /**
3567
- * The mock id a live query would carry. `query` has to be the declared query of the mock being matched
3568
- * against: it is part of the id, and a registered query carries no declaration of its own.
3569
- */
3570
- idOf(entry, query = '') {
3571
- return queryDevtoolsMockId({
3572
- clientName: entry.meta.clientName ?? '',
3573
- method: entry.meta.method ?? 'GET',
3574
- pattern: entry.meta.route ?? '',
3575
- query,
3576
- });
3582
+ showsGoneQueries() {
3583
+ return this.host.queryFacets().has('gone');
3577
3584
  }
3578
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsMocksTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3579
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsMocksTabComponent, isStandalone: true, selector: "et-query-devtools-mocks-tab", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-mocks-toolbar\">\n <p class=\"et-query-devtools-hint\">\n A mock replaces the request, so it answers a route that has never run - or does not exist yet. It bypasses the\n interceptor chain by construction, so a mocked secure route never exercises the token flow. The library is kept;\n whether a mock is <strong>armed</strong> is not, so a reload always stops serving them. GraphQL queries are not\n offered: they all POST one route, so matching them needs the document rather than the path.\n </p>\n <div class=\"et-query-devtools-settings-controls\">\n @if (rows().length && armedCount() < rows().length) {\n <button\n (click)=\"ARM_ALL()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Serve every mock in the library - the whole screen off the network at once\"\n >\n Arm all ({{ rows().length }})\n </button>\n }\n @if (armedCount()) {\n <button (click)=\"DISARM_ALL()\" class=\"et-query-devtools-btn\" type=\"button\">\n Disarm all ({{ armedCount() }})\n </button>\n }\n <button (click)=\"openDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n <span aria-hidden=\"true\">\uFF0B</span>\n New mock\n </button>\n </div>\n </div>\n\n @if (draft(); as form) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>New mock</strong>\n <span class=\"et-query-devtools-count\">for any route, whether a query has ever called it or not</span>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Client</span>\n <select #clientSelect (change)=\"pickClient(clientSelect.value)\" class=\"et-query-devtools-select\">\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\" [selected]=\"name === form.clientName\">{{ name }}</option>\n }\n </select>\n <small>a mock answers one client, matched by name</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Method</span>\n <select #methodSelect (change)=\"patchDraft({ method: methodSelect.value })\" class=\"et-query-devtools-select\">\n @for (method of METHODS; track method) {\n <option [value]=\"method\" [selected]=\"method === form.method\">{{ method }}</option>\n }\n </select>\n <small>matched exactly</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Path</span>\n <input\n #patternInput\n [value]=\"form.pattern\"\n (input)=\"patchDraft({ pattern: patternInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"/posts/:id/comments\"\n />\n <small><code>:name</code> matches any one segment, so the route is mocked rather than one URL</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Query</span>\n <input\n #queryInput\n [value]=\"form.query\"\n (input)=\"patchDraft({ query: queryInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"page=2&limit=10\"\n />\n <small>\n parameters the request must carry; anything else it asks for is ignored. Empty answers whatever the query\n string is - and a mock naming parameters wins over one that does not\n </small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusDraftInput\n [value]=\"form.status\"\n (input)=\"patchDraft({ status: statusDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyDraftInput\n [value]=\"form.latencyMs\"\n (input)=\"patchDraft({ latencyMs: latencyDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles</small>\n </label>\n </div>\n\n @if (hasSchema()) {\n <div class=\"et-query-devtools-seed\">\n <span class=\"et-query-devtools-section\">Seed</span>\n @if (isSchemaReady()) {\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [options]=\"routeOptions()\"\n (pickOption)=\"pickRoute($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n pickOnly\n >\n <input etSelectSearch placeholder=\"search the routes it declares\u2026\" />\n </et-select>\n <button\n (click)=\"seedFromDraftRoute()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Generate a body from what the description says this path returns\"\n >\n From this path\n </button>\n </div>\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [value]=\"pickedSchema()\"\n [options]=\"schemaNameOptions()\"\n (valueChange)=\"pickSchema($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n >\n <input etSelectSearch placeholder=\"search its named types\u2026\" />\n </et-select>\n <button\n [disabled]=\"!pickedSchema()\"\n (click)=\"seedFromSchema()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n From this type\n </button>\n </div>\n <select\n #stylePick\n (change)=\"pickSeedStyle(stylePick.value)\"\n class=\"et-query-devtools-select\"\n title=\"How lifelike the generated values are\"\n >\n @for (style of SEED_STYLES; track style.value) {\n <option [value]=\"style.value\" [selected]=\"style.value === seedStyle()\">{{ style.label }}</option>\n }\n </select>\n <small class=\"et-query-devtools-hint et-query-devtools-seed-hint\">{{ seedStyleHint() }}</small>\n } @else if (schemaError(); as error) {\n <span class=\"et-query-devtools-settings-warn\">The API description could not be loaded: {{ error }}</span>\n } @else {\n <span class=\"et-query-devtools-count\">Loading the API description\u2026</span>\n }\n </div>\n }\n\n <label class=\"et-query-devtools-mock-body\">\n <span class=\"et-query-devtools-section\">Body</span>\n <textarea\n #bodyInput\n [value]=\"form.body\"\n (input)=\"patchDraft({ body: bodyInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-mock-textarea\"\n rows=\"8\"\n spellcheck=\"false\"\n ></textarea>\n </label>\n\n @if (draftSeed(); as seed) {\n <p class=\"et-query-devtools-hint\">\n Generated from the API description{{ seed.schemaName ? ' as ' + seed.schemaName : '' }} - a starting point,\n not the contract. Saving opens the designer on it.\n </p>\n @if (seed.notes.length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of seed.notes; track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n }\n\n @if (draftError(); as error) {\n <p class=\"et-query-devtools-settings-warn\">{{ error }}</p>\n }\n\n <div class=\"et-query-devtools-mock-head\">\n <button (click)=\"saveDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n Save to the library\n </button>\n <button (click)=\"closeDraft()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Designed</strong>\n <span class=\"et-query-devtools-count\">{{ rows().length }} in the library</span>\n @if (rows().length) {\n <div class=\"et-query-devtools-spec-export\">\n <select #formatPick (change)=\"pickSpecFormat(formatPick.value)\" class=\"et-query-devtools-select\">\n @for (format of SPEC_FORMATS; track format.value) {\n <option [value]=\"format.value\" [selected]=\"format.value === specFormat()\">{{ format.label }}</option>\n }\n </select>\n <button\n (click)=\"exportLibrary()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every designed route as one OpenAPI 3.1 document - the response schemas inferred from the designed bodies, each body as an example\"\n >\n <span aria-hidden=\"true\">\u21E9</span>\n Export OpenAPI\n </button>\n </div>\n }\n </div>\n\n @for (row of rows(); track row.mock.id) {\n <div [class.et-query-devtools-mock-row--armed]=\"row.armed\" class=\"et-query-devtools-mock-row\">\n <div class=\"et-query-devtools-mock-head\">\n <button\n [class.et-query-devtools-btn--tampered]=\"row.armed\"\n [attr.aria-pressed]=\"row.armed\"\n (click)=\"toggleArmed(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{ row.armed ? 'Stop serving this response' : 'Serve this response instead of the request' }}\"\n >\n {{ row.armed ? 'Armed' : 'Arm' }}\n </button>\n <span class=\"et-query-devtools-method\">{{ row.mock.method }}</span>\n <span class=\"et-query-devtools-route et-query-devtools-mono\">{{ row.mock.pattern }}</span>\n @if (row.mock.query) {\n <span class=\"et-query-devtools-url\">?{{ row.mock.query }}</span>\n }\n <span class=\"et-query-devtools-url\">{{ row.mock.clientName }}</span>\n @if (row.mock.capturedAt) {\n <span class=\"et-query-devtools-chip\">captured</span>\n }\n @if (row.mock.schemaName; as schemaName) {\n <span class=\"et-query-devtools-chip\" title=\"Seeded from the API description\">{{ schemaName }}</span>\n }\n @if (row.isSecure) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"A mock sends nothing, so no token is attached and the auth flow is never exercised\"\n >\n no auth\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"editBody(row)\" class=\"et-query-devtools-btn\" type=\"button\">Body</button>\n <button\n (click)=\"copyDefinition(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as a @ethlete/query definition - the response type inferred from the body, the args contract and the creator call\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedDefinition.value() === row.mock.id ? 'Copied' : 'TS' }}\n </button>\n <button\n (click)=\"copyPathItem(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as an OpenAPI paths entry, ready to paste under an existing description\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedPathItem.value() === row.mock.id ? 'Copied' : 'OAS' }}\n </button>\n <button (click)=\"remove(row)\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Delete\n </button>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusInput\n [value]=\"row.mock.status\"\n (change)=\"setStatus(row, statusInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error, body and all</small>\n </label>\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyInput\n [value]=\"row.mock.latencyMs\"\n (change)=\"setLatency(row, latencyInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles, so the route still has a loading state</small>\n </label>\n </div>\n\n @if (editingId() === row.mock.id) {\n <et-query-devtools-mock-designer\n [body]=\"row.mock.body\"\n [annotations]=\"editingAnnotations()\"\n (save)=\"saveBody(row, $event)\"\n (dismiss)=\"cancelBody()\"\n />\n }\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">\n Nothing designed yet. <strong>New mock</strong> writes one from scratch; capturing below seeds one from\n something that actually happened.\n </p>\n }\n\n @if (specNotes().length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of specNotes(); track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Capture</strong>\n <span class=\"et-query-devtools-count\">live queries holding a response</span>\n </div>\n\n @for (row of captureRows(); track row.entry.id) {\n <div class=\"et-query-devtools-mock-head\">\n <span class=\"et-query-devtools-method\">{{ row.method }}</span>\n <button\n (click)=\"host.selectQuery(row.entry.id)\"\n class=\"et-query-devtools-route et-query-devtools-mono et-query-devtools-row-link\"\n type=\"button\"\n title=\"Open this query\"\n >\n {{ row.pattern }}\n </button>\n <span class=\"et-query-devtools-url\">{{ row.clientName }}</span>\n @if (row.shared > 1) {\n <span class=\"et-query-devtools-count\" title=\"A mock answers the route, so it answers all of them\">\n {{ row.shared }} queries\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"capture(row)\" class=\"et-query-devtools-btn\" type=\"button\">\n {{ row.exists ? 'Re-capture' : 'Capture' }}\n </button>\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">No live query has a response yet.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-mocks-toolbar{align-items:flex-start}.et-query-devtools-mock-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-mock-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-mock-row--armed{background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-mock-head{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-mock-fields,.et-query-devtools-seed,.et-query-devtools-mock-body{max-inline-size:96rem}.et-query-devtools-mock-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(38rem,1fr));align-items:start;gap:.4rem 1.6rem;padding-block-start:.4rem}.et-query-devtools-mock-fields .et-query-devtools-field{display:grid;grid-template-columns:7rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-mock-fields .et-query-devtools-select{justify-self:start;max-inline-size:100%}.et-query-devtools-mock-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-mock-fields .et-query-devtools-field--wide{grid-column:1 / -1;grid-template-columns:7rem minmax(0,1fr)}.et-query-devtools-spec-export{display:flex;align-items:center;gap:.6rem;margin-inline-start:auto}.et-query-devtools-seed{display:flex;align-items:center;flex-wrap:wrap;gap:.4rem 2.4rem;padding-block-start:.4rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-seed-pick{display:flex;align-items:center;gap:.2rem}.et-query-devtools-seed .et-query-devtools-select{max-inline-size:32rem}.et-query-devtools-combobox{flex:0 1 auto;inline-size:32rem;min-block-size:var(--_et-qdt-control-h);box-sizing:border-box;background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .6rem;font-size:1.15rem}.et-query-devtools-combobox input{background:none;border:0;padding:0;color:inherit;font:inherit}.et-query-devtools-seed-hint{flex-basis:100%;margin:0}.et-query-devtools-mock-body{display:block;padding-block-start:.4rem}.et-query-devtools-mock-textarea{display:block;inline-size:100%;resize:vertical;font-family:inherit;font-size:1.15rem;line-height:1.5;tab-size:2}}\n"], dependencies: [{ kind: "component", type: QueryDevtoolsMockDesignerComponent, selector: "et-query-devtools-mock-designer", inputs: ["body", "annotations", "notes"], outputs: ["save", "dismiss"] }, { kind: "component", type: SelectComponent, selector: "et-select", inputs: ["loadMoreLabel", "addNewLabel", "createLabel", "clearable", "clearLabel", "selectAllLabel"] }, { kind: "directive", type: SelectSearchDirective, selector: "input[etSelectSearch]", inputs: ["query"], outputs: ["queryChange"], exportAs: ["etSelectSearch"] }], encapsulation: i0.ViewEncapsulation.None }); }
3585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsSettingsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3586
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsSettingsComponent, isStandalone: true, selector: "et-query-devtools-settings", ngImport: i0, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-settings-toolbar\">\n <p class=\"et-query-devtools-hint\">\n Panel-wide, and kept in <code class=\"et-query-devtools-mono\">localStorage</code> whatever the scopes below say -\n so a scope of <em>none</em> does not erase the choice that set it. Every switch under <strong>Mirrored</strong> is\n the same one its own tab carries.\n </p>\n </div>\n\n @if (apiEnvs().length) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>API environment</strong>\n <span class=\"et-query-devtools-count\">the app's own key, not the panel's - picking reloads the page</span>\n </div>\n\n @for (apiSwitch of apiEnvs(); track apiSwitch.storageKey) {\n @let value = apiEnvValue(apiSwitch);\n @let custom = apiEnvCustomUrl(apiSwitch);\n @let fallback = apiEnvFallback(apiSwitch);\n @let production = apiEnvIsProduction(apiSwitch);\n <div [class.et-query-devtools-settings-api--production]=\"production\" class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ apiSwitch.name }}</span>\n <div class=\"et-query-devtools-btn-group\">\n <button\n [class.et-query-devtools-btn--active]=\"value === null\"\n [class.et-query-devtools-btn--danger]=\"fallback.production\"\n [attr.aria-pressed]=\"value === null\"\n (click)=\"pickApiEnv(apiSwitch, null)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ fallback.production ? '\u26A0 ' : '' }}{{ fallback.label }}\n </button>\n @for (env of apiSwitch.envs; track env.id) {\n <button\n [class.et-query-devtools-btn--active]=\"value === env.id\"\n [class.et-query-devtools-btn--danger]=\"env.production\"\n [attr.aria-pressed]=\"value === env.id\"\n [title]=\"env.url ?? env.id\"\n (click)=\"pickApiEnv(apiSwitch, env.id)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ env.production ? '\u26A0 ' : '' }}{{ env.label ?? env.id }}\n </button>\n }\n </div>\n </div>\n @if (production) {\n <strong class=\"et-query-devtools-settings-api-live\">\n Live data. Every request from this app reaches the real backend.\n </strong>\n }\n <small>\n Written to <span class=\"et-query-devtools-mono\">{{ apiSwitch.storageKey }}</span> in\n <code class=\"et-query-devtools-mono\">localStorage</code>, which the app reads before it boots.\n </small>\n @if (apiSwitch.custom) {\n <label class=\"et-query-devtools-field et-query-devtools-settings-api-url\">\n <span>Base URL</span>\n <input\n #customUrlInput\n [value]=\"custom\"\n (change)=\"setCustomApiUrl(apiSwitch, customUrlInput.value)\"\n class=\"et-query-devtools-input\"\n type=\"url\"\n placeholder=\"http://localhost:8040\"\n />\n <small>A backend none of the buttons above name. Empty goes back to the app's own default.</small>\n </label>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Storage</strong>\n <span class=\"et-query-devtools-count\">what survives a reload, and how long</span>\n </div>\n\n @for (row of SCOPE_ROWS; track row.key) {\n @let scope = scopeOf(row.key);\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ row.label }}</span>\n <div class=\"et-query-devtools-btn-group\">\n @for (option of SCOPES; track option.value) {\n @let unavailable = unavailableReason(row, option.value);\n <button\n [class.et-query-devtools-btn--active]=\"scope === option.value\"\n [attr.aria-pressed]=\"scope === option.value\"\n [disabled]=\"!!unavailable\"\n [title]=\"unavailable\"\n (click)=\"setScope(row.key, option.value)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ option.label }}\n </button>\n }\n <button [title]=\"INDEXED_DB_TITLE\" class=\"et-query-devtools-btn\" type=\"button\" disabled>IndexedDB</button>\n </div>\n </div>\n <small>{{ row.hint }}</small>\n @if (warningFor(row, scope); as warning) {\n <p class=\"et-query-devtools-settings-warn\">\n <span aria-hidden=\"true\">\u26A0</span>\n {{ warning }}\n </p>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Reset devtools</span>\n @if (resetConfirming()) {\n <div class=\"et-query-devtools-btn-group\">\n <button (click)=\"reset()\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Reset everything\n </button>\n <button (click)=\"resetConfirming.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <button (click)=\"resetConfirming.set(true)\" class=\"et-query-devtools-btn\" type=\"button\">Reset\u2026</button>\n }\n </div>\n <small>\n Clears every one of these keys from both stores, whatever the scopes above say, and puts the panel back where it\n ships - layout, filters, selections and pins. The settings on this tab stay.\n </small>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Limits</strong>\n <span class=\"et-query-devtools-count\">how much the panel keeps in memory</span>\n </div>\n\n <div class=\"et-query-devtools-settings-fields\">\n @for (row of LIMIT_ROWS; track row.key) {\n <label class=\"et-query-devtools-field\">\n <span>{{ row.label }}</span>\n <input\n #limitInput\n [value]=\"limitOf(row.key)\"\n [min]=\"row.min\"\n [max]=\"row.max\"\n [step]=\"row.step\"\n (change)=\"setLimit(row.key, limitInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n />\n <small>{{ row.hint }}</small>\n </label>\n }\n\n <label class=\"et-query-devtools-field\">\n <span>Response history</span>\n <input\n #responseHistoryInput\n [value]=\"responseHistory()\"\n (change)=\"setResponseHistory(responseHistoryInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"1\"\n max=\"50\"\n step=\"1\"\n />\n <small>\n bodies each query keeps, which is how far back a response diff can reach. Bodies dominate what the run buffer\n retains, so this is the one limit that costs real memory. Applies to runs from now on.\n @if (settings().responseHistory !== null) {\n <button (click)=\"clearResponseHistory()\" class=\"et-query-devtools-btn\" type=\"button\">\n Back to the app's own value\n </button>\n }\n </small>\n </label>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Mirrored</strong>\n <span class=\"et-query-devtools-count\">the same switches their tabs carry</span>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Queries</span>\n <div class=\"et-query-devtools-btn-group\">\n @let recentFirst = host.queryRecentFirst();\n <button\n [class.et-query-devtools-btn--active]=\"recentFirst\"\n [attr.aria-pressed]=\"recentFirst\"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n recent first\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n tree view\n </button>\n @let gone = showsGoneQueries();\n <button\n [class.et-query-devtools-btn--active]=\"gone\"\n [attr.aria-pressed]=\"gone\"\n (click)=\"toggleGoneQueries()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n list gone\n </button>\n </div>\n </div>\n <small>Sort order, whether the list groups by route path, and whether destroyed queries are listed at all.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Sessions</span>\n <div class=\"et-query-devtools-settings-controls\">\n <span class=\"et-query-devtools-count\">{{ sessionCount() }} stored</span>\n <button\n [disabled]=\"!sessionCount()\"\n (click)=\"FORGET_SESSIONS()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n >\n Forget every session\n </button>\n </div>\n </div>\n <small>\n Drops every stored token pair, every account added in the panel and every credential typed into one. The live\n session is left alone - the Auth tab switches between them.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Events</span>\n <div class=\"et-query-devtools-settings-controls\">\n @let errorsOnly = host.eventErrorsOnly();\n <button\n [class.et-query-devtools-btn--active]=\"errorsOnly\"\n [attr.aria-pressed]=\"errorsOnly\"\n (click)=\"host.eventErrorsOnly.set(!errorsOnly)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n failures only\n </button>\n @let pickedClient = host.eventClient();\n <select\n #eventClientSelect\n (change)=\"host.eventClient.set(eventClientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Event log client\"\n >\n <option [selected]=\"!pickedClient\" value=\"\">All clients</option>\n @for (name of eventClients(); track name) {\n <option [value]=\"name\" [selected]=\"name === pickedClient\">{{ name }}</option>\n }\n </select>\n </div>\n </div>\n <small>What the event log is narrowed to. The log itself always holds every client's traffic.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Response overrides</span>\n @let persist = host.overridesPersist();\n <button\n [class.et-query-devtools-btn--active]=\"persist\"\n [attr.aria-pressed]=\"persist\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Keep across reloads\n </button>\n </div>\n <small>\n The drawer's own toggle, which is the Storage scope above - currently\n <span class=\"et-query-devtools-mono\">{{ host.overridesScopeLabel() }}</span\n >.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Armed</span>\n <div class=\"et-query-devtools-settings-controls\">\n <button\n [disabled]=\"!mockCount() || armedMockCount() === mockCount()\"\n (click)=\"ARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Arm every mock ({{ mockCount() }})\n </button>\n <button\n [disabled]=\"!armedMockCount()\"\n (click)=\"DISARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm mocks ({{ armedMockCount() }})\n </button>\n <button\n [disabled]=\"!armedFaultCount()\"\n (click)=\"DISARM_ALL_FAULTS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm faults ({{ armedFaultCount() }})\n </button>\n </div>\n </div>\n <small>\n The Mocks and Faults tabs' own buttons. Whether either survives a reload is the two <em>Armed</em> scopes above,\n both <em>none</em> unless they were changed.\n </small>\n </div>\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-settings-toolbar{align-items:flex-start}.et-query-devtools-settings-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-settings-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-settings-row-head{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem}.et-query-devtools-settings-controls{display:flex;align-items:center;gap:.5rem}.et-query-devtools-settings-row>small{display:block;max-inline-size:60rem;margin-block-start:.3rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-warn{margin:.4rem 0 0;color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-settings-api--production{background:color-mix(in srgb,var(--_et-qdt-error) 8%,transparent);box-shadow:inset .3rem 0 0 var(--_et-qdt-error);padding-inline-start:.8rem}.et-query-devtools-settings-api-live{display:block;margin-block-start:.4rem;color:var(--_et-qdt-error);font-size:1.2rem}.et-query-devtools-btn--danger.et-query-devtools-btn--active{background:color-mix(in srgb,var(--_et-qdt-error) 28%,transparent);border-color:var(--_et-qdt-error);color:var(--_et-qdt-fg)}@media(prefers-reduced-motion:no-preference){.et-query-devtools-settings-api-live{animation:et-qdt-settings-api-live 1.6s ease-in-out infinite}}@keyframes et-qdt-settings-api-live{0%,to{opacity:.55}50%{opacity:1}}.et-query-devtools-settings-api-url{display:grid;grid-template-columns:auto minmax(0,32rem);align-items:center;margin-block-start:.5rem;gap:.2rem .6rem}.et-query-devtools-settings-api-url small{grid-column:1 / -1;max-inline-size:60rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(24rem,1fr));align-items:start;gap:.8rem 1.6rem}.et-query-devtools-settings-fields .et-query-devtools-field{display:grid;grid-template-columns:11rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-settings-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
3580
3587
  }
3581
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsMocksTabComponent, decorators: [{
3588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsSettingsComponent, decorators: [{
3582
3589
  type: Component,
3583
- args: [{ selector: 'et-query-devtools-mocks-tab', encapsulation: ViewEncapsulation.None, imports: [QueryDevtoolsMockDesignerComponent, SelectComponent, SelectSearchDirective], template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-mocks-toolbar\">\n <p class=\"et-query-devtools-hint\">\n A mock replaces the request, so it answers a route that has never run - or does not exist yet. It bypasses the\n interceptor chain by construction, so a mocked secure route never exercises the token flow. The library is kept;\n whether a mock is <strong>armed</strong> is not, so a reload always stops serving them. GraphQL queries are not\n offered: they all POST one route, so matching them needs the document rather than the path.\n </p>\n <div class=\"et-query-devtools-settings-controls\">\n @if (rows().length && armedCount() < rows().length) {\n <button\n (click)=\"ARM_ALL()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Serve every mock in the library - the whole screen off the network at once\"\n >\n Arm all ({{ rows().length }})\n </button>\n }\n @if (armedCount()) {\n <button (click)=\"DISARM_ALL()\" class=\"et-query-devtools-btn\" type=\"button\">\n Disarm all ({{ armedCount() }})\n </button>\n }\n <button (click)=\"openDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n <span aria-hidden=\"true\">\uFF0B</span>\n New mock\n </button>\n </div>\n </div>\n\n @if (draft(); as form) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>New mock</strong>\n <span class=\"et-query-devtools-count\">for any route, whether a query has ever called it or not</span>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Client</span>\n <select #clientSelect (change)=\"pickClient(clientSelect.value)\" class=\"et-query-devtools-select\">\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\" [selected]=\"name === form.clientName\">{{ name }}</option>\n }\n </select>\n <small>a mock answers one client, matched by name</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Method</span>\n <select #methodSelect (change)=\"patchDraft({ method: methodSelect.value })\" class=\"et-query-devtools-select\">\n @for (method of METHODS; track method) {\n <option [value]=\"method\" [selected]=\"method === form.method\">{{ method }}</option>\n }\n </select>\n <small>matched exactly</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Path</span>\n <input\n #patternInput\n [value]=\"form.pattern\"\n (input)=\"patchDraft({ pattern: patternInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"/posts/:id/comments\"\n />\n <small><code>:name</code> matches any one segment, so the route is mocked rather than one URL</small>\n </label>\n\n <label class=\"et-query-devtools-field et-query-devtools-field--wide\">\n <span>Query</span>\n <input\n #queryInput\n [value]=\"form.query\"\n (input)=\"patchDraft({ query: queryInput.value })\"\n class=\"et-query-devtools-input\"\n type=\"text\"\n placeholder=\"page=2&limit=10\"\n />\n <small>\n parameters the request must carry; anything else it asks for is ignored. Empty answers whatever the query\n string is - and a mock naming parameters wins over one that does not\n </small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusDraftInput\n [value]=\"form.status\"\n (input)=\"patchDraft({ status: statusDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error</small>\n </label>\n\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyDraftInput\n [value]=\"form.latencyMs\"\n (input)=\"patchDraft({ latencyMs: latencyDraftInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles</small>\n </label>\n </div>\n\n @if (hasSchema()) {\n <div class=\"et-query-devtools-seed\">\n <span class=\"et-query-devtools-section\">Seed</span>\n @if (isSchemaReady()) {\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [options]=\"routeOptions()\"\n (pickOption)=\"pickRoute($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n pickOnly\n >\n <input etSelectSearch placeholder=\"search the routes it declares\u2026\" />\n </et-select>\n <button\n (click)=\"seedFromDraftRoute()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Generate a body from what the description says this path returns\"\n >\n From this path\n </button>\n </div>\n <div class=\"et-query-devtools-seed-pick\">\n <et-select\n [value]=\"pickedSchema()\"\n [options]=\"schemaNameOptions()\"\n (valueChange)=\"pickSchema($event)\"\n class=\"et-query-devtools-combobox\"\n mirrorPanelWidth=\"false\"\n >\n <input etSelectSearch placeholder=\"search its named types\u2026\" />\n </et-select>\n <button\n [disabled]=\"!pickedSchema()\"\n (click)=\"seedFromSchema()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n From this type\n </button>\n </div>\n <select\n #stylePick\n (change)=\"pickSeedStyle(stylePick.value)\"\n class=\"et-query-devtools-select\"\n title=\"How lifelike the generated values are\"\n >\n @for (style of SEED_STYLES; track style.value) {\n <option [value]=\"style.value\" [selected]=\"style.value === seedStyle()\">{{ style.label }}</option>\n }\n </select>\n <small class=\"et-query-devtools-hint et-query-devtools-seed-hint\">{{ seedStyleHint() }}</small>\n } @else if (schemaError(); as error) {\n <span class=\"et-query-devtools-settings-warn\">The API description could not be loaded: {{ error }}</span>\n } @else {\n <span class=\"et-query-devtools-count\">Loading the API description\u2026</span>\n }\n </div>\n }\n\n <label class=\"et-query-devtools-mock-body\">\n <span class=\"et-query-devtools-section\">Body</span>\n <textarea\n #bodyInput\n [value]=\"form.body\"\n (input)=\"patchDraft({ body: bodyInput.value })\"\n class=\"et-query-devtools-input et-query-devtools-mock-textarea\"\n rows=\"8\"\n spellcheck=\"false\"\n ></textarea>\n </label>\n\n @if (draftSeed(); as seed) {\n <p class=\"et-query-devtools-hint\">\n Generated from the API description{{ seed.schemaName ? ' as ' + seed.schemaName : '' }} - a starting point,\n not the contract. Saving opens the designer on it.\n </p>\n @if (seed.notes.length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of seed.notes; track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n }\n\n @if (draftError(); as error) {\n <p class=\"et-query-devtools-settings-warn\">{{ error }}</p>\n }\n\n <div class=\"et-query-devtools-mock-head\">\n <button (click)=\"saveDraft()\" class=\"et-query-devtools-btn et-query-devtools-btn--primary\" type=\"button\">\n Save to the library\n </button>\n <button (click)=\"closeDraft()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Designed</strong>\n <span class=\"et-query-devtools-count\">{{ rows().length }} in the library</span>\n @if (rows().length) {\n <div class=\"et-query-devtools-spec-export\">\n <select #formatPick (change)=\"pickSpecFormat(formatPick.value)\" class=\"et-query-devtools-select\">\n @for (format of SPEC_FORMATS; track format.value) {\n <option [value]=\"format.value\" [selected]=\"format.value === specFormat()\">{{ format.label }}</option>\n }\n </select>\n <button\n (click)=\"exportLibrary()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every designed route as one OpenAPI 3.1 document - the response schemas inferred from the designed bodies, each body as an example\"\n >\n <span aria-hidden=\"true\">\u21E9</span>\n Export OpenAPI\n </button>\n </div>\n }\n </div>\n\n @for (row of rows(); track row.mock.id) {\n <div [class.et-query-devtools-mock-row--armed]=\"row.armed\" class=\"et-query-devtools-mock-row\">\n <div class=\"et-query-devtools-mock-head\">\n <button\n [class.et-query-devtools-btn--tampered]=\"row.armed\"\n [attr.aria-pressed]=\"row.armed\"\n (click)=\"toggleArmed(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{ row.armed ? 'Stop serving this response' : 'Serve this response instead of the request' }}\"\n >\n {{ row.armed ? 'Armed' : 'Arm' }}\n </button>\n <span class=\"et-query-devtools-method\">{{ row.mock.method }}</span>\n <span class=\"et-query-devtools-route et-query-devtools-mono\">{{ row.mock.pattern }}</span>\n @if (row.mock.query) {\n <span class=\"et-query-devtools-url\">?{{ row.mock.query }}</span>\n }\n <span class=\"et-query-devtools-url\">{{ row.mock.clientName }}</span>\n @if (row.mock.capturedAt) {\n <span class=\"et-query-devtools-chip\">captured</span>\n }\n @if (row.mock.schemaName; as schemaName) {\n <span class=\"et-query-devtools-chip\" title=\"Seeded from the API description\">{{ schemaName }}</span>\n }\n @if (row.isSecure) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"A mock sends nothing, so no token is attached and the auth flow is never exercised\"\n >\n no auth\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"editBody(row)\" class=\"et-query-devtools-btn\" type=\"button\">Body</button>\n <button\n (click)=\"copyDefinition(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as a @ethlete/query definition - the response type inferred from the body, the args contract and the creator call\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedDefinition.value() === row.mock.id ? 'Copied' : 'TS' }}\n </button>\n <button\n (click)=\"copyPathItem(row)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy this route as an OpenAPI paths entry, ready to paste under an existing description\"\n >\n <span aria-hidden=\"true\">\u29C9</span>\n {{ copiedPathItem.value() === row.mock.id ? 'Copied' : 'OAS' }}\n </button>\n <button (click)=\"remove(row)\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Delete\n </button>\n </div>\n\n <div class=\"et-query-devtools-mock-fields\">\n <label class=\"et-query-devtools-field\">\n <span>Status</span>\n <input\n #statusInput\n [value]=\"row.mock.status\"\n (change)=\"setStatus(row, statusInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"100\"\n max=\"599\"\n step=\"1\"\n />\n <small>400 and above arrive as a real error, body and all</small>\n </label>\n <label class=\"et-query-devtools-field\">\n <span>Latency</span>\n <input\n #latencyInput\n [value]=\"row.mock.latencyMs\"\n (change)=\"setLatency(row, latencyInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"0\"\n max=\"60000\"\n step=\"100\"\n />\n <small>ms before it settles, so the route still has a loading state</small>\n </label>\n </div>\n\n @if (editingId() === row.mock.id) {\n <et-query-devtools-mock-designer\n [body]=\"row.mock.body\"\n [annotations]=\"editingAnnotations()\"\n (save)=\"saveBody(row, $event)\"\n (dismiss)=\"cancelBody()\"\n />\n }\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">\n Nothing designed yet. <strong>New mock</strong> writes one from scratch; capturing below seeds one from\n something that actually happened.\n </p>\n }\n\n @if (specNotes().length) {\n <ul class=\"et-query-devtools-designer-notes\">\n @for (note of specNotes(); track note) {\n <li>{{ note }}</li>\n }\n </ul>\n }\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Capture</strong>\n <span class=\"et-query-devtools-count\">live queries holding a response</span>\n </div>\n\n @for (row of captureRows(); track row.entry.id) {\n <div class=\"et-query-devtools-mock-head\">\n <span class=\"et-query-devtools-method\">{{ row.method }}</span>\n <button\n (click)=\"host.selectQuery(row.entry.id)\"\n class=\"et-query-devtools-route et-query-devtools-mono et-query-devtools-row-link\"\n type=\"button\"\n title=\"Open this query\"\n >\n {{ row.pattern }}\n </button>\n <span class=\"et-query-devtools-url\">{{ row.clientName }}</span>\n @if (row.shared > 1) {\n <span class=\"et-query-devtools-count\" title=\"A mock answers the route, so it answers all of them\">\n {{ row.shared }} queries\n </span>\n }\n <span class=\"et-query-devtools-count\">{{ host.formatBytes(row.bytes) }}</span>\n <button (click)=\"capture(row)\" class=\"et-query-devtools-btn\" type=\"button\">\n {{ row.exists ? 'Re-capture' : 'Capture' }}\n </button>\n </div>\n } @empty {\n <p class=\"et-query-devtools-empty\">No live query has a response yet.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-mocks-toolbar{align-items:flex-start}.et-query-devtools-mock-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-mock-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-mock-row--armed{background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-mock-head{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-mock-fields,.et-query-devtools-seed,.et-query-devtools-mock-body{max-inline-size:96rem}.et-query-devtools-mock-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(38rem,1fr));align-items:start;gap:.4rem 1.6rem;padding-block-start:.4rem}.et-query-devtools-mock-fields .et-query-devtools-field{display:grid;grid-template-columns:7rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-mock-fields .et-query-devtools-select{justify-self:start;max-inline-size:100%}.et-query-devtools-mock-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-mock-fields .et-query-devtools-field--wide{grid-column:1 / -1;grid-template-columns:7rem minmax(0,1fr)}.et-query-devtools-spec-export{display:flex;align-items:center;gap:.6rem;margin-inline-start:auto}.et-query-devtools-seed{display:flex;align-items:center;flex-wrap:wrap;gap:.4rem 2.4rem;padding-block-start:.4rem;min-block-size:var(--_et-qdt-row-h)}.et-query-devtools-seed-pick{display:flex;align-items:center;gap:.2rem}.et-query-devtools-seed .et-query-devtools-select{max-inline-size:32rem}.et-query-devtools-combobox{flex:0 1 auto;inline-size:32rem;min-block-size:var(--_et-qdt-control-h);box-sizing:border-box;background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .6rem;font-size:1.15rem}.et-query-devtools-combobox input{background:none;border:0;padding:0;color:inherit;font:inherit}.et-query-devtools-seed-hint{flex-basis:100%;margin:0}.et-query-devtools-mock-body{display:block;padding-block-start:.4rem}.et-query-devtools-mock-textarea{display:block;inline-size:100%;resize:vertical;font-family:inherit;font-size:1.15rem;line-height:1.5;tab-size:2}}\n"] }]
3584
- }], ctorParameters: () => [] });
3590
+ args: [{ selector: 'et-query-devtools-settings', encapsulation: ViewEncapsulation.None, template: "<div class=\"et-query-devtools-scroll\">\n <div class=\"et-query-devtools-toolbar et-query-devtools-settings-toolbar\">\n <p class=\"et-query-devtools-hint\">\n Panel-wide, and kept in <code class=\"et-query-devtools-mono\">localStorage</code> whatever the scopes below say -\n so a scope of <em>none</em> does not erase the choice that set it. Every switch under <strong>Mirrored</strong> is\n the same one its own tab carries.\n </p>\n </div>\n\n @if (apiEnvs().length) {\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>API environment</strong>\n <span class=\"et-query-devtools-count\">the app's own key, not the panel's - picking reloads the page</span>\n </div>\n\n @for (apiSwitch of apiEnvs(); track apiSwitch.storageKey) {\n @let value = apiEnvValue(apiSwitch);\n @let custom = apiEnvCustomUrl(apiSwitch);\n @let fallback = apiEnvFallback(apiSwitch);\n @let production = apiEnvIsProduction(apiSwitch);\n <div [class.et-query-devtools-settings-api--production]=\"production\" class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ apiSwitch.name }}</span>\n <div class=\"et-query-devtools-btn-group\">\n <button\n [class.et-query-devtools-btn--active]=\"value === null\"\n [class.et-query-devtools-btn--danger]=\"fallback.production\"\n [attr.aria-pressed]=\"value === null\"\n (click)=\"pickApiEnv(apiSwitch, null)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ fallback.production ? '\u26A0 ' : '' }}{{ fallback.label }}\n </button>\n @for (env of apiSwitch.envs; track env.id) {\n <button\n [class.et-query-devtools-btn--active]=\"value === env.id\"\n [class.et-query-devtools-btn--danger]=\"env.production\"\n [attr.aria-pressed]=\"value === env.id\"\n [title]=\"env.url ?? env.id\"\n (click)=\"pickApiEnv(apiSwitch, env.id)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ env.production ? '\u26A0 ' : '' }}{{ env.label ?? env.id }}\n </button>\n }\n </div>\n </div>\n @if (production) {\n <strong class=\"et-query-devtools-settings-api-live\">\n Live data. Every request from this app reaches the real backend.\n </strong>\n }\n <small>\n Written to <span class=\"et-query-devtools-mono\">{{ apiSwitch.storageKey }}</span> in\n <code class=\"et-query-devtools-mono\">localStorage</code>, which the app reads before it boots.\n </small>\n @if (apiSwitch.custom) {\n <label class=\"et-query-devtools-field et-query-devtools-settings-api-url\">\n <span>Base URL</span>\n <input\n #customUrlInput\n [value]=\"custom\"\n (change)=\"setCustomApiUrl(apiSwitch, customUrlInput.value)\"\n class=\"et-query-devtools-input\"\n type=\"url\"\n placeholder=\"http://localhost:8040\"\n />\n <small>A backend none of the buttons above name. Empty goes back to the app's own default.</small>\n </label>\n }\n </div>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Storage</strong>\n <span class=\"et-query-devtools-count\">what survives a reload, and how long</span>\n </div>\n\n @for (row of SCOPE_ROWS; track row.key) {\n @let scope = scopeOf(row.key);\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>{{ row.label }}</span>\n <div class=\"et-query-devtools-btn-group\">\n @for (option of SCOPES; track option.value) {\n @let unavailable = unavailableReason(row, option.value);\n <button\n [class.et-query-devtools-btn--active]=\"scope === option.value\"\n [attr.aria-pressed]=\"scope === option.value\"\n [disabled]=\"!!unavailable\"\n [title]=\"unavailable\"\n (click)=\"setScope(row.key, option.value)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ option.label }}\n </button>\n }\n <button [title]=\"INDEXED_DB_TITLE\" class=\"et-query-devtools-btn\" type=\"button\" disabled>IndexedDB</button>\n </div>\n </div>\n <small>{{ row.hint }}</small>\n @if (warningFor(row, scope); as warning) {\n <p class=\"et-query-devtools-settings-warn\">\n <span aria-hidden=\"true\">\u26A0</span>\n {{ warning }}\n </p>\n }\n </div>\n }\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Reset devtools</span>\n @if (resetConfirming()) {\n <div class=\"et-query-devtools-btn-group\">\n <button (click)=\"reset()\" class=\"et-query-devtools-btn et-query-devtools-btn--danger\" type=\"button\">\n Reset everything\n </button>\n <button (click)=\"resetConfirming.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <button (click)=\"resetConfirming.set(true)\" class=\"et-query-devtools-btn\" type=\"button\">Reset\u2026</button>\n }\n </div>\n <small>\n Clears every one of these keys from both stores, whatever the scopes above say, and puts the panel back where it\n ships - layout, filters, selections and pins. The settings on this tab stay.\n </small>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Limits</strong>\n <span class=\"et-query-devtools-count\">how much the panel keeps in memory</span>\n </div>\n\n <div class=\"et-query-devtools-settings-fields\">\n @for (row of LIMIT_ROWS; track row.key) {\n <label class=\"et-query-devtools-field\">\n <span>{{ row.label }}</span>\n <input\n #limitInput\n [value]=\"limitOf(row.key)\"\n [min]=\"row.min\"\n [max]=\"row.max\"\n [step]=\"row.step\"\n (change)=\"setLimit(row.key, limitInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n />\n <small>{{ row.hint }}</small>\n </label>\n }\n\n <label class=\"et-query-devtools-field\">\n <span>Response history</span>\n <input\n #responseHistoryInput\n [value]=\"responseHistory()\"\n (change)=\"setResponseHistory(responseHistoryInput.value)\"\n class=\"et-query-devtools-input et-query-devtools-input--number\"\n type=\"number\"\n min=\"1\"\n max=\"50\"\n step=\"1\"\n />\n <small>\n bodies each query keeps, which is how far back a response diff can reach. Bodies dominate what the run buffer\n retains, so this is the one limit that costs real memory. Applies to runs from now on.\n @if (settings().responseHistory !== null) {\n <button (click)=\"clearResponseHistory()\" class=\"et-query-devtools-btn\" type=\"button\">\n Back to the app's own value\n </button>\n }\n </small>\n </label>\n </div>\n </div>\n\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <strong>Mirrored</strong>\n <span class=\"et-query-devtools-count\">the same switches their tabs carry</span>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Queries</span>\n <div class=\"et-query-devtools-btn-group\">\n @let recentFirst = host.queryRecentFirst();\n <button\n [class.et-query-devtools-btn--active]=\"recentFirst\"\n [attr.aria-pressed]=\"recentFirst\"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n recent first\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n tree view\n </button>\n @let gone = showsGoneQueries();\n <button\n [class.et-query-devtools-btn--active]=\"gone\"\n [attr.aria-pressed]=\"gone\"\n (click)=\"toggleGoneQueries()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n list gone\n </button>\n </div>\n </div>\n <small>Sort order, whether the list groups by route path, and whether destroyed queries are listed at all.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Sessions</span>\n <div class=\"et-query-devtools-settings-controls\">\n <span class=\"et-query-devtools-count\">{{ sessionCount() }} stored</span>\n <button\n [disabled]=\"!sessionCount()\"\n (click)=\"FORGET_SESSIONS()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n >\n Forget every session\n </button>\n </div>\n </div>\n <small>\n Drops every stored token pair, every account added in the panel and every credential typed into one. The live\n session is left alone - the Auth tab switches between them.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Events</span>\n <div class=\"et-query-devtools-settings-controls\">\n @let errorsOnly = host.eventErrorsOnly();\n <button\n [class.et-query-devtools-btn--active]=\"errorsOnly\"\n [attr.aria-pressed]=\"errorsOnly\"\n (click)=\"host.eventErrorsOnly.set(!errorsOnly)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n failures only\n </button>\n @let pickedClient = host.eventClient();\n <select\n #eventClientSelect\n (change)=\"host.eventClient.set(eventClientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Event log client\"\n >\n <option [selected]=\"!pickedClient\" value=\"\">All clients</option>\n @for (name of eventClients(); track name) {\n <option [value]=\"name\" [selected]=\"name === pickedClient\">{{ name }}</option>\n }\n </select>\n </div>\n </div>\n <small>What the event log is narrowed to. The log itself always holds every client's traffic.</small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Response overrides</span>\n @let persist = host.overridesPersist();\n <button\n [class.et-query-devtools-btn--active]=\"persist\"\n [attr.aria-pressed]=\"persist\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Keep across reloads\n </button>\n </div>\n <small>\n The drawer's own toggle, which is the Storage scope above - currently\n <span class=\"et-query-devtools-mono\">{{ host.overridesScopeLabel() }}</span\n >.\n </small>\n </div>\n\n <div class=\"et-query-devtools-settings-row\">\n <div class=\"et-query-devtools-settings-row-head\">\n <span>Armed</span>\n <div class=\"et-query-devtools-settings-controls\">\n <button\n [disabled]=\"!mockCount() || armedMockCount() === mockCount()\"\n (click)=\"ARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Arm every mock ({{ mockCount() }})\n </button>\n <button\n [disabled]=\"!armedMockCount()\"\n (click)=\"DISARM_ALL_MOCKS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm mocks ({{ armedMockCount() }})\n </button>\n <button\n [disabled]=\"!armedFaultCount()\"\n (click)=\"DISARM_ALL_FAULTS()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Disarm faults ({{ armedFaultCount() }})\n </button>\n </div>\n </div>\n <small>\n The Mocks and Faults tabs' own buttons. Whether either survives a reload is the two <em>Armed</em> scopes above,\n both <em>none</em> unless they were changed.\n </small>\n </div>\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-settings-toolbar{align-items:flex-start}.et-query-devtools-settings-row{padding-block:.6rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-card>.et-query-devtools-settings-row:first-of-type{border-block-start:0;padding-block-start:0}.et-query-devtools-settings-row-head{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem}.et-query-devtools-settings-controls{display:flex;align-items:center;gap:.5rem}.et-query-devtools-settings-row>small{display:block;max-inline-size:60rem;margin-block-start:.3rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-warn{margin:.4rem 0 0;color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-settings-api--production{background:color-mix(in srgb,var(--_et-qdt-error) 8%,transparent);box-shadow:inset .3rem 0 0 var(--_et-qdt-error);padding-inline-start:.8rem}.et-query-devtools-settings-api-live{display:block;margin-block-start:.4rem;color:var(--_et-qdt-error);font-size:1.2rem}.et-query-devtools-btn--danger.et-query-devtools-btn--active{background:color-mix(in srgb,var(--_et-qdt-error) 28%,transparent);border-color:var(--_et-qdt-error);color:var(--_et-qdt-fg)}@media(prefers-reduced-motion:no-preference){.et-query-devtools-settings-api-live{animation:et-qdt-settings-api-live 1.6s ease-in-out infinite}}@keyframes et-qdt-settings-api-live{0%,to{opacity:.55}50%{opacity:1}}.et-query-devtools-settings-api-url{display:grid;grid-template-columns:auto minmax(0,32rem);align-items:center;margin-block-start:.5rem;gap:.2rem .6rem}.et-query-devtools-settings-api-url small{grid-column:1 / -1;max-inline-size:60rem;color:var(--_et-qdt-subtle);font-size:1.1rem}.et-query-devtools-settings-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(24rem,1fr));align-items:start;gap:.8rem 1.6rem}.et-query-devtools-settings-fields .et-query-devtools-field{display:grid;grid-template-columns:11rem minmax(0,1fr);align-items:baseline;row-gap:.2rem;color:var(--_et-qdt-fg)}.et-query-devtools-settings-fields .et-query-devtools-field small{grid-column:2;color:var(--_et-qdt-subtle);font-size:1.1rem}}\n"] }]
3591
+ }] });
3585
3592
 
3586
3593
  /** The Faults tab: arms latency/failure injection per client - in-memory only, not persisted. */
3587
3594
  class QueryDevtoolsFaultsTabComponent {
@@ -3739,7 +3746,7 @@ const summarizeLocks = (options) => {
3739
3746
 
3740
3747
  // Generated from package.json by tools/scripts/generate-version.js - do not edit.
3741
3748
  /** The version of `@ethlete/query-devtools` this build was cut from. */
3742
- const QUERY_DEVTOOLS_VERSION = '1.0.0-next.14';
3749
+ const QUERY_DEVTOOLS_VERSION = '1.0.0-next.16';
3743
3750
 
3744
3751
  /**
3745
3752
  * How deep a value is walked before it is replaced by a marker, and how much of a long string or a long
@@ -4223,11 +4230,13 @@ const flattenQueryPathTree = (tree, options) => {
4223
4230
  class QueryDevtoolsQueriesTabComponent {
4224
4231
  constructor() {
4225
4232
  this.host = injectQueryDevtoolsHost();
4233
+ this.devtoolsEnabled = isQueryDevtoolsEnabled();
4226
4234
  /** The status chips above the list, in the order a problem is usually looked for. */
4227
4235
  this.facets = [
4228
4236
  { id: 'error', label: 'Failing' },
4229
4237
  { id: 'loading', label: 'Loading' },
4230
4238
  { id: 'stale', label: 'Stale' },
4239
+ { id: 'parked', label: 'Parked' },
4231
4240
  { id: 'idle', label: 'Idle' },
4232
4241
  { id: 'gone', label: 'Gone' },
4233
4242
  ];
@@ -4250,7 +4259,7 @@ class QueryDevtoolsQueriesTabComponent {
4250
4259
  // Staleness is a `Date.now()` comparison and deliberately not reactive, so the clock is what makes
4251
4260
  // the counts age with it - without it a chip would keep the number it happened to be built with.
4252
4261
  this.host.clock();
4253
- const counts = { error: 0, loading: 0, stale: 0, idle: 0, gone: 0 };
4262
+ const counts = { error: 0, loading: 0, stale: 0, parked: 0, idle: 0, gone: 0 };
4254
4263
  for (const { entry, query } of this.searchedQueries()) {
4255
4264
  // A tombstone's frozen state is not live state: counting it as failing or idle would put a query
4256
4265
  // that no longer exists into the numbers the panel is read for.
@@ -4263,6 +4272,8 @@ class QueryDevtoolsQueriesTabComponent {
4263
4272
  counts.error++;
4264
4273
  if (status === 'loading')
4265
4274
  counts.loading++;
4275
+ if (status === 'parked')
4276
+ counts.parked++;
4266
4277
  if (status === 'idle')
4267
4278
  counts.idle++;
4268
4279
  if (this.host.isStale(query))
@@ -4417,6 +4428,8 @@ class QueryDevtoolsQueriesTabComponent {
4417
4428
  return 'loading';
4418
4429
  if (statuses.includes('success'))
4419
4430
  return 'success';
4431
+ if (statuses.includes('parked'))
4432
+ return 'parked';
4420
4433
  return 'idle';
4421
4434
  }
4422
4435
  isGroupStale(group) {
@@ -4488,6 +4501,7 @@ class QueryDevtoolsQueriesTabComponent {
4488
4501
  const status = this.host.queryStatus(item.query);
4489
4502
  return ((facets.has('error') && status === 'error') ||
4490
4503
  (facets.has('loading') && status === 'loading') ||
4504
+ (facets.has('parked') && status === 'parked') ||
4491
4505
  (facets.has('idle') && status === 'idle') ||
4492
4506
  (facets.has('stale') && this.host.isStale(item.query)));
4493
4507
  }
@@ -4534,11 +4548,11 @@ class QueryDevtoolsQueriesTabComponent {
4534
4548
  return parts.join(' ').toLowerCase();
4535
4549
  }
4536
4550
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsQueriesTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4537
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsQueriesTabComponent, isStandalone: true, selector: "et-query-devtools-queries-tab", ngImport: i0, template: "<div #panes class=\"et-query-devtools-master-detail\">\n <div class=\"et-query-devtools-list\">\n <div [class.et-query-devtools-toolbar--filtered]=\"!!host.inspectFilterIds()\" class=\"et-query-devtools-toolbar\">\n <div class=\"et-query-devtools-toolbar-row\">\n <input\n #queryFilterInput\n [value]=\"host.queryFilter()\"\n (input)=\"host.queryFilter.set(queryFilterInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter method / route / url\u2026\"\n aria-label=\"Filter queries\"\n />\n @if (host.inspectFilterIds(); as ids) {\n <span class=\"et-query-devtools-filter-chip\">\n <span class=\"et-query-devtools-filter-icon\" aria-hidden=\"true\">\u2316</span>\n Inspected element\n <span class=\"et-query-devtools-filter-count\">{{ ids.length }}</span>\n </span>\n <button\n (click)=\"host.clearInspectFilter()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the inspection filter and show all queries\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n Clear\n </button>\n } @else {\n <select\n #clientSelect\n [value]=\"host.selectedClientName() ?? ''\"\n (change)=\"host.selectClient(clientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Client\"\n >\n <option value=\"\">All clients</option>\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n }\n <span class=\"et-query-devtools-count\">\n @if (isQueryListNarrowed()) {\n {{ filteredQueries().length }} of {{ scopedQueryCount() }}\n } @else {\n {{ scopedQueryCount() }}\n }\n </span>\n <button\n [disabled]=\"!filteredQueries().length\"\n (click)=\"downloadInsomniaCollection()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download the listed queries as an Insomnia collection, with the auth provider's token refresh\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Insomnia\n </button>\n </div>\n\n <div class=\"et-query-devtools-toolbar-row\">\n @let recentFirst = host.queryRecentFirst();\n <div class=\"et-query-devtools-btn-group\">\n <button\n [title]=\"\n (recentFirst ? 'Newest run first.' : 'Oldest run first.') +\n ' Click to reverse. Queries that have never run stay at the bottom either way.'\n \"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n recent <span aria-hidden=\"true\">{{ recentFirst ? '\u2193' : '\u2191' }}</span>\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n [title]=\"\n treeView\n ? 'Grouped by route path. Click for the flat list.'\n : 'Flat list. Click to group by route path - segments nothing branches off are folded into one row.'\n \"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2442</span> tree\n </button>\n </div>\n @for (facet of visibleFacets(); track facet.id) {\n <button\n [class.et-query-devtools-facet--active]=\"facet.active\"\n [attr.aria-pressed]=\"facet.active\"\n (click)=\"host.toggleFacet(facet.id)\"\n class=\"et-query-devtools-chip et-query-devtools-facet\"\n type=\"button\"\n >\n {{ facet.label }}\n <span class=\"et-query-devtools-facet-count\">{{ facet.count }}</span>\n </button>\n }\n @let goneListed = listedGoneQueries().length;\n @if (goneListed) {\n <button\n (click)=\"forgetGoneQueries()\"\n class=\"et-query-devtools-forget\"\n type=\"button\"\n title=\"Drop the {{ goneListed }} destroyed queries listed below - they cannot be brought back\"\n >\n Forget {{ goneListed }}\n </button>\n }\n @if (isQueryListNarrowed()) {\n <button\n (click)=\"host.clearQueryFilters()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the search term and the status chips\"\n aria-label=\"Clear filters\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n }\n </div>\n </div>\n\n @if (host.queryTreeView()) {\n @for (row of queryTree(); track row.key) {\n @if (row.kind === 'folder') {\n <div [style.--_et-qdt-tree-depth]=\"row.depth\" class=\"et-query-devtools-row et-query-devtools-row--folder\">\n <button\n [attr.aria-expanded]=\"!row.collapsed\"\n [title]=\"\n (row.collapsed ? 'Expand' : 'Collapse') + ' /' + row.label + ' - ' + row.count + ' queries below it'\n \"\n (click)=\"host.toggleQueryPath(row.key)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ row.collapsed ? '\u25B8' : '\u25BE' }}</span>\n <span class=\"et-query-devtools-folder\">/{{ row.label }}</span>\n <span class=\"et-query-devtools-row-count\">{{ row.count }}</span>\n </button>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"queryGroupBlock\"\n [ngTemplateOutletContext]=\"{ group: row.item, depth: row.depth, trim: row.parentPath }\"\n />\n }\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n } @else {\n @for (group of queryGroups(); track group.key) {\n <ng-container [ngTemplateOutlet]=\"queryGroupBlock\" [ngTemplateOutletContext]=\"{ group, depth: 0, trim: '' }\" />\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n }\n\n <ng-template #emptyList>\n @if (scopedQueryCount()) {\n <p class=\"et-query-devtools-empty\">No query matches the filter \u00B7 {{ scopedQueryCount() }} in scope.</p>\n } @else if (goneQueryCount()) {\n <p class=\"et-query-devtools-empty\">\n No query in scope still exists \u00B7 pick Gone to list the {{ goneQueryCount() }} destroyed.\n </p>\n } @else if (host.inspectFilterIds()) {\n <p class=\"et-query-devtools-empty\">\n The inspected element's queries are no longer registered. Clear the filter.\n </p>\n } @else {\n <p class=\"et-query-devtools-empty\">No queries registered.</p>\n }\n </ng-template>\n\n <ng-template #queryGroupBlock let-group=\"group\" let-depth=\"depth\" let-trim=\"trim\">\n @if (batchEntryOf(group); as batchEntry) {\n <ng-container\n [ngTemplateOutlet]=\"batchGroupBlock\"\n [ngTemplateOutletContext]=\"{ group, batchEntry, depth, trim }\"\n />\n } @else if (group.items.length === 1) {\n <ng-container [ngTemplateOutlet]=\"queryRow\" [ngTemplateOutletContext]=\"{ item: group.head, depth, trim }\" />\n } @else {\n @let expanded = isGroupExpanded(group);\n @let head = group.head;\n @let groupGone = !!head.entry.destroyedAt;\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n [title]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"Inspect this request - all {{\n group.items.length\n }} consumers share it, so any of them answers for it\"\n >\n <span\n [attr.data-status]=\"groupGone ? null : groupStatus(group)\"\n [title]=\"groupGone ? 'destroyed' : groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ head.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(head.entry, head.query)\" [trimPrefix]=\"trim\" />\n </span>\n @if (groupGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"These queries no longer exist - what you see is the last state they held, frozen\"\n >\n gone\n </span>\n }\n @if (!groupGone && isGroupStale(group)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (isGroupTampered(group)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"At least one of these is showing an armed response override or a devtools-injected failure\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Consumers of this one request\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, ordinal: $index + 1, depth, trim }\"\n />\n }\n }\n }\n </ng-template>\n\n <ng-template #batchGroupBlock let-group=\"group\" let-batchEntry=\"batchEntry\" let-depth=\"depth\" let-trim=\"trim\">\n @let batch = host.asBatch(batchEntry);\n @let expanded = isGroupExpanded(group);\n @let toggleLabel =\n (expanded ? 'Collapse' : 'Expand') + ' the ' + group.items.length + ' requests this batch has in flight';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"toggleLabel\"\n [title]=\"toggleLabel\"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"One item of a batch run - {{ batch.completed() }} of {{\n batch.total()\n }} settled. The Batches tab has the whole run.\"\n >\n <span\n [attr.data-status]=\"groupStatus(group)\"\n [title]=\"groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ batchEntry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.batchRouteSegments(batchEntry)\" [trimPrefix]=\"trim\" />\n </span>\n <span\n class=\"et-query-devtools-chip\"\n title=\"Registered by createQueryBatch - inspect the run on the Batches tab\"\n >\n batch {{ batch.completed() }}/{{ batch.total() }}\n </span>\n @if (batch.failed()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--error\">{{ batch.failed() }} failed</span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Requests this batch has in flight\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(group.head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, showRoute: true, depth, trim }\"\n />\n }\n }\n </ng-template>\n\n <ng-template\n #queryRow\n let-item=\"item\"\n let-nested=\"nested\"\n let-showRoute=\"showRoute\"\n let-ordinal=\"ordinal\"\n let-depth=\"depth\"\n let-trim=\"trim\"\n >\n @let isGone = !!item.entry.destroyedAt;\n @let isPinned = host.isQueryPinned(item.entry);\n @let pinLabel = isPinned ? 'Unpin this query' : 'Pin this query to the top of the list';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"host.selectedQueryId() === item.entry.id\"\n [class.et-query-devtools-row--gone]=\"isGone\"\n [class.et-query-devtools-row--nested]=\"nested\"\n class=\"et-query-devtools-row\"\n >\n <button (click)=\"host.selectedQueryId.set(item.entry.id)\" class=\"et-query-devtools-row-select\" type=\"button\">\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\"></span>\n <span\n [attr.data-status]=\"isGone ? null : host.queryStatus(item.query)\"\n [title]=\"isGone ? 'destroyed' : host.queryStatus(item.query)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ item.entry.meta.method }}</span>\n @if (nested && !showRoute) {\n <span class=\"et-query-devtools-consumer\">\n @if (consumerLabel(item); as consumer) {\n &lt;{{ consumer }}&gt;\n } @else {\n created outside a component\n }\n </span>\n <span class=\"et-query-devtools-row-count\">#{{ ordinal }}</span>\n } @else {\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(item.entry, item.query)\" [trimPrefix]=\"trim\" />\n </span>\n }\n @if (isGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"This query no longer exists - what you see is the last state it held, frozen\"\n >\n gone\n </span>\n }\n @if (!isGone && host.requestProgress(item.query)?.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Waiting out a retry backoff before attempt {{ retry.attempt }}\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ retry.attempt }}\n </span>\n }\n @if (!isGone && host.isStale(item.query)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (host.isTampered(item.entry)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"Showing an armed response override or a devtools-injected failure, not what the server actually sent\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(item)) }}</span>\n </button>\n <button\n [class.et-query-devtools-row-pin--active]=\"isPinned\"\n [title]=\"pinLabel\"\n [attr.aria-label]=\"pinLabel\"\n [attr.aria-pressed]=\"isPinned\"\n (click)=\"host.toggleQueryPin(item.entry)\"\n class=\"et-query-devtools-row-pin\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">{{ isPinned ? '\u2605' : '\u2606' }}</span>\n </button>\n </div>\n </ng-template>\n </div>\n\n <div\n (pointerdown)=\"host.startPaneResize($event, { pane: 'list', container: panes })\"\n (dblclick)=\"host.resetPaneSize('list')\"\n class=\"et-query-devtools-pane-resize\"\n title=\"Drag to resize, double-click to reset\"\n aria-hidden=\"true\"\n ></div>\n\n <div class=\"et-query-devtools-detail\">\n @if (host.selectedQuery(); as sel) {\n <et-query-devtools-detail [sel]=\"sel\" />\n } @else {\n <p class=\"et-query-devtools-empty\">Select a query to inspect it.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-master-detail{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-list{flex:0 0 var(--_et-qdt-list-width, 34%);min-inline-size:var(--_et-qdt-list-width, 22rem);max-inline-size:var(--_et-qdt-list-width, 40rem);overflow-y:auto;border-inline-end:1px solid var(--_et-qdt-border)}.et-query-devtools-forget{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid color-mix(in srgb,var(--_et-qdt-error) 50%,transparent);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-error) 10%,transparent);color:var(--_et-qdt-error);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-forget:hover{border-color:var(--_et-qdt-error);background:color-mix(in srgb,var(--_et-qdt-error) 22%,transparent)}}.et-query-devtools-list .et-query-devtools-toolbar-row .et-query-devtools-search{flex:1 1 100%}.et-query-devtools-toolbar--filtered{background:linear-gradient(to right,color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent),transparent 65%),var(--_et-qdt-bg);box-shadow:inset .2rem 0 0 var(--_et-qdt-accent),inset 0 -1px color-mix(in srgb,var(--_et-qdt-accent) 30%,transparent)}.et-query-devtools-row-select{display:flex;flex:1 1 auto;align-items:center;gap:.8rem;min-inline-size:0;text-align:start;appearance:none;border:none;background:transparent;color:inherit;padding:.8rem;cursor:pointer;font:inherit}.et-query-devtools-row-select>.et-query-devtools-chip{padding-block:.1rem;line-height:1.2}.et-query-devtools-row-pin{display:flex;flex:0 0 auto;align-self:center;align-items:center;justify-content:center;inline-size:3.2rem;block-size:3.2rem;margin-inline-end:.4rem;appearance:none;border:none;border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font-family:inherit;font-size:1.8rem;line-height:1;opacity:0}.et-query-devtools-row-pin:focus-visible,.et-query-devtools-row-pin--active{opacity:1}@media(hover:hover){.et-query-devtools-row:hover .et-query-devtools-row-pin{opacity:1}}@media(hover:none){.et-query-devtools-row-pin{opacity:1}}@media(hover:hover){.et-query-devtools-row-pin:hover{background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-row-pin--active,.et-query-devtools-row-pin--active:hover{color:var(--_et-qdt-accent)}.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row--gone{color:var(--_et-qdt-muted)}.et-query-devtools-row-caret{flex:0 0 auto;inline-size:1rem;color:var(--_et-qdt-subtle);font-size:1rem;line-height:1}.et-query-devtools-row-caret-btn{display:flex;flex:0 0 auto;align-items:center;appearance:none;border:none;background:transparent;color:inherit;cursor:pointer;padding-block:0;padding-inline:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem) 0;font:inherit}@media(hover:hover){.et-query-devtools-row-caret-btn:hover .et-query-devtools-row-caret{color:var(--_et-qdt-fg)}}.et-query-devtools-row>.et-query-devtools-row-select{padding-inline-start:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--nested>.et-query-devtools-row-select{padding-inline-start:calc(2.6rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--group>.et-query-devtools-row-select{padding-inline:.8rem 4.4rem}.et-query-devtools-consumer{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--folder{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-folder{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--group{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-row--group.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row-count{flex:0 0 auto;color:var(--_et-qdt-subtle);font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-row-time{flex:0 0 auto;inline-size:8ch;text-align:end;color:var(--_et-qdt-subtle);font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-sort{flex:0 0 auto;color:var(--_et-qdt-muted)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QueryDevtoolsDetailComponent, selector: "et-query-devtools-detail", inputs: ["sel"] }, { kind: "component", type: QueryDevtoolsRouteComponent, selector: "et-query-devtools-route", inputs: ["segments", "fallback", "trimPrefix"] }], encapsulation: i0.ViewEncapsulation.None }); }
4551
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsQueriesTabComponent, isStandalone: true, selector: "et-query-devtools-queries-tab", ngImport: i0, template: "<div #panes class=\"et-query-devtools-master-detail\">\n <div class=\"et-query-devtools-list\">\n <div [class.et-query-devtools-toolbar--filtered]=\"!!host.inspectFilterIds()\" class=\"et-query-devtools-toolbar\">\n <div class=\"et-query-devtools-toolbar-row\">\n <input\n #queryFilterInput\n [value]=\"host.queryFilter()\"\n (input)=\"host.queryFilter.set(queryFilterInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter method / route / url\u2026\"\n aria-label=\"Filter queries\"\n />\n @if (host.inspectFilterIds(); as ids) {\n <span class=\"et-query-devtools-filter-chip\">\n <span class=\"et-query-devtools-filter-icon\" aria-hidden=\"true\">\u2316</span>\n Inspected element\n <span class=\"et-query-devtools-filter-count\">{{ ids.length }}</span>\n </span>\n <button\n (click)=\"host.clearInspectFilter()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the inspection filter and show all queries\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n Clear\n </button>\n } @else {\n <select\n #clientSelect\n [value]=\"host.selectedClientName() ?? ''\"\n (change)=\"host.selectClient(clientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Client\"\n >\n <option value=\"\">All clients</option>\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n }\n <span class=\"et-query-devtools-count\">\n @if (isQueryListNarrowed()) {\n {{ filteredQueries().length }} of {{ scopedQueryCount() }}\n } @else {\n {{ scopedQueryCount() }}\n }\n </span>\n <button\n [disabled]=\"!filteredQueries().length\"\n (click)=\"downloadInsomniaCollection()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download the listed queries as an Insomnia collection, with the auth provider's token refresh\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Insomnia\n </button>\n </div>\n\n <div class=\"et-query-devtools-toolbar-row\">\n @let recentFirst = host.queryRecentFirst();\n <div class=\"et-query-devtools-btn-group\">\n <button\n [title]=\"\n (recentFirst ? 'Newest run first.' : 'Oldest run first.') +\n ' Click to reverse. Queries that have never run stay at the bottom either way.'\n \"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n recent <span aria-hidden=\"true\">{{ recentFirst ? '\u2193' : '\u2191' }}</span>\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n [title]=\"\n treeView\n ? 'Grouped by route path. Click for the flat list.'\n : 'Flat list. Click to group by route path - segments nothing branches off are folded into one row.'\n \"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2442</span> tree\n </button>\n </div>\n @for (facet of visibleFacets(); track facet.id) {\n <button\n [class.et-query-devtools-facet--active]=\"facet.active\"\n [attr.aria-pressed]=\"facet.active\"\n (click)=\"host.toggleFacet(facet.id)\"\n class=\"et-query-devtools-chip et-query-devtools-facet\"\n type=\"button\"\n >\n {{ facet.label }}\n <span class=\"et-query-devtools-facet-count\">{{ facet.count }}</span>\n </button>\n }\n @let goneListed = listedGoneQueries().length;\n @if (goneListed) {\n <button\n (click)=\"forgetGoneQueries()\"\n class=\"et-query-devtools-forget\"\n type=\"button\"\n title=\"Drop the {{ goneListed }} destroyed queries listed below - they cannot be brought back\"\n >\n Forget {{ goneListed }}\n </button>\n }\n @if (isQueryListNarrowed()) {\n <button\n (click)=\"host.clearQueryFilters()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the search term and the status chips\"\n aria-label=\"Clear filters\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n }\n </div>\n </div>\n\n @if (host.queryTreeView()) {\n @for (row of queryTree(); track row.key) {\n @if (row.kind === 'folder') {\n <div [style.--_et-qdt-tree-depth]=\"row.depth\" class=\"et-query-devtools-row et-query-devtools-row--folder\">\n <button\n [attr.aria-expanded]=\"!row.collapsed\"\n [title]=\"\n (row.collapsed ? 'Expand' : 'Collapse') + ' /' + row.label + ' - ' + row.count + ' queries below it'\n \"\n (click)=\"host.toggleQueryPath(row.key)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ row.collapsed ? '\u25B8' : '\u25BE' }}</span>\n <span class=\"et-query-devtools-folder\">/{{ row.label }}</span>\n <span class=\"et-query-devtools-row-count\">{{ row.count }}</span>\n </button>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"queryGroupBlock\"\n [ngTemplateOutletContext]=\"{ group: row.item, depth: row.depth, trim: row.parentPath }\"\n />\n }\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n } @else {\n @for (group of queryGroups(); track group.key) {\n <ng-container [ngTemplateOutlet]=\"queryGroupBlock\" [ngTemplateOutletContext]=\"{ group, depth: 0, trim: '' }\" />\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n }\n\n <ng-template #emptyList>\n @if (scopedQueryCount()) {\n <p class=\"et-query-devtools-empty\">No query matches the filter \u00B7 {{ scopedQueryCount() }} in scope.</p>\n } @else if (goneQueryCount()) {\n <p class=\"et-query-devtools-empty\">\n No query in scope still exists \u00B7 pick Gone to list the {{ goneQueryCount() }} destroyed.\n </p>\n } @else if (host.inspectFilterIds()) {\n <p class=\"et-query-devtools-empty\">\n The inspected element's queries are no longer registered. Clear the filter.\n </p>\n } @else if (!devtoolsEnabled) {\n <p class=\"et-query-devtools-empty\">\n No queries registered: provideQueryDevtools() is not in the application providers.\n </p>\n } @else {\n <p class=\"et-query-devtools-empty\">No queries registered.</p>\n }\n </ng-template>\n\n <ng-template #queryGroupBlock let-group=\"group\" let-depth=\"depth\" let-trim=\"trim\">\n @if (batchEntryOf(group); as batchEntry) {\n <ng-container\n [ngTemplateOutlet]=\"batchGroupBlock\"\n [ngTemplateOutletContext]=\"{ group, batchEntry, depth, trim }\"\n />\n } @else if (group.items.length === 1) {\n <ng-container [ngTemplateOutlet]=\"queryRow\" [ngTemplateOutletContext]=\"{ item: group.head, depth, trim }\" />\n } @else {\n @let expanded = isGroupExpanded(group);\n @let head = group.head;\n @let groupGone = !!head.entry.destroyedAt;\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n [title]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"Inspect this request - all {{\n group.items.length\n }} consumers share it, so any of them answers for it\"\n >\n <span\n [attr.data-status]=\"groupGone ? null : groupStatus(group)\"\n [title]=\"groupGone ? 'destroyed' : groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ head.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(head.entry, head.query)\" [trimPrefix]=\"trim\" />\n </span>\n @if (groupGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"These queries no longer exist - what you see is the last state they held, frozen\"\n >\n gone\n </span>\n }\n @if (!groupGone && isGroupStale(group)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (isGroupTampered(group)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"At least one of these is showing an armed response override or a devtools-injected failure\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Consumers of this one request\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, ordinal: $index + 1, depth, trim }\"\n />\n }\n }\n }\n </ng-template>\n\n <ng-template #batchGroupBlock let-group=\"group\" let-batchEntry=\"batchEntry\" let-depth=\"depth\" let-trim=\"trim\">\n @let batch = host.asBatch(batchEntry);\n @let expanded = isGroupExpanded(group);\n @let toggleLabel =\n (expanded ? 'Collapse' : 'Expand') + ' the ' + group.items.length + ' requests this batch has in flight';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"toggleLabel\"\n [title]=\"toggleLabel\"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"One item of a batch run - {{ batch.completed() }} of {{\n batch.total()\n }} settled. The Batches tab has the whole run.\"\n >\n <span\n [attr.data-status]=\"groupStatus(group)\"\n [title]=\"groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ batchEntry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.batchRouteSegments(batchEntry)\" [trimPrefix]=\"trim\" />\n </span>\n <span\n class=\"et-query-devtools-chip\"\n title=\"Registered by createQueryBatch - inspect the run on the Batches tab\"\n >\n batch {{ batch.completed() }}/{{ batch.total() }}\n </span>\n @if (batch.failed()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--error\">{{ batch.failed() }} failed</span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Requests this batch has in flight\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(group.head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, showRoute: true, depth, trim }\"\n />\n }\n }\n </ng-template>\n\n <ng-template\n #queryRow\n let-item=\"item\"\n let-nested=\"nested\"\n let-showRoute=\"showRoute\"\n let-ordinal=\"ordinal\"\n let-depth=\"depth\"\n let-trim=\"trim\"\n >\n @let isGone = !!item.entry.destroyedAt;\n @let isPinned = host.isQueryPinned(item.entry);\n @let pinLabel = isPinned ? 'Unpin this query' : 'Pin this query to the top of the list';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"host.selectedQueryId() === item.entry.id\"\n [class.et-query-devtools-row--gone]=\"isGone\"\n [class.et-query-devtools-row--nested]=\"nested\"\n class=\"et-query-devtools-row\"\n >\n <button (click)=\"host.selectedQueryId.set(item.entry.id)\" class=\"et-query-devtools-row-select\" type=\"button\">\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\"></span>\n <span\n [attr.data-status]=\"isGone ? null : host.queryStatus(item.query)\"\n [title]=\"isGone ? 'destroyed' : host.queryStatus(item.query)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ item.entry.meta.method }}</span>\n @if (nested && !showRoute) {\n <span class=\"et-query-devtools-consumer\">\n @if (consumerLabel(item); as consumer) {\n &lt;{{ consumer }}&gt;\n } @else {\n created outside a component\n }\n </span>\n <span class=\"et-query-devtools-row-count\">#{{ ordinal }}</span>\n } @else {\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(item.entry, item.query)\" [trimPrefix]=\"trim\" />\n </span>\n }\n @if (isGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"This query no longer exists - what you see is the last state it held, frozen\"\n >\n gone\n </span>\n }\n @if (!isGone && host.requestProgress(item.query)?.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Waiting out a retry backoff before attempt {{ retry.attempt }}\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ retry.attempt }}\n </span>\n }\n @if (!isGone && host.isStale(item.query)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (host.isTampered(item.entry)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"Showing an armed response override or a devtools-injected failure, not what the server actually sent\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(item)) }}</span>\n </button>\n <button\n [class.et-query-devtools-row-pin--active]=\"isPinned\"\n [title]=\"pinLabel\"\n [attr.aria-label]=\"pinLabel\"\n [attr.aria-pressed]=\"isPinned\"\n (click)=\"host.toggleQueryPin(item.entry)\"\n class=\"et-query-devtools-row-pin\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">{{ isPinned ? '\u2605' : '\u2606' }}</span>\n </button>\n </div>\n </ng-template>\n </div>\n\n <div\n (pointerdown)=\"host.startPaneResize($event, { pane: 'list', container: panes })\"\n (dblclick)=\"host.resetPaneSize('list')\"\n class=\"et-query-devtools-pane-resize\"\n title=\"Drag to resize, double-click to reset\"\n aria-hidden=\"true\"\n ></div>\n\n <div class=\"et-query-devtools-detail\">\n @if (host.selectedQuery(); as sel) {\n <et-query-devtools-detail [sel]=\"sel\" />\n } @else {\n <p class=\"et-query-devtools-empty\">Select a query to inspect it.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-master-detail{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-list{flex:0 0 var(--_et-qdt-list-width, 34%);min-inline-size:var(--_et-qdt-list-width, 22rem);max-inline-size:var(--_et-qdt-list-width, 40rem);overflow-y:auto;border-inline-end:1px solid var(--_et-qdt-border)}.et-query-devtools-forget{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid color-mix(in srgb,var(--_et-qdt-error) 50%,transparent);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-error) 10%,transparent);color:var(--_et-qdt-error);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-forget:hover{border-color:var(--_et-qdt-error);background:color-mix(in srgb,var(--_et-qdt-error) 22%,transparent)}}.et-query-devtools-list .et-query-devtools-toolbar-row .et-query-devtools-search{flex:1 1 100%}.et-query-devtools-toolbar--filtered{background:linear-gradient(to right,color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent),transparent 65%),var(--_et-qdt-bg);box-shadow:inset .2rem 0 0 var(--_et-qdt-accent),inset 0 -1px color-mix(in srgb,var(--_et-qdt-accent) 30%,transparent)}.et-query-devtools-row-select{display:flex;flex:1 1 auto;align-items:center;gap:.8rem;min-inline-size:0;text-align:start;appearance:none;border:none;background:transparent;color:inherit;padding:.8rem;cursor:pointer;font:inherit}.et-query-devtools-row-select>.et-query-devtools-chip{padding-block:.1rem;line-height:1.2}.et-query-devtools-row-pin{display:flex;flex:0 0 auto;align-self:center;align-items:center;justify-content:center;inline-size:3.2rem;block-size:3.2rem;margin-inline-end:.4rem;appearance:none;border:none;border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font-family:inherit;font-size:1.8rem;line-height:1;opacity:0}.et-query-devtools-row-pin:focus-visible,.et-query-devtools-row-pin--active{opacity:1}@media(hover:hover){.et-query-devtools-row:hover .et-query-devtools-row-pin{opacity:1}}@media(hover:none){.et-query-devtools-row-pin{opacity:1}}@media(hover:hover){.et-query-devtools-row-pin:hover{background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-row-pin--active,.et-query-devtools-row-pin--active:hover{color:var(--_et-qdt-accent)}.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row--gone{color:var(--_et-qdt-muted)}.et-query-devtools-row-caret{flex:0 0 auto;inline-size:1rem;color:var(--_et-qdt-subtle);font-size:1rem;line-height:1}.et-query-devtools-row-caret-btn{display:flex;flex:0 0 auto;align-items:center;appearance:none;border:none;background:transparent;color:inherit;cursor:pointer;padding-block:0;padding-inline:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem) 0;font:inherit}@media(hover:hover){.et-query-devtools-row-caret-btn:hover .et-query-devtools-row-caret{color:var(--_et-qdt-fg)}}.et-query-devtools-row>.et-query-devtools-row-select{padding-inline-start:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--nested>.et-query-devtools-row-select{padding-inline-start:calc(2.6rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--group>.et-query-devtools-row-select{padding-inline:.8rem 4.4rem}.et-query-devtools-consumer{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--folder{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-folder{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--group{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-row--group.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row-count{flex:0 0 auto;color:var(--_et-qdt-subtle);font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-row-time{flex:0 0 auto;inline-size:8ch;text-align:end;color:var(--_et-qdt-subtle);font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-sort{flex:0 0 auto;color:var(--_et-qdt-muted)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QueryDevtoolsDetailComponent, selector: "et-query-devtools-detail", inputs: ["sel"] }, { kind: "component", type: QueryDevtoolsRouteComponent, selector: "et-query-devtools-route", inputs: ["segments", "fallback", "trimPrefix"] }], encapsulation: i0.ViewEncapsulation.None }); }
4538
4552
  }
4539
4553
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsQueriesTabComponent, decorators: [{
4540
4554
  type: Component,
4541
- args: [{ selector: 'et-query-devtools-queries-tab', encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, QueryDevtoolsDetailComponent, QueryDevtoolsRouteComponent], template: "<div #panes class=\"et-query-devtools-master-detail\">\n <div class=\"et-query-devtools-list\">\n <div [class.et-query-devtools-toolbar--filtered]=\"!!host.inspectFilterIds()\" class=\"et-query-devtools-toolbar\">\n <div class=\"et-query-devtools-toolbar-row\">\n <input\n #queryFilterInput\n [value]=\"host.queryFilter()\"\n (input)=\"host.queryFilter.set(queryFilterInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter method / route / url\u2026\"\n aria-label=\"Filter queries\"\n />\n @if (host.inspectFilterIds(); as ids) {\n <span class=\"et-query-devtools-filter-chip\">\n <span class=\"et-query-devtools-filter-icon\" aria-hidden=\"true\">\u2316</span>\n Inspected element\n <span class=\"et-query-devtools-filter-count\">{{ ids.length }}</span>\n </span>\n <button\n (click)=\"host.clearInspectFilter()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the inspection filter and show all queries\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n Clear\n </button>\n } @else {\n <select\n #clientSelect\n [value]=\"host.selectedClientName() ?? ''\"\n (change)=\"host.selectClient(clientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Client\"\n >\n <option value=\"\">All clients</option>\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n }\n <span class=\"et-query-devtools-count\">\n @if (isQueryListNarrowed()) {\n {{ filteredQueries().length }} of {{ scopedQueryCount() }}\n } @else {\n {{ scopedQueryCount() }}\n }\n </span>\n <button\n [disabled]=\"!filteredQueries().length\"\n (click)=\"downloadInsomniaCollection()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download the listed queries as an Insomnia collection, with the auth provider's token refresh\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Insomnia\n </button>\n </div>\n\n <div class=\"et-query-devtools-toolbar-row\">\n @let recentFirst = host.queryRecentFirst();\n <div class=\"et-query-devtools-btn-group\">\n <button\n [title]=\"\n (recentFirst ? 'Newest run first.' : 'Oldest run first.') +\n ' Click to reverse. Queries that have never run stay at the bottom either way.'\n \"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n recent <span aria-hidden=\"true\">{{ recentFirst ? '\u2193' : '\u2191' }}</span>\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n [title]=\"\n treeView\n ? 'Grouped by route path. Click for the flat list.'\n : 'Flat list. Click to group by route path - segments nothing branches off are folded into one row.'\n \"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2442</span> tree\n </button>\n </div>\n @for (facet of visibleFacets(); track facet.id) {\n <button\n [class.et-query-devtools-facet--active]=\"facet.active\"\n [attr.aria-pressed]=\"facet.active\"\n (click)=\"host.toggleFacet(facet.id)\"\n class=\"et-query-devtools-chip et-query-devtools-facet\"\n type=\"button\"\n >\n {{ facet.label }}\n <span class=\"et-query-devtools-facet-count\">{{ facet.count }}</span>\n </button>\n }\n @let goneListed = listedGoneQueries().length;\n @if (goneListed) {\n <button\n (click)=\"forgetGoneQueries()\"\n class=\"et-query-devtools-forget\"\n type=\"button\"\n title=\"Drop the {{ goneListed }} destroyed queries listed below - they cannot be brought back\"\n >\n Forget {{ goneListed }}\n </button>\n }\n @if (isQueryListNarrowed()) {\n <button\n (click)=\"host.clearQueryFilters()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the search term and the status chips\"\n aria-label=\"Clear filters\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n }\n </div>\n </div>\n\n @if (host.queryTreeView()) {\n @for (row of queryTree(); track row.key) {\n @if (row.kind === 'folder') {\n <div [style.--_et-qdt-tree-depth]=\"row.depth\" class=\"et-query-devtools-row et-query-devtools-row--folder\">\n <button\n [attr.aria-expanded]=\"!row.collapsed\"\n [title]=\"\n (row.collapsed ? 'Expand' : 'Collapse') + ' /' + row.label + ' - ' + row.count + ' queries below it'\n \"\n (click)=\"host.toggleQueryPath(row.key)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ row.collapsed ? '\u25B8' : '\u25BE' }}</span>\n <span class=\"et-query-devtools-folder\">/{{ row.label }}</span>\n <span class=\"et-query-devtools-row-count\">{{ row.count }}</span>\n </button>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"queryGroupBlock\"\n [ngTemplateOutletContext]=\"{ group: row.item, depth: row.depth, trim: row.parentPath }\"\n />\n }\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n } @else {\n @for (group of queryGroups(); track group.key) {\n <ng-container [ngTemplateOutlet]=\"queryGroupBlock\" [ngTemplateOutletContext]=\"{ group, depth: 0, trim: '' }\" />\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n }\n\n <ng-template #emptyList>\n @if (scopedQueryCount()) {\n <p class=\"et-query-devtools-empty\">No query matches the filter \u00B7 {{ scopedQueryCount() }} in scope.</p>\n } @else if (goneQueryCount()) {\n <p class=\"et-query-devtools-empty\">\n No query in scope still exists \u00B7 pick Gone to list the {{ goneQueryCount() }} destroyed.\n </p>\n } @else if (host.inspectFilterIds()) {\n <p class=\"et-query-devtools-empty\">\n The inspected element's queries are no longer registered. Clear the filter.\n </p>\n } @else {\n <p class=\"et-query-devtools-empty\">No queries registered.</p>\n }\n </ng-template>\n\n <ng-template #queryGroupBlock let-group=\"group\" let-depth=\"depth\" let-trim=\"trim\">\n @if (batchEntryOf(group); as batchEntry) {\n <ng-container\n [ngTemplateOutlet]=\"batchGroupBlock\"\n [ngTemplateOutletContext]=\"{ group, batchEntry, depth, trim }\"\n />\n } @else if (group.items.length === 1) {\n <ng-container [ngTemplateOutlet]=\"queryRow\" [ngTemplateOutletContext]=\"{ item: group.head, depth, trim }\" />\n } @else {\n @let expanded = isGroupExpanded(group);\n @let head = group.head;\n @let groupGone = !!head.entry.destroyedAt;\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n [title]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"Inspect this request - all {{\n group.items.length\n }} consumers share it, so any of them answers for it\"\n >\n <span\n [attr.data-status]=\"groupGone ? null : groupStatus(group)\"\n [title]=\"groupGone ? 'destroyed' : groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ head.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(head.entry, head.query)\" [trimPrefix]=\"trim\" />\n </span>\n @if (groupGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"These queries no longer exist - what you see is the last state they held, frozen\"\n >\n gone\n </span>\n }\n @if (!groupGone && isGroupStale(group)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (isGroupTampered(group)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"At least one of these is showing an armed response override or a devtools-injected failure\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Consumers of this one request\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, ordinal: $index + 1, depth, trim }\"\n />\n }\n }\n }\n </ng-template>\n\n <ng-template #batchGroupBlock let-group=\"group\" let-batchEntry=\"batchEntry\" let-depth=\"depth\" let-trim=\"trim\">\n @let batch = host.asBatch(batchEntry);\n @let expanded = isGroupExpanded(group);\n @let toggleLabel =\n (expanded ? 'Collapse' : 'Expand') + ' the ' + group.items.length + ' requests this batch has in flight';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"toggleLabel\"\n [title]=\"toggleLabel\"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"One item of a batch run - {{ batch.completed() }} of {{\n batch.total()\n }} settled. The Batches tab has the whole run.\"\n >\n <span\n [attr.data-status]=\"groupStatus(group)\"\n [title]=\"groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ batchEntry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.batchRouteSegments(batchEntry)\" [trimPrefix]=\"trim\" />\n </span>\n <span\n class=\"et-query-devtools-chip\"\n title=\"Registered by createQueryBatch - inspect the run on the Batches tab\"\n >\n batch {{ batch.completed() }}/{{ batch.total() }}\n </span>\n @if (batch.failed()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--error\">{{ batch.failed() }} failed</span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Requests this batch has in flight\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(group.head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, showRoute: true, depth, trim }\"\n />\n }\n }\n </ng-template>\n\n <ng-template\n #queryRow\n let-item=\"item\"\n let-nested=\"nested\"\n let-showRoute=\"showRoute\"\n let-ordinal=\"ordinal\"\n let-depth=\"depth\"\n let-trim=\"trim\"\n >\n @let isGone = !!item.entry.destroyedAt;\n @let isPinned = host.isQueryPinned(item.entry);\n @let pinLabel = isPinned ? 'Unpin this query' : 'Pin this query to the top of the list';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"host.selectedQueryId() === item.entry.id\"\n [class.et-query-devtools-row--gone]=\"isGone\"\n [class.et-query-devtools-row--nested]=\"nested\"\n class=\"et-query-devtools-row\"\n >\n <button (click)=\"host.selectedQueryId.set(item.entry.id)\" class=\"et-query-devtools-row-select\" type=\"button\">\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\"></span>\n <span\n [attr.data-status]=\"isGone ? null : host.queryStatus(item.query)\"\n [title]=\"isGone ? 'destroyed' : host.queryStatus(item.query)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ item.entry.meta.method }}</span>\n @if (nested && !showRoute) {\n <span class=\"et-query-devtools-consumer\">\n @if (consumerLabel(item); as consumer) {\n &lt;{{ consumer }}&gt;\n } @else {\n created outside a component\n }\n </span>\n <span class=\"et-query-devtools-row-count\">#{{ ordinal }}</span>\n } @else {\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(item.entry, item.query)\" [trimPrefix]=\"trim\" />\n </span>\n }\n @if (isGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"This query no longer exists - what you see is the last state it held, frozen\"\n >\n gone\n </span>\n }\n @if (!isGone && host.requestProgress(item.query)?.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Waiting out a retry backoff before attempt {{ retry.attempt }}\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ retry.attempt }}\n </span>\n }\n @if (!isGone && host.isStale(item.query)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (host.isTampered(item.entry)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"Showing an armed response override or a devtools-injected failure, not what the server actually sent\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(item)) }}</span>\n </button>\n <button\n [class.et-query-devtools-row-pin--active]=\"isPinned\"\n [title]=\"pinLabel\"\n [attr.aria-label]=\"pinLabel\"\n [attr.aria-pressed]=\"isPinned\"\n (click)=\"host.toggleQueryPin(item.entry)\"\n class=\"et-query-devtools-row-pin\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">{{ isPinned ? '\u2605' : '\u2606' }}</span>\n </button>\n </div>\n </ng-template>\n </div>\n\n <div\n (pointerdown)=\"host.startPaneResize($event, { pane: 'list', container: panes })\"\n (dblclick)=\"host.resetPaneSize('list')\"\n class=\"et-query-devtools-pane-resize\"\n title=\"Drag to resize, double-click to reset\"\n aria-hidden=\"true\"\n ></div>\n\n <div class=\"et-query-devtools-detail\">\n @if (host.selectedQuery(); as sel) {\n <et-query-devtools-detail [sel]=\"sel\" />\n } @else {\n <p class=\"et-query-devtools-empty\">Select a query to inspect it.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-master-detail{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-list{flex:0 0 var(--_et-qdt-list-width, 34%);min-inline-size:var(--_et-qdt-list-width, 22rem);max-inline-size:var(--_et-qdt-list-width, 40rem);overflow-y:auto;border-inline-end:1px solid var(--_et-qdt-border)}.et-query-devtools-forget{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid color-mix(in srgb,var(--_et-qdt-error) 50%,transparent);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-error) 10%,transparent);color:var(--_et-qdt-error);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-forget:hover{border-color:var(--_et-qdt-error);background:color-mix(in srgb,var(--_et-qdt-error) 22%,transparent)}}.et-query-devtools-list .et-query-devtools-toolbar-row .et-query-devtools-search{flex:1 1 100%}.et-query-devtools-toolbar--filtered{background:linear-gradient(to right,color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent),transparent 65%),var(--_et-qdt-bg);box-shadow:inset .2rem 0 0 var(--_et-qdt-accent),inset 0 -1px color-mix(in srgb,var(--_et-qdt-accent) 30%,transparent)}.et-query-devtools-row-select{display:flex;flex:1 1 auto;align-items:center;gap:.8rem;min-inline-size:0;text-align:start;appearance:none;border:none;background:transparent;color:inherit;padding:.8rem;cursor:pointer;font:inherit}.et-query-devtools-row-select>.et-query-devtools-chip{padding-block:.1rem;line-height:1.2}.et-query-devtools-row-pin{display:flex;flex:0 0 auto;align-self:center;align-items:center;justify-content:center;inline-size:3.2rem;block-size:3.2rem;margin-inline-end:.4rem;appearance:none;border:none;border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font-family:inherit;font-size:1.8rem;line-height:1;opacity:0}.et-query-devtools-row-pin:focus-visible,.et-query-devtools-row-pin--active{opacity:1}@media(hover:hover){.et-query-devtools-row:hover .et-query-devtools-row-pin{opacity:1}}@media(hover:none){.et-query-devtools-row-pin{opacity:1}}@media(hover:hover){.et-query-devtools-row-pin:hover{background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-row-pin--active,.et-query-devtools-row-pin--active:hover{color:var(--_et-qdt-accent)}.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row--gone{color:var(--_et-qdt-muted)}.et-query-devtools-row-caret{flex:0 0 auto;inline-size:1rem;color:var(--_et-qdt-subtle);font-size:1rem;line-height:1}.et-query-devtools-row-caret-btn{display:flex;flex:0 0 auto;align-items:center;appearance:none;border:none;background:transparent;color:inherit;cursor:pointer;padding-block:0;padding-inline:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem) 0;font:inherit}@media(hover:hover){.et-query-devtools-row-caret-btn:hover .et-query-devtools-row-caret{color:var(--_et-qdt-fg)}}.et-query-devtools-row>.et-query-devtools-row-select{padding-inline-start:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--nested>.et-query-devtools-row-select{padding-inline-start:calc(2.6rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--group>.et-query-devtools-row-select{padding-inline:.8rem 4.4rem}.et-query-devtools-consumer{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--folder{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-folder{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--group{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-row--group.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row-count{flex:0 0 auto;color:var(--_et-qdt-subtle);font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-row-time{flex:0 0 auto;inline-size:8ch;text-align:end;color:var(--_et-qdt-subtle);font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-sort{flex:0 0 auto;color:var(--_et-qdt-muted)}}\n"] }]
4555
+ args: [{ selector: 'et-query-devtools-queries-tab', encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, QueryDevtoolsDetailComponent, QueryDevtoolsRouteComponent], template: "<div #panes class=\"et-query-devtools-master-detail\">\n <div class=\"et-query-devtools-list\">\n <div [class.et-query-devtools-toolbar--filtered]=\"!!host.inspectFilterIds()\" class=\"et-query-devtools-toolbar\">\n <div class=\"et-query-devtools-toolbar-row\">\n <input\n #queryFilterInput\n [value]=\"host.queryFilter()\"\n (input)=\"host.queryFilter.set(queryFilterInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter method / route / url\u2026\"\n aria-label=\"Filter queries\"\n />\n @if (host.inspectFilterIds(); as ids) {\n <span class=\"et-query-devtools-filter-chip\">\n <span class=\"et-query-devtools-filter-icon\" aria-hidden=\"true\">\u2316</span>\n Inspected element\n <span class=\"et-query-devtools-filter-count\">{{ ids.length }}</span>\n </span>\n <button\n (click)=\"host.clearInspectFilter()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the inspection filter and show all queries\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n Clear\n </button>\n } @else {\n <select\n #clientSelect\n [value]=\"host.selectedClientName() ?? ''\"\n (change)=\"host.selectClient(clientSelect.value || null)\"\n class=\"et-query-devtools-select\"\n aria-label=\"Client\"\n >\n <option value=\"\">All clients</option>\n @for (name of host.clientNames(); track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n }\n <span class=\"et-query-devtools-count\">\n @if (isQueryListNarrowed()) {\n {{ filteredQueries().length }} of {{ scopedQueryCount() }}\n } @else {\n {{ scopedQueryCount() }}\n }\n </span>\n <button\n [disabled]=\"!filteredQueries().length\"\n (click)=\"downloadInsomniaCollection()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download the listed queries as an Insomnia collection, with the auth provider's token refresh\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Insomnia\n </button>\n </div>\n\n <div class=\"et-query-devtools-toolbar-row\">\n @let recentFirst = host.queryRecentFirst();\n <div class=\"et-query-devtools-btn-group\">\n <button\n [title]=\"\n (recentFirst ? 'Newest run first.' : 'Oldest run first.') +\n ' Click to reverse. Queries that have never run stay at the bottom either way.'\n \"\n (click)=\"host.queryRecentFirst.set(!recentFirst)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n recent <span aria-hidden=\"true\">{{ recentFirst ? '\u2193' : '\u2191' }}</span>\n </button>\n @let treeView = host.queryTreeView();\n <button\n [class.et-query-devtools-btn--active]=\"treeView\"\n [attr.aria-pressed]=\"treeView\"\n [title]=\"\n treeView\n ? 'Grouped by route path. Click for the flat list.'\n : 'Flat list. Click to group by route path - segments nothing branches off are folded into one row.'\n \"\n (click)=\"host.queryTreeView.set(!treeView)\"\n class=\"et-query-devtools-btn et-query-devtools-sort\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2442</span> tree\n </button>\n </div>\n @for (facet of visibleFacets(); track facet.id) {\n <button\n [class.et-query-devtools-facet--active]=\"facet.active\"\n [attr.aria-pressed]=\"facet.active\"\n (click)=\"host.toggleFacet(facet.id)\"\n class=\"et-query-devtools-chip et-query-devtools-facet\"\n type=\"button\"\n >\n {{ facet.label }}\n <span class=\"et-query-devtools-facet-count\">{{ facet.count }}</span>\n </button>\n }\n @let goneListed = listedGoneQueries().length;\n @if (goneListed) {\n <button\n (click)=\"forgetGoneQueries()\"\n class=\"et-query-devtools-forget\"\n type=\"button\"\n title=\"Drop the {{ goneListed }} destroyed queries listed below - they cannot be brought back\"\n >\n Forget {{ goneListed }}\n </button>\n }\n @if (isQueryListNarrowed()) {\n <button\n (click)=\"host.clearQueryFilters()\"\n class=\"et-query-devtools-filter-clear\"\n type=\"button\"\n title=\"Clear the search term and the status chips\"\n aria-label=\"Clear filters\"\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n }\n </div>\n </div>\n\n @if (host.queryTreeView()) {\n @for (row of queryTree(); track row.key) {\n @if (row.kind === 'folder') {\n <div [style.--_et-qdt-tree-depth]=\"row.depth\" class=\"et-query-devtools-row et-query-devtools-row--folder\">\n <button\n [attr.aria-expanded]=\"!row.collapsed\"\n [title]=\"\n (row.collapsed ? 'Expand' : 'Collapse') + ' /' + row.label + ' - ' + row.count + ' queries below it'\n \"\n (click)=\"host.toggleQueryPath(row.key)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ row.collapsed ? '\u25B8' : '\u25BE' }}</span>\n <span class=\"et-query-devtools-folder\">/{{ row.label }}</span>\n <span class=\"et-query-devtools-row-count\">{{ row.count }}</span>\n </button>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"queryGroupBlock\"\n [ngTemplateOutletContext]=\"{ group: row.item, depth: row.depth, trim: row.parentPath }\"\n />\n }\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n } @else {\n @for (group of queryGroups(); track group.key) {\n <ng-container [ngTemplateOutlet]=\"queryGroupBlock\" [ngTemplateOutletContext]=\"{ group, depth: 0, trim: '' }\" />\n } @empty {\n <ng-container [ngTemplateOutlet]=\"emptyList\" />\n }\n }\n\n <ng-template #emptyList>\n @if (scopedQueryCount()) {\n <p class=\"et-query-devtools-empty\">No query matches the filter \u00B7 {{ scopedQueryCount() }} in scope.</p>\n } @else if (goneQueryCount()) {\n <p class=\"et-query-devtools-empty\">\n No query in scope still exists \u00B7 pick Gone to list the {{ goneQueryCount() }} destroyed.\n </p>\n } @else if (host.inspectFilterIds()) {\n <p class=\"et-query-devtools-empty\">\n The inspected element's queries are no longer registered. Clear the filter.\n </p>\n } @else if (!devtoolsEnabled) {\n <p class=\"et-query-devtools-empty\">\n No queries registered: provideQueryDevtools() is not in the application providers.\n </p>\n } @else {\n <p class=\"et-query-devtools-empty\">No queries registered.</p>\n }\n </ng-template>\n\n <ng-template #queryGroupBlock let-group=\"group\" let-depth=\"depth\" let-trim=\"trim\">\n @if (batchEntryOf(group); as batchEntry) {\n <ng-container\n [ngTemplateOutlet]=\"batchGroupBlock\"\n [ngTemplateOutletContext]=\"{ group, batchEntry, depth, trim }\"\n />\n } @else if (group.items.length === 1) {\n <ng-container [ngTemplateOutlet]=\"queryRow\" [ngTemplateOutletContext]=\"{ item: group.head, depth, trim }\" />\n } @else {\n @let expanded = isGroupExpanded(group);\n @let head = group.head;\n @let groupGone = !!head.entry.destroyedAt;\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n [title]=\"\n (expanded ? 'Collapse' : 'Expand') +\n ' the ' +\n group.items.length +\n ' consumers of this query - one registry entry each'\n \"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"Inspect this request - all {{\n group.items.length\n }} consumers share it, so any of them answers for it\"\n >\n <span\n [attr.data-status]=\"groupGone ? null : groupStatus(group)\"\n [title]=\"groupGone ? 'destroyed' : groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ head.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(head.entry, head.query)\" [trimPrefix]=\"trim\" />\n </span>\n @if (groupGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"These queries no longer exist - what you see is the last state they held, frozen\"\n >\n gone\n </span>\n }\n @if (!groupGone && isGroupStale(group)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (isGroupTampered(group)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"At least one of these is showing an armed response override or a devtools-injected failure\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Consumers of this one request\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, ordinal: $index + 1, depth, trim }\"\n />\n }\n }\n }\n </ng-template>\n\n <ng-template #batchGroupBlock let-group=\"group\" let-batchEntry=\"batchEntry\" let-depth=\"depth\" let-trim=\"trim\">\n @let batch = host.asBatch(batchEntry);\n @let expanded = isGroupExpanded(group);\n @let toggleLabel =\n (expanded ? 'Collapse' : 'Expand') + ' the ' + group.items.length + ' requests this batch has in flight';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"holdsSelection(group)\"\n class=\"et-query-devtools-row et-query-devtools-row--group\"\n >\n <button\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-label]=\"toggleLabel\"\n [title]=\"toggleLabel\"\n (click)=\"host.toggleQueryGroup(group.key)\"\n class=\"et-query-devtools-row-caret-btn\"\n type=\"button\"\n >\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\">{{ expanded ? '\u25BE' : '\u25B8' }}</span>\n </button>\n <button\n (click)=\"selectGroup(group)\"\n class=\"et-query-devtools-row-select\"\n type=\"button\"\n title=\"One item of a batch run - {{ batch.completed() }} of {{\n batch.total()\n }} settled. The Batches tab has the whole run.\"\n >\n <span\n [attr.data-status]=\"groupStatus(group)\"\n [title]=\"groupStatus(group)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ batchEntry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.batchRouteSegments(batchEntry)\" [trimPrefix]=\"trim\" />\n </span>\n <span\n class=\"et-query-devtools-chip\"\n title=\"Registered by createQueryBatch - inspect the run on the Batches tab\"\n >\n batch {{ batch.completed() }}/{{ batch.total() }}\n </span>\n @if (batch.failed()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--error\">{{ batch.failed() }} failed</span>\n }\n <span class=\"et-query-devtools-row-count\" title=\"Requests this batch has in flight\">\n \u00D7{{ group.items.length }}\n </span>\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(group.head)) }}</span>\n </button>\n </div>\n @if (expanded) {\n @for (item of group.items; track item.entry.id) {\n <ng-container\n [ngTemplateOutlet]=\"queryRow\"\n [ngTemplateOutletContext]=\"{ item, nested: true, showRoute: true, depth, trim }\"\n />\n }\n }\n </ng-template>\n\n <ng-template\n #queryRow\n let-item=\"item\"\n let-nested=\"nested\"\n let-showRoute=\"showRoute\"\n let-ordinal=\"ordinal\"\n let-depth=\"depth\"\n let-trim=\"trim\"\n >\n @let isGone = !!item.entry.destroyedAt;\n @let isPinned = host.isQueryPinned(item.entry);\n @let pinLabel = isPinned ? 'Unpin this query' : 'Pin this query to the top of the list';\n <div\n [style.--_et-qdt-tree-depth]=\"depth\"\n [class.et-query-devtools-row--active]=\"host.selectedQueryId() === item.entry.id\"\n [class.et-query-devtools-row--gone]=\"isGone\"\n [class.et-query-devtools-row--nested]=\"nested\"\n class=\"et-query-devtools-row\"\n >\n <button (click)=\"host.selectedQueryId.set(item.entry.id)\" class=\"et-query-devtools-row-select\" type=\"button\">\n <span class=\"et-query-devtools-row-caret\" aria-hidden=\"true\"></span>\n <span\n [attr.data-status]=\"isGone ? null : host.queryStatus(item.query)\"\n [title]=\"isGone ? 'destroyed' : host.queryStatus(item.query)\"\n class=\"et-query-devtools-status\"\n ></span>\n <span class=\"et-query-devtools-method\">{{ item.entry.meta.method }}</span>\n @if (nested && !showRoute) {\n <span class=\"et-query-devtools-consumer\">\n @if (consumerLabel(item); as consumer) {\n &lt;{{ consumer }}&gt;\n } @else {\n created outside a component\n }\n </span>\n <span class=\"et-query-devtools-row-count\">#{{ ordinal }}</span>\n } @else {\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(item.entry, item.query)\" [trimPrefix]=\"trim\" />\n </span>\n }\n @if (isGone) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"This query no longer exists - what you see is the last state it held, frozen\"\n >\n gone\n </span>\n }\n @if (!isGone && host.requestProgress(item.query)?.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Waiting out a retry backoff before attempt {{ retry.attempt }}\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ retry.attempt }}\n </span>\n }\n @if (!isGone && host.isStale(item.query)) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">stale</span>\n }\n @if (host.isTampered(item.entry)) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"Showing an armed response override or a devtools-injected failure, not what the server actually sent\"\n >\n tampered\n </span>\n }\n <span class=\"et-query-devtools-row-time\">{{ host.formatTime(lastExecutedAt(item)) }}</span>\n </button>\n <button\n [class.et-query-devtools-row-pin--active]=\"isPinned\"\n [title]=\"pinLabel\"\n [attr.aria-label]=\"pinLabel\"\n [attr.aria-pressed]=\"isPinned\"\n (click)=\"host.toggleQueryPin(item.entry)\"\n class=\"et-query-devtools-row-pin\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">{{ isPinned ? '\u2605' : '\u2606' }}</span>\n </button>\n </div>\n </ng-template>\n </div>\n\n <div\n (pointerdown)=\"host.startPaneResize($event, { pane: 'list', container: panes })\"\n (dblclick)=\"host.resetPaneSize('list')\"\n class=\"et-query-devtools-pane-resize\"\n title=\"Drag to resize, double-click to reset\"\n aria-hidden=\"true\"\n ></div>\n\n <div class=\"et-query-devtools-detail\">\n @if (host.selectedQuery(); as sel) {\n <et-query-devtools-detail [sel]=\"sel\" />\n } @else {\n <p class=\"et-query-devtools-empty\">Select a query to inspect it.</p>\n }\n </div>\n</div>\n", styles: ["@layer components{.et-query-devtools-master-detail{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-list{flex:0 0 var(--_et-qdt-list-width, 34%);min-inline-size:var(--_et-qdt-list-width, 22rem);max-inline-size:var(--_et-qdt-list-width, 40rem);overflow-y:auto;border-inline-end:1px solid var(--_et-qdt-border)}.et-query-devtools-forget{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid color-mix(in srgb,var(--_et-qdt-error) 50%,transparent);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-error) 10%,transparent);color:var(--_et-qdt-error);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-forget:hover{border-color:var(--_et-qdt-error);background:color-mix(in srgb,var(--_et-qdt-error) 22%,transparent)}}.et-query-devtools-list .et-query-devtools-toolbar-row .et-query-devtools-search{flex:1 1 100%}.et-query-devtools-toolbar--filtered{background:linear-gradient(to right,color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent),transparent 65%),var(--_et-qdt-bg);box-shadow:inset .2rem 0 0 var(--_et-qdt-accent),inset 0 -1px color-mix(in srgb,var(--_et-qdt-accent) 30%,transparent)}.et-query-devtools-row-select{display:flex;flex:1 1 auto;align-items:center;gap:.8rem;min-inline-size:0;text-align:start;appearance:none;border:none;background:transparent;color:inherit;padding:.8rem;cursor:pointer;font:inherit}.et-query-devtools-row-select>.et-query-devtools-chip{padding-block:.1rem;line-height:1.2}.et-query-devtools-row-pin{display:flex;flex:0 0 auto;align-self:center;align-items:center;justify-content:center;inline-size:3.2rem;block-size:3.2rem;margin-inline-end:.4rem;appearance:none;border:none;border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font-family:inherit;font-size:1.8rem;line-height:1;opacity:0}.et-query-devtools-row-pin:focus-visible,.et-query-devtools-row-pin--active{opacity:1}@media(hover:hover){.et-query-devtools-row:hover .et-query-devtools-row-pin{opacity:1}}@media(hover:none){.et-query-devtools-row-pin{opacity:1}}@media(hover:hover){.et-query-devtools-row-pin:hover{background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-row-pin--active,.et-query-devtools-row-pin--active:hover{color:var(--_et-qdt-accent)}.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row--gone{color:var(--_et-qdt-muted)}.et-query-devtools-row-caret{flex:0 0 auto;inline-size:1rem;color:var(--_et-qdt-subtle);font-size:1rem;line-height:1}.et-query-devtools-row-caret-btn{display:flex;flex:0 0 auto;align-items:center;appearance:none;border:none;background:transparent;color:inherit;cursor:pointer;padding-block:0;padding-inline:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem) 0;font:inherit}@media(hover:hover){.et-query-devtools-row-caret-btn:hover .et-query-devtools-row-caret{color:var(--_et-qdt-fg)}}.et-query-devtools-row>.et-query-devtools-row-select{padding-inline-start:calc(.8rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--nested>.et-query-devtools-row-select{padding-inline-start:calc(2.6rem + var(--_et-qdt-tree-depth, 0) * 1.4rem)}.et-query-devtools-row--group>.et-query-devtools-row-select{padding-inline:.8rem 4.4rem}.et-query-devtools-consumer{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--folder{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-folder{flex:1 1 auto;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--_et-qdt-muted)}.et-query-devtools-row--group{background:color-mix(in srgb,var(--_et-qdt-interaction) 5%,transparent)}.et-query-devtools-row--group.et-query-devtools-row--active{background:var(--_et-qdt-active)}.et-query-devtools-row-count{flex:0 0 auto;color:var(--_et-qdt-subtle);font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-row-time{flex:0 0 auto;inline-size:8ch;text-align:end;color:var(--_et-qdt-subtle);font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.1rem}.et-query-devtools-sort{flex:0 0 auto;color:var(--_et-qdt-muted)}}\n"] }]
4542
4556
  }], ctorParameters: () => [] });
4543
4557
 
4544
4558
  /**
@@ -4644,6 +4658,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
4644
4658
  ], template: "<div #panes class=\"et-query-devtools-split\">\n <div class=\"et-query-devtools-scroll\">\n @for (entry of host.stackEntries(); track entry.id) {\n @if (entry.kind === 'paged-query-stack') {\n @let paged = host.asPagedStack(entry);\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <span class=\"et-query-devtools-chip\">paged stack</span>\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">{{ paged.direction() }}</span>\n @if (paged.loading()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--loading\">loading</span>\n }\n </div>\n\n @let pagedId = stackIdentity(paged);\n <div class=\"et-query-devtools-card-title\">\n <span class=\"et-query-devtools-method\">{{ pagedId.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"pagedId.segments\" />\n </span>\n </div>\n <div class=\"et-query-devtools-card-sub et-query-devtools-mono\">{{ pagedId.baseUrl }}</div>\n @if (entry.meta.features?.length) {\n <et-query-devtools-features [features]=\"entry.meta.features ?? []\" />\n }\n\n <dl class=\"et-query-devtools-meta\">\n <dt>Pages loaded</dt>\n <dd>{{ paged.queries().length }}</dd>\n <dt>Items</dt>\n <dd>{{ paged.items().length }}</dd>\n <dt>First page loaded</dt>\n <dd>{{ paged.isFirstPageLoaded() }}</dd>\n <dt>Last page loaded</dt>\n <dd>{{ paged.isLastPageLoaded() }}</dd>\n <ng-container *ngTemplateOutlet=\"activityRow; context: { activity: host.stackActivity(paged) }\" />\n </dl>\n <ng-container *ngTemplateOutlet=\"innerQueries; context: { links: host.queriesForStack(paged) }\" />\n </div>\n } @else {\n @let stack = host.asStack(entry);\n <div class=\"et-query-devtools-card\">\n <div class=\"et-query-devtools-card-head\">\n <span class=\"et-query-devtools-chip\">stack</span>\n @if (stack.anyLoading()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--loading\">loading</span>\n }\n @if (stack.anyError()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--error\">error</span>\n }\n </div>\n\n @let stackId = stackIdentity(stack);\n <div class=\"et-query-devtools-card-title\">\n <span class=\"et-query-devtools-method\">{{ stackId.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"stackId.segments\" />\n </span>\n </div>\n <div class=\"et-query-devtools-card-sub et-query-devtools-mono\">{{ stackId.baseUrl }}</div>\n @if (entry.meta.features?.length) {\n <et-query-devtools-features [features]=\"entry.meta.features ?? []\" />\n }\n\n <dl class=\"et-query-devtools-meta\">\n <dt>Queries</dt>\n <dd>{{ stack.queries().length }}</dd>\n <dt>Loading</dt>\n <dd>{{ stack.loadingProgress().loaded }} / {{ stack.loadingProgress().total }}</dd>\n <dt>Errors</dt>\n <dd>{{ stack.errors().length }}</dd>\n <ng-container *ngTemplateOutlet=\"activityRow; context: { activity: host.stackActivity(stack) }\" />\n </dl>\n <ng-container *ngTemplateOutlet=\"innerQueries; context: { links: host.queriesForStack(stack) }\" />\n </div>\n }\n } @empty {\n <p class=\"et-query-devtools-empty\">No stacks registered.</p>\n }\n </div>\n\n <et-query-devtools-drawer\n [sel]=\"host.stackSelectedQuery()\"\n [container]=\"panes\"\n (dismiss)=\"host.stackSelectedQueryId.set(null)\"\n />\n</div>\n\n<ng-template #activityRow let-activity=\"activity\">\n <dt>Traffic</dt>\n <dd>\n @if (activity.hasActivity) {\n {{ activity.stats.requests }} request{{ activity.stats.requests === 1 ? '' : 's' }} \u00B7 \u2193\n {{ host.formatTransferred(activity.stats.receivedBytes, activity.stats.hasEstimatedBytes) }}\n @if (activity.stats.sentBytes) {\n \u00B7 \u2191 {{ host.formatTransferred(activity.stats.sentBytes, activity.stats.hasEstimatedBytes) }}\n }\n @if (activity.cacheServed) {\n \u00B7 {{ activity.cacheServed }} from cache\n }\n @if (activity.stats.errors) {\n \u00B7 {{ activity.stats.errors }} failed\n }\n } @else {\n \u2014\n }\n </dd>\n</ng-template>\n\n<ng-template #innerQueries let-links=\"links\">\n <div class=\"et-query-devtools-inner-queries\">\n @for (link of links; track $index) {\n <button\n [class.et-query-devtools-inner-row--active]=\"host.stackSelectedQueryId() === link.id\"\n [disabled]=\"!link.id\"\n (click)=\"host.stackSelectedQueryId.set(link.id)\"\n class=\"et-query-devtools-inner-row\"\n type=\"button\"\n >\n <span [attr.data-status]=\"host.queryStatus(link.query)\" class=\"et-query-devtools-status\"></span>\n <span class=\"et-query-devtools-method\">{{ link.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"link.segments\" [fallback]=\"link.query.id() || 'query ' + ($index + 1)\" />\n </span>\n @let linkStats = host.linkActivity(link);\n @if (linkStats.hasActivity) {\n <span class=\"et-query-devtools-traffic\">\n {{ host.formatTransferred(linkStats.stats.receivedBytes, linkStats.stats.hasEstimatedBytes) }}\n </span>\n }\n </button>\n }\n </div>\n</ng-template>\n", styles: ["@layer components{.et-query-devtools-traffic{margin-inline-start:auto;flex:0 0 auto;white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--_et-qdt-subtle)}.et-query-devtools-card-title{display:flex;align-items:baseline;gap:.5rem;margin-block-end:.2rem}.et-query-devtools-card-sub{color:var(--_et-qdt-subtle);font-size:1.1rem;margin-block-end:.6rem;overflow-wrap:anywhere}}\n"] }]
4645
4659
  }] });
4646
4660
 
4661
+ /**
4662
+ * The waterfall's grid, axis and bars, as a styles-only component the panel mounts when the Timeline tab
4663
+ * is first opened.
4664
+ *
4665
+ * @internal
4666
+ */
4667
+ class QueryDevtoolsTimelineStylesComponent {
4668
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsTimelineStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4669
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: QueryDevtoolsTimelineStylesComponent, isStandalone: true, selector: "et-query-devtools-timeline-styles", ngImport: i0, template: '', isInline: true, styles: ["@layer components{.et-query-devtools-timeline{display:grid;grid-template-columns:minmax(10rem,26rem) minmax(14rem,1fr) max-content max-content max-content;gap:.1rem .8rem;padding-inline:.4rem 1rem}.et-query-devtools-timeline-axis,.et-query-devtools-timeline-row{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;align-items:center}.et-query-devtools-timeline-axis{position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border);padding-block-end:.4rem;margin-block-end:.4rem}.et-query-devtools-timeline-ticks{grid-column:2;position:relative;block-size:1.5rem}.et-query-devtools-timeline-tick{position:absolute;inset-block-start:0;transform:translate(-50%);color:var(--_et-qdt-subtle);font-size:1.1rem;white-space:nowrap}.et-query-devtools-timeline-tick:first-child{transform:none}.et-query-devtools-timeline-tick:last-child{transform:translate(-100%)}.et-query-devtools-timeline-row{appearance:none;border:0;background:transparent;color:inherit;font:inherit;text-align:start;padding:.15rem 0;cursor:pointer}@media(hover:hover){.et-query-devtools-timeline-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-timeline-row--active{background:var(--_et-qdt-active)}.et-query-devtools-timeline-label{display:flex;align-items:baseline;gap:.4rem;min-inline-size:0;overflow:hidden}.et-query-devtools-timeline-label .et-query-devtools-url{max-inline-size:none;margin-inline-start:0}.et-query-devtools-timeline-track{position:relative;block-size:1.8rem;border-radius:var(--_et-qdt-radius-sm);overflow:hidden;background-color:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);background-image:repeating-linear-gradient(to right,var(--_et-qdt-border) 0 1px,transparent 1px 25%)}.et-query-devtools-timeline-bar{position:absolute;inset-block:.4rem;min-inline-size:.2rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-subtle)}.et-query-devtools-timeline-bar[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-timeline-bar[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-timeline-bar[data-status=loading]{background:var(--_et-qdt-loading)}.et-query-devtools-timeline-bar[data-status=aborted]{min-inline-size:.5rem;background:color-mix(in srgb,var(--_et-qdt-subtle) 20%,transparent);outline:1px solid color-mix(in srgb,var(--_et-qdt-subtle) 70%,transparent);outline-offset:-1px}.et-query-devtools-timeline-duration,.et-query-devtools-timeline-size{text-align:end;color:var(--_et-qdt-muted);font-size:1.1rem;font-variant-numeric:tabular-nums;white-space:nowrap}.et-query-devtools-timeline-duration{color:var(--_et-qdt-fg)}.et-query-devtools-timeline-flags{display:flex;align-items:center;gap:.3rem;white-space:nowrap}.et-query-devtools-timeline-flags .et-query-devtools-chip{padding:0 .4rem;border-color:transparent;border-radius:var(--_et-qdt-radius-sm);background:color-mix(in srgb,currentcolor 12%,transparent);font-size:1rem;line-height:1.5;font-variant-numeric:tabular-nums}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
4670
+ }
4671
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsTimelineStylesComponent, decorators: [{
4672
+ type: Component,
4673
+ args: [{ selector: 'et-query-devtools-timeline-styles', template: '', encapsulation: ViewEncapsulation.None, styles: ["@layer components{.et-query-devtools-timeline{display:grid;grid-template-columns:minmax(10rem,26rem) minmax(14rem,1fr) max-content max-content max-content;gap:.1rem .8rem;padding-inline:.4rem 1rem}.et-query-devtools-timeline-axis,.et-query-devtools-timeline-row{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;align-items:center}.et-query-devtools-timeline-axis{position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border);padding-block-end:.4rem;margin-block-end:.4rem}.et-query-devtools-timeline-ticks{grid-column:2;position:relative;block-size:1.5rem}.et-query-devtools-timeline-tick{position:absolute;inset-block-start:0;transform:translate(-50%);color:var(--_et-qdt-subtle);font-size:1.1rem;white-space:nowrap}.et-query-devtools-timeline-tick:first-child{transform:none}.et-query-devtools-timeline-tick:last-child{transform:translate(-100%)}.et-query-devtools-timeline-row{appearance:none;border:0;background:transparent;color:inherit;font:inherit;text-align:start;padding:.15rem 0;cursor:pointer}@media(hover:hover){.et-query-devtools-timeline-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-timeline-row--active{background:var(--_et-qdt-active)}.et-query-devtools-timeline-label{display:flex;align-items:baseline;gap:.4rem;min-inline-size:0;overflow:hidden}.et-query-devtools-timeline-label .et-query-devtools-url{max-inline-size:none;margin-inline-start:0}.et-query-devtools-timeline-track{position:relative;block-size:1.8rem;border-radius:var(--_et-qdt-radius-sm);overflow:hidden;background-color:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);background-image:repeating-linear-gradient(to right,var(--_et-qdt-border) 0 1px,transparent 1px 25%)}.et-query-devtools-timeline-bar{position:absolute;inset-block:.4rem;min-inline-size:.2rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-subtle)}.et-query-devtools-timeline-bar[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-timeline-bar[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-timeline-bar[data-status=loading]{background:var(--_et-qdt-loading)}.et-query-devtools-timeline-bar[data-status=aborted]{min-inline-size:.5rem;background:color-mix(in srgb,var(--_et-qdt-subtle) 20%,transparent);outline:1px solid color-mix(in srgb,var(--_et-qdt-subtle) 70%,transparent);outline-offset:-1px}.et-query-devtools-timeline-duration,.et-query-devtools-timeline-size{text-align:end;color:var(--_et-qdt-muted);font-size:1.1rem;font-variant-numeric:tabular-nums;white-space:nowrap}.et-query-devtools-timeline-duration{color:var(--_et-qdt-fg)}.et-query-devtools-timeline-flags{display:flex;align-items:center;gap:.3rem;white-space:nowrap}.et-query-devtools-timeline-flags .et-query-devtools-chip{padding:0 .4rem;border-color:transparent;border-radius:var(--_et-qdt-radius-sm);background:color-mix(in srgb,currentcolor 12%,transparent);font-size:1rem;line-height:1.5;font-variant-numeric:tabular-nums}}\n"] }]
4674
+ }] });
4675
+
4647
4676
  /** Past this many rows, the timeline keeps the newest and counts the rest instead of drawing them. */
4648
4677
  const MAX_TIMELINE_ROWS = 200;
4649
4678
  /** Where the timeline's axis labels sit, as fractions of the window. */
@@ -4737,6 +4766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
4737
4766
 
4738
4767
  const MAX_BATCH_ITEM_ROWS = 100;
4739
4768
  const LOCATE_HOLD_MS = 2500;
4769
+ const PARKED_EXECUTE_HINT = 'Parked: its withArgs source returns null. Run it with args from here, or set what the source reads.';
4740
4770
  const LOCATE_MAX_DEPTH = 4;
4741
4771
  /**
4742
4772
  * The element to scroll to and outline for a query: the one it was created in, or the shallowest
@@ -4796,7 +4826,7 @@ const describeEntryId = (id) => {
4796
4826
  return id;
4797
4827
  return `${method} ${route}${client ? ` · ${client}` : ''}${seq && seq !== '0' ? ` #${seq}` : ''}`;
4798
4828
  };
4799
- const STORAGE_KEY = QUERY_DEVTOOLS_VIEW_STATE_KEY;
4829
+ const STORAGE_KEY = _QUERY_DEVTOOLS_VIEW_STATE_KEY;
4800
4830
  /**
4801
4831
  * Pinned queries, held apart from {@link STORAGE_KEY} and defaulting to `localStorage`: everything under
4802
4832
  * that key is view state that should die with the tab, while a pin says which query is being worked on
@@ -4861,7 +4891,7 @@ const settledFloatRect = (rect, viewport) => {
4861
4891
  };
4862
4892
  };
4863
4893
  const resizedFloatRect = (base, { move, viewport }) => {
4864
- const { edge, dx, dy } = move;
4894
+ const { edge, totalDx: dx, totalDy: dy } = move;
4865
4895
  const maxWidth = edge.includes('w') ? base.x + base.width : viewport.width - base.x;
4866
4896
  const maxHeight = edge.includes('n') ? base.y + base.height : viewport.height - base.y;
4867
4897
  const requestedWidth = edge.includes('e') ? base.width + dx : edge.includes('w') ? base.width - dx : base.width;
@@ -5005,6 +5035,7 @@ const decodeJwtPayload = (token) => {
5005
5035
  return null;
5006
5036
  }
5007
5037
  };
5038
+ let warnedMissingProvider = false;
5008
5039
  /**
5009
5040
  * A floating, dockable panel that inspects the live state of the signals-first `@ethlete/query`
5010
5041
  * system: queries, stacks, sequences, bearer auth providers, the repository cache and a rolling
@@ -5022,6 +5053,7 @@ class QueryDevtoolsComponent {
5022
5053
  this.zone = inject(NgZone);
5023
5054
  this.destroyRef = inject(DestroyRef);
5024
5055
  this.document = inject(DOCUMENT);
5056
+ this.injector = inject(Injector);
5025
5057
  this.viewport = injectViewportSize();
5026
5058
  this.isDocumentVisible = injectIsDocumentVisible();
5027
5059
  /**
@@ -5031,6 +5063,11 @@ class QueryDevtoolsComponent {
5031
5063
  this.startOpen = input(false, { ...(ngDevMode ? { debugName: "startOpen" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5032
5064
  this.panelEl = viewChild('panel', /* @ts-ignore */
5033
5065
  ...(ngDevMode ? [{ debugName: "panelEl" }] : /* istanbul ignore next */ []));
5066
+ this.toggle = viewChild(QueryDevtoolsToggleComponent, /* @ts-ignore */
5067
+ ...(ngDevMode ? [{ debugName: "toggle" }] : /* istanbul ignore next */ []));
5068
+ this.tabButtons = viewChildren('tabButton', /* @ts-ignore */
5069
+ ...(ngDevMode ? [{ debugName: "tabButtons" }] : /* istanbul ignore next */ []));
5070
+ this.focusBeforeOpen = null;
5034
5071
  this.eventIdCounter = 0;
5035
5072
  this.lastSelectionKey = '';
5036
5073
  this.tabBeforeSettings = 'queries';
@@ -5311,6 +5348,10 @@ class QueryDevtoolsComponent {
5311
5348
  ...(ngDevMode ? [{ debugName: "inspectFilterIds" }] : /* istanbul ignore next */ []));
5312
5349
  this.queryEntries = computed(() => queryDevtoolsEntries().filter((e) => e.kind === 'query'), /* @ts-ignore */
5313
5350
  ...(ngDevMode ? [{ debugName: "queryEntries" }] : /* istanbul ignore next */ []));
5351
+ this.argsSourceQueries = computed(() => new Set(this.queryEntries()
5352
+ .filter((e) => e.meta.features?.some((feature) => feature.type === QueryFeatureType.WITH_ARGS))
5353
+ .map((e) => e.handle)), /* @ts-ignore */
5354
+ ...(ngDevMode ? [{ debugName: "argsSourceQueries" }] : /* istanbul ignore next */ []));
5314
5355
  /**
5315
5356
  * The queries that still exist. Everything that measures what the application is doing right now -
5316
5357
  * the tab bar's error flags, the tamper dot, the timeline -
@@ -5541,6 +5582,10 @@ class QueryDevtoolsComponent {
5541
5582
  ...(ngDevMode ? [{ debugName: "restoredOverrides" }] : /* istanbul ignore next */ []));
5542
5583
  this.DROP_RESTORED_OVERRIDES = clearRestoredQueryDevtoolsOverrides;
5543
5584
  this.FLOAT_RESIZE_EDGES = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];
5585
+ if (ngDevMode && !warnedMissingProvider && !isQueryDevtoolsEnabled()) {
5586
+ warnedMissingProvider = true;
5587
+ console.warn("<et-query-devtools>: provideQueryDevtools() is not in the application providers, so the panel stays empty. Add it to bootstrapApplication's providers.");
5588
+ }
5544
5589
  setQueryDevtoolsUiMounted(true);
5545
5590
  this.destroyRef.onDestroy(() => setQueryDevtoolsUiMounted(false));
5546
5591
  this.toggleJsonPath = (path, expand) => {
@@ -5736,7 +5781,7 @@ class QueryDevtoolsComponent {
5736
5781
  }
5737
5782
  ngOnInit() {
5738
5783
  if (this.startOpen())
5739
- this.open.set(true);
5784
+ this.openPanel();
5740
5785
  }
5741
5786
  overridesPersist() {
5742
5787
  return queryDevtoolsOverridePersistence();
@@ -5817,7 +5862,12 @@ class QueryDevtoolsComponent {
5817
5862
  this.dockBack();
5818
5863
  return;
5819
5864
  }
5820
- this.open.update((v) => !v);
5865
+ if (this.open()) {
5866
+ this.closePanel();
5867
+ }
5868
+ else {
5869
+ this.openPanel();
5870
+ }
5821
5871
  }
5822
5872
  floatPanel() {
5823
5873
  this.popOutBlocked.set(false);
@@ -5971,13 +6021,16 @@ class QueryDevtoolsComponent {
5971
6021
  queryStatus(query) {
5972
6022
  const state = query.executionState();
5973
6023
  if (!state)
5974
- return 'idle';
6024
+ return this.isParked(query) ? 'parked' : 'idle';
5975
6025
  if (state.type === 'loading')
5976
6026
  return 'loading';
5977
6027
  if (state.type === 'failure')
5978
6028
  return 'error';
5979
6029
  return 'success';
5980
6030
  }
6031
+ isParked(query) {
6032
+ return this.argsSourceQueries().has(query) && this.queryArgs(query) === null;
6033
+ }
5981
6034
  isStale(query) {
5982
6035
  try {
5983
6036
  const request = query.subtle.request();
@@ -6162,6 +6215,11 @@ class QueryDevtoolsComponent {
6162
6215
  */
6163
6216
  executeQuery(selection, allowCache) {
6164
6217
  const { query } = selection;
6218
+ if (this.isParked(query)) {
6219
+ this.openArgsEditor(selection);
6220
+ this.editError.set(PARKED_EXECUTE_HINT);
6221
+ return;
6222
+ }
6165
6223
  try {
6166
6224
  query.execute({ args: this.queryArgs(query), options: allowCache ? { allowCache: true } : undefined });
6167
6225
  }
@@ -6505,7 +6563,9 @@ class QueryDevtoolsComponent {
6505
6563
  }));
6506
6564
  }
6507
6565
  causeLabel(cause) {
6508
- const scope = cause.url ? this.requestPath(cause.url) : 'everything in use';
6566
+ const scope = [cause.url ? this.requestPath(cause.url) : null, cause.tag ? `tag ${cause.tag}` : null]
6567
+ .filter((part) => part !== null)
6568
+ .join(' · ') || 'everything in use';
6509
6569
  const what = cause.type === 'invalidation'
6510
6570
  ? `invalidated ${scope}`
6511
6571
  : cause.type === 'mutation'
@@ -6744,6 +6804,33 @@ class QueryDevtoolsComponent {
6744
6804
  this.eventOwners.set(event, id);
6745
6805
  return id;
6746
6806
  }
6807
+ openPanel() {
6808
+ const active = this.document.activeElement;
6809
+ this.focusBeforeOpen =
6810
+ active instanceof HTMLElement && active !== this.document.body && !this.hostEl.nativeElement.contains(active)
6811
+ ? active
6812
+ : null;
6813
+ this.open.set(true);
6814
+ afterNextRender(() => {
6815
+ const tabs = this.tabButtons().map((ref) => ref.nativeElement);
6816
+ const tab = tabs.find((el) => el.getAttribute('aria-selected') === 'true') ?? tabs[0];
6817
+ tab?.focus();
6818
+ }, { injector: this.injector });
6819
+ }
6820
+ closePanel() {
6821
+ const returnTo = this.focusBeforeOpen;
6822
+ this.focusBeforeOpen = null;
6823
+ this.inspectActive.set(false);
6824
+ this.open.set(false);
6825
+ afterNextRender(() => {
6826
+ if (returnTo?.isConnected) {
6827
+ returnTo.focus();
6828
+ }
6829
+ else {
6830
+ this.toggle()?.focus();
6831
+ }
6832
+ }, { injector: this.injector });
6833
+ }
6747
6834
  resolvedHeaders(request, args) {
6748
6835
  try {
6749
6836
  if (request)
@@ -7442,7 +7529,7 @@ class QueryDevtoolsComponent {
7442
7529
  this.eventLog.update((log) => [item, ...log].slice(0, queryDevtoolsSettings().maxEvents));
7443
7530
  }
7444
7531
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7445
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsComponent, isStandalone: true, selector: "et-query-devtools", inputs: { startOpen: { classPropertyName: "startOpen", publicName: "startOpen", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-et-overlay-layer": "2147483020" }, properties: { "attr.data-dock": "dock()" }, classAttribute: "et-query-devtools-host" }, providers: [{ provide: QUERY_DEVTOOLS_HOST, useExisting: QueryDevtoolsComponent }], viewQueries: [{ propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <section\n #panel\n [class.et-query-devtools-panel--resizing]=\"resizing()\"\n [attr.data-dock]=\"poppedOut() ? 'popout' : dock()\"\n [attr.data-pane-axis]=\"paneAxis()\"\n [attr.data-parked]=\"floatParked() ? '' : null\"\n [style.block-size.px]=\"panelBlockSize()\"\n [style.inline-size.px]=\"panelInlineSize()\"\n [style.inset-block-start.px]=\"panelInsetBlock()\"\n [style.inset-inline-start.px]=\"panelInsetInline()\"\n [style.--_et-qdt-list-width.px]=\"listWidth()\"\n [style.--_et-qdt-drawer-width.px]=\"drawerWidth()\"\n [style.--_et-qdt-list-height.px]=\"listHeight()\"\n [style.--_et-qdt-drawer-height.px]=\"drawerHeight()\"\n class=\"et-query-devtools-panel\"\n >\n @if (floating()) {\n <et-resize-handles\n [edges]=\"FLOAT_RESIZE_EDGES\"\n [disabled]=\"floatParked()\"\n (resizeStarted)=\"startFloatResize()\"\n (resizeMoved)=\"resizeFloat($event)\"\n (resizeEnded)=\"endFloatResize()\"\n (resizeCancelled)=\"endFloatResize()\"\n />\n <div\n (dragMoved)=\"moveFloat($event)\"\n (dragEnded)=\"endFloatMove()\"\n (dragCancelled)=\"endFloatMove()\"\n (dragTapped)=\"restoreFloat()\"\n class=\"et-query-devtools-move\"\n title=\"Drag to move \u2014 shove it off an edge to park it, click the strip to bring it back\"\n aria-hidden=\"true\"\n etDragHandle\n ></div>\n } @else if (!poppedOut()) {\n <div\n (pointerdown)=\"startResize($event)\"\n class=\"et-query-devtools-resize\"\n title=\"Drag to resize\"\n aria-hidden=\"true\"\n ></div>\n }\n <header class=\"et-query-devtools-header\">\n <nav class=\"et-query-devtools-tabs\" role=\"tablist\">\n @for (tab of visibleTabs(); track tab.id) {\n @let badge = tabBadges()[tab.id];\n <button\n [class.et-query-devtools-tab--active]=\"activeTab() === tab.id\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n (click)=\"activeTab.set(tab.id)\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (badge.count) {\n <span class=\"et-query-devtools-tab-badge\">{{ badge.count }}</span>\n }\n @if (badge.errors) {\n <span\n class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\"\n title=\"{{ badge.errors }} {{ badge.errorNoun ?? 'failing' }}\"\n >\n {{ badge.errors }}\n </span>\n }\n </button>\n }\n\n @if (overflowTabs().length; as overflowCount) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [title]=\"overflowCount + ' tabs with nothing in them'\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n etMenuTrigger\n >\n More\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n @for (tab of overflowTabs(); track tab.id) {\n <button (activate)=\"activeTab.set(tab.id)\" et-menu-item type=\"button\">{{ tab.label }}</button>\n }\n </et-menu>\n </ng-template>\n </div>\n }\n </nav>\n\n <div class=\"et-query-devtools-header-actions\">\n <button\n [class.et-query-devtools-inspect-btn--active]=\"inspectActive()\"\n [attr.aria-pressed]=\"inspectActive()\"\n (click)=\"toggleInspect()\"\n class=\"et-query-devtools-btn et-query-devtools-inspect-btn\"\n type=\"button\"\n title=\"Inspect: hover the UI to find its query\"\n >\n <svg\n class=\"et-query-devtools-inspect-icon\"\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle class=\"et-query-devtools-inspect-icon-ring\" cx=\"8\" cy=\"8\" r=\"4.25\" />\n <circle class=\"et-query-devtools-inspect-icon-dot\" cx=\"8\" cy=\"8\" r=\"1.15\" />\n <path d=\"M8 0.9v2.1M8 13v2.1M0.9 8h2.1M13 8h2.1\" />\n </svg>\n {{ inspectActive() ? 'Inspecting' : 'Inspect' }}\n @if (inspectActive()) {\n <kbd class=\"et-query-devtools-kbd et-query-devtools-kbd--inverse\">Esc</kbd>\n }\n </button>\n <button\n (click)=\"downloadSession()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every registered entry, the event log, the cache totals and anything armed as one JSON file - the attachment for a bug report\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Session\n </button>\n <button\n [class.et-query-devtools-btn--active]=\"activeTab() === 'settings'\"\n [attr.aria-pressed]=\"activeTab() === 'settings'\"\n (click)=\"toggleSettings()\"\n class=\"et-query-devtools-btn et-query-devtools-icon-btn\"\n type=\"button\"\n title=\"Settings: where panel state is kept, and the limits it holds\"\n aria-label=\"Settings\"\n >\n <span aria-hidden=\"true\">\u2699</span>\n </button>\n @if (!poppedOut()) {\n @let layout = currentLayout();\n <div class=\"et-query-devtools-menu\" etMenu placement=\"bottom-end\">\n <button class=\"et-query-devtools-btn\" title=\"Where the panel sits\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ layout.glyph }}</span>\n {{ layout.label }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <et-menu-radio-group [value]=\"dock()\">\n @for (option of LAYOUTS; track option.id) {\n <!-- eslint-disable ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <et-menu-radio-item\n [value]=\"option.id\"\n [title]=\"option.hint\"\n [closeOnActivate]=\"true\"\n (activate)=\"selectLayout(option.id)\"\n >\n <!-- eslint-enable ethlete/prefer-static-boolean-properties -->\n <span class=\"et-query-devtools-menu-item-glyph\" aria-hidden=\"true\">{{ option.glyph }}</span>\n {{ option.label }}\n </et-menu-radio-item>\n }\n </et-menu-radio-group>\n <et-menu-separator />\n <et-menu-checkbox-item\n [checked]=\"reservesSpace()\"\n [disabled]=\"floating()\"\n (checkedChange)=\"reservesSpace.set($event)\"\n title=\"The page gives up the room the panel covers, so its last rows can still be scrolled to. Docks only - a float sits wherever it was dragged.\"\n >\n Reserve page space\n </et-menu-checkbox-item>\n </et-menu>\n </ng-template>\n </div>\n }\n <span class=\"et-query-devtools-header-divider\" aria-hidden=\"true\"></span>\n <button\n (click)=\"toggleOpen()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n title=\"{{ poppedOut() ? 'Bring the panel back into the app window' : 'Close devtools (' + shortcut + ')' }}\"\n >\n @if (poppedOut()) {\n <span aria-hidden=\"true\">\u29C8</span>\n Dock back\n } @else {\n <span aria-hidden=\"true\">\u2715</span>\n Close\n <kbd class=\"et-query-devtools-kbd\">{{ shortcut }}</kbd>\n }\n </button>\n </div>\n </header>\n\n @if (popOutBlocked()) {\n <div class=\"et-query-devtools-notice-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-text\">\n The browser blocked the pop-up window. Allow pop-ups for this site, or float the panel over the page instead \u2014\n a float needs no permission.\n </span>\n <button (click)=\"floatPanel()\" class=\"et-query-devtools-btn\" type=\"button\">Float instead</button>\n <button (click)=\"popOutBlocked.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Dismiss</button>\n </div>\n }\n\n @if (armedFaultClients(); as armed) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Faults armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ armed.join(', ') }}</span>\n \u2014 every failure and delay you see from\n {{ armed.length === 1 ? 'this client' : 'these clients' }} is injected, not the API.\n @if (faultsRestored()) {\n They came back from your last page load \u2014 set <em>Armed faults</em> back to <em>none</em> in Settings to\n stop that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'faults'\"\n (click)=\"activeTab.set('faults')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"CLEAR_FAULTS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (armedMockRoutes(); as mocked) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Mocks armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ mocked.join(', ') }}</span>\n \u2014 {{ mocked.length === 1 ? 'that route is' : 'those routes are' }} answered by the panel, so nothing they show\n reached the API.\n @if (mocksRestored()) {\n They came back from your last page load \u2014 set <em>Armed mocks</em> back to <em>none</em> in Settings to stop\n that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'mocks'\"\n (click)=\"activeTab.set('mocks')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"DISARM_MOCKS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (restoredOverrides(); as restored) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n @if (restored.ops) {\n <strong>Overrides re-armed</strong> \u2014 {{ restored.ops }} {{ restored.ops === 1 ? 'edit' : 'edits' }} from\n your last page load {{ restored.ops === 1 ? 'is' : 'are' }} back on {{ restored.queries }}\n {{ restored.queries === 1 ? 'query' : 'queries' }}, so those responses are not what the API sent.\n @if (restored.fromLocalStorage) {\n They came back from <strong>localStorage</strong>, so they outlive closing this tab \u2014 clear them, or set\n overrides back to <em>session</em> in Settings.\n }\n } @else {\n <strong>Overrides could not be re-armed.</strong>\n }\n @if (restored.orphaned.length) {\n <span class=\"et-query-devtools-armed-orphans\">\n {{ restored.orphaned.length }} stored\n {{ restored.orphaned.length === 1 ? 'override' : 'overrides' }} matched no query \u2014\n <span class=\"et-query-devtools-mono\">{{ restored.orphaned.join(', ') }}</span>\n </span>\n }\n </span>\n @if (restored.firstId; as firstId) {\n <button (click)=\"reviewRestoredOverrides(firstId)\" class=\"et-query-devtools-btn\" type=\"button\">Review</button>\n }\n <button (click)=\"DROP_RESTORED_OVERRIDES()\" class=\"et-query-devtools-btn\" type=\"button\">Drop all</button>\n </div>\n }\n\n <div class=\"et-query-devtools-body\">\n @switch (activeTab()) {\n @case ('queries') {\n <et-query-devtools-queries-tab />\n }\n\n @case ('stacks') {\n <et-query-devtools-stacks-tab />\n }\n\n @case ('sequences') {\n <et-query-devtools-sequences-tab />\n }\n\n @case ('batches') {\n <et-query-devtools-batches-tab />\n }\n\n @case ('forms') {\n <et-query-devtools-forms-tab />\n }\n\n @case ('auth') {\n <et-query-devtools-auth-tab />\n }\n\n @case ('ws') {\n <et-query-devtools-sockets-tab />\n }\n\n @case ('cache') {\n <et-query-devtools-cache-tab />\n }\n\n @case ('locks') {\n <et-query-devtools-locks-tab />\n }\n\n @case ('timeline') {\n <et-query-devtools-timeline-tab />\n }\n\n @case ('events') {\n <et-query-devtools-events-tab />\n }\n\n @case ('faults') {\n <et-query-devtools-faults-tab />\n }\n\n @case ('mocks') {\n <et-query-devtools-mocks-tab />\n }\n\n @case ('about') {\n <et-query-devtools-about />\n }\n\n @case ('settings') {\n <et-query-devtools-settings />\n }\n }\n </div>\n </section>\n}\n\n@if (!open()) {\n <et-query-devtools-toggle [tampered]=\"panelTampered()\" (openChange)=\"toggleOpen()\" />\n}\n\n@if (inspectActive() && inspectHover(); as hover) {\n <div\n [style.left.px]=\"hover.rect.left\"\n [style.top.px]=\"hover.rect.top\"\n [style.width.px]=\"hover.rect.width\"\n [style.height.px]=\"hover.rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">{{ inspectLabel(hover.entries) }}</span>\n </div>\n}\n\n@if (locatedRect(); as rect) {\n <div\n [style.left.px]=\"rect.left\"\n [style.top.px]=\"rect.top\"\n [style.width.px]=\"rect.width\"\n [style.height.px]=\"rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">created here</span>\n </div>\n}\n", styles: ["@layer components{.et-query-devtools-host{--_et-qdt-bg: var(--et-surface-background-solid, rgb(24 24 27));--_et-qdt-fg: var(--et-surface-color-solid, rgb(244 244 245));--_et-qdt-muted: var(--et-surface-color-muted-solid, rgb(161 161 170));--_et-qdt-subtle: var(--et-surface-color-subtle-solid, rgb(113 113 122));--_et-qdt-border: var(--et-surface-border-solid, rgb(255 255 255 / .12));--_et-qdt-interaction: var(--et-surface-interaction-solid, rgb(255 255 255));--_et-qdt-line: color-mix(in srgb, var(--_et-qdt-interaction) 24%, transparent);--_et-qdt-line-strong: color-mix(in srgb, var(--_et-qdt-interaction) 42%, transparent);--_et-qdt-accent: var(--et-theme-color-primary-solid, rgb(96 165 250));--_et-qdt-on-accent: var(--et-theme-color-on-primary, #09090b);--_et-qdt-hover: color-mix(in srgb, var(--_et-qdt-interaction) 10%, transparent);--_et-qdt-field: color-mix(in srgb, var(--_et-qdt-interaction) 8%, transparent);--_et-qdt-active: color-mix(in srgb, var(--_et-qdt-interaction) 18%, transparent);--_et-qdt-success: rgb(34 197 94);--_et-qdt-error: rgb(239 68 68);--_et-qdt-loading: rgb(234 179 8);--_et-qdt-title-bar: 2.4rem;--_et-qdt-radius-sm: .3rem;--_et-qdt-radius: .5rem;--_et-qdt-radius-lg: .6rem;--_et-qdt-control-h: 2.4rem;--_et-qdt-row-h: 3.6rem;position:fixed;inset-inline:0;inset-block-end:0;z-index:2147483010;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,Liberation Mono,monospace;font-size:1.2rem;line-height:1.4;pointer-events:none}.et-query-devtools-host>*{pointer-events:auto}@media(pointer:coarse){.et-query-devtools-host{--_et-qdt-control-h: 3.4rem;--_et-qdt-row-h: 4.4rem}}.et-query-devtools-panel{position:relative;display:flex;flex-direction:column;inline-size:100%;min-block-size:20rem;max-block-size:90vh;background:var(--_et-qdt-bg);color:var(--_et-qdt-fg);border-block-start:1px solid var(--_et-qdt-border);box-shadow:0 -.4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=right]){inset-block:0;inset-inline-start:auto}.et-query-devtools-panel:where([data-dock=right]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-start:1px solid var(--_et-qdt-border);box-shadow:-.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=float]){inset:0}.et-query-devtools-panel:where([data-dock=float]){--_et-qdt-frame: .8rem;--et-resize-handles-edge-size: var(--_et-qdt-frame);--et-resize-handles-touch-edge-size: var(--_et-qdt-frame);--et-resize-handles-corner-size: 1.6rem;--et-resize-handles-touch-corner-size: 1.6rem;--et-resize-handles-edge-inset: 1.6rem;--et-resize-handles-side-top: var(--_et-qdt-title-bar);--et-resize-handles-side-bottom: 1.6rem;--et-resize-handles-z-index: 3;position:absolute;inline-size:auto;min-block-size:0;max-block-size:none;padding-block-start:var(--_et-qdt-title-bar);padding-inline:var(--_et-qdt-frame);padding-block-end:var(--_et-qdt-frame);border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);box-shadow:0 1rem 4rem #00000073;overflow:hidden}.et-query-devtools-move{position:absolute;inset-inline:0;inset-block-start:0;block-size:var(--_et-qdt-title-bar);cursor:move;z-index:2}.et-query-devtools-panel:where([data-dock=float]) .et-query-devtools-body{border-radius:var(--_et-qdt-radius-sm);overflow:hidden}.et-query-devtools-move:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.9rem;inline-size:3rem;margin-inline-start:-1.5rem;block-size:.6rem;background-image:radial-gradient(currentcolor 40%,transparent 42%);background-size:.4rem .3rem;color:var(--_et-qdt-subtle)}@media(hover:hover){.et-query-devtools-move:hover:after{color:var(--_et-qdt-accent)}}.et-query-devtools-panel:where([data-dock=float][data-parked]){opacity:.85}@media(hover:hover){.et-query-devtools-panel:where([data-dock=float][data-parked]):hover{opacity:1}}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move{cursor:grab;background:var(--_et-qdt-active)}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move:after{color:var(--_et-qdt-accent)}.et-query-devtools-host:where([data-dock=left]){inset-block:0;inset-inline-end:auto}.et-query-devtools-panel:where([data-dock=left]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-end:1px solid var(--_et-qdt-border);box-shadow:.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=top]){inset-block-start:0;inset-block-end:auto}.et-query-devtools-panel:where([data-dock=top]){border-block-start:0;border-block-end:1px solid var(--_et-qdt-border);box-shadow:0 .4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=popout]){position:static;inline-size:100%;block-size:100%}.et-query-devtools-panel:where([data-dock=popout]){block-size:100%;max-block-size:none;border:0;box-shadow:none}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-header{flex-wrap:wrap}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions){flex:1 1 auto;flex-wrap:nowrap;min-inline-size:0;overflow-x:auto}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions)>*{flex:none}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-master-detail,.et-query-devtools-split){flex-direction:column}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-list,.et-query-devtools-detail,.et-query-devtools-drawer,.et-query-devtools-split .et-query-devtools-scroll){flex:1 1 50%;min-inline-size:0;min-block-size:0;max-inline-size:none;border-inline-start:0;border-inline-end:0}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-detail,.et-query-devtools-drawer){border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-master-detail>.et-query-devtools-list{flex:0 1 var(--_et-qdt-list-height, 50%);min-block-size:var(--_et-qdt-list-height, 0);max-block-size:var(--_et-qdt-list-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-split .et-query-devtools-drawer{flex:0 1 var(--_et-qdt-drawer-height, 50%);min-block-size:var(--_et-qdt-drawer-height, 0);max-block-size:var(--_et-qdt-drawer-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-pane-resize{cursor:ns-resize}.et-query-devtools-panel--resizing{-webkit-user-select:none;user-select:none}.et-query-devtools-resize,.et-query-devtools-pane-resize{touch-action:none}.et-query-devtools-resize{position:absolute;inset-inline:0;inset-block-start:0;block-size:.6rem;cursor:ns-resize;z-index:1}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize{inset-inline:0 auto;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize{inset-inline:auto 0;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize{inset-block:auto 0}.et-query-devtools-resize:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.2rem;inline-size:4rem;margin-inline-start:-2rem;block-size:.2rem;border-radius:999px;background:var(--_et-qdt-border)}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize:after{inset-inline:.2rem auto;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize:after{inset-inline:auto .2rem;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize:after{inset-block:auto .2rem}@media(hover:hover){.et-query-devtools-resize:hover:after{background:var(--_et-qdt-accent)}}.et-query-devtools-header{display:flex;align-items:center;justify-content:space-between;gap:.8rem;padding-inline:.8rem;border-block-end:1px solid var(--_et-qdt-border);flex:0 0 auto}.et-query-devtools-armed-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-block-end:1px solid color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-armed-text{flex:1 1 auto;min-inline-size:0}.et-query-devtools-notice-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:var(--_et-qdt-hover);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg);font-size:1.1rem}.et-query-devtools-notice-bar .et-query-devtools-btn{flex:0 0 auto}.et-query-devtools-armed-orphans{display:block;opacity:.85}.et-query-devtools-armed-dot{flex:0 0 auto;inline-size:.8rem;block-size:.8rem;border-radius:50%;background:var(--_et-qdt-error);animation:et-query-devtools-armed-pulse 1.6s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.et-query-devtools-armed-dot{animation:none}}@keyframes et-query-devtools-armed-pulse{50%{opacity:.25}}.et-query-devtools-armed-bar .et-query-devtools-btn{flex:0 0 auto;border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-tabs{display:flex;flex-wrap:wrap;gap:.2rem}.et-query-devtools-tab{appearance:none;display:inline-flex;align-items:center;gap:.5rem;border:none;background:transparent;color:var(--_et-qdt-muted);padding:.9rem 1rem;cursor:pointer;border-block-end:2px solid transparent;font:inherit}@media(hover:hover){.et-query-devtools-tab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-tab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-tab-badge{display:inline-block;padding-inline:.45rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-interaction) 12%,transparent);color:var(--_et-qdt-muted);font-size:1rem;font-variant-numeric:tabular-nums}.et-query-devtools-tab-badge--error{background:color-mix(in srgb,var(--_et-qdt-error) 25%,transparent);color:var(--_et-qdt-fg)}.et-query-devtools-menu{display:contents}.et-query-devtools-menu-caret{font-size:.9em;opacity:.7}.et-query-devtools-menu-glyph{display:inline-block;min-inline-size:1.2rem;text-align:center}.et-query-devtools-menu>[data-menu-open]{background:var(--_et-qdt-hover);color:var(--_et-qdt-fg)}.et-menu .et-query-devtools-menu-item-glyph{display:inline-block;inline-size:16px;text-align:center}.et-menu-item-content:has(.et-query-devtools-menu-item-note){display:flex;flex-direction:column;align-items:start;gap:2px;padding-block:8px}.et-query-devtools-menu-item-note{color:var(--et-surface-color-muted-solid, rgb(255 255 255 / .55));font-size:12px}.et-query-devtools-header-actions{display:flex;align-items:center;gap:.2rem;flex:0 0 auto}.et-query-devtools-header-divider{inline-size:1px;block-size:1.6rem;margin-inline:.4rem;background:var(--_et-qdt-border)}.et-query-devtools-inspect-btn{position:relative}.et-query-devtools-inspect-icon{inline-size:1.4rem;block-size:1.4rem;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.25;stroke-linecap:round}.et-query-devtools-inspect-icon-dot{fill:currentColor;stroke:none}.et-query-devtools-btn.et-query-devtools-inspect-btn--active,.et-query-devtools-btn.et-query-devtools-inspect-btn--active:hover{color:var(--_et-qdt-on-accent);background:var(--_et-qdt-accent);border-color:var(--_et-qdt-accent)}.et-query-devtools-inspect-btn--active:after{content:\"\";position:absolute;inset:-.3rem;border:1px solid var(--_et-qdt-accent);border-radius:calc(var(--_et-qdt-radius) + .3rem);pointer-events:none;animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}@keyframes et-query-devtools-inspect-pulse{0%,to{opacity:.2}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.et-query-devtools-inspect-btn--active:after,.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:none;opacity:1}}.et-query-devtools-kbd{border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-hover);box-shadow:inset 0 0 0 1px var(--_et-qdt-border);color:var(--_et-qdt-muted);padding:.15rem .4rem;font:inherit;font-size:1.1rem;line-height:1.2;white-space:nowrap}.et-query-devtools-kbd--inverse{background:#00000026;box-shadow:inset 0 0 0 1px #00000040;color:inherit}@media(hover:none)and (pointer:coarse){.et-query-devtools-kbd{display:none}}.et-query-devtools-inspect-box{position:fixed;z-index:2147483002;pointer-events:none;border:2px solid var(--_et-qdt-accent);background:color-mix(in srgb,var(--_et-qdt-accent) 15%,transparent);border-radius:var(--_et-qdt-radius-sm)}.et-query-devtools-inspect-tag{position:absolute;inset-block-start:100%;inset-inline-start:0;margin-block-start:.2rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);font-family:ui-monospace,monospace;font-size:1.1rem;font-weight:600;white-space:nowrap}.et-query-devtools-panel :is(a,button,input,select,summary,textarea,[tabindex]):focus-visible{outline:2px solid var(--_et-qdt-accent);outline-offset:1px}.et-query-devtools-body{flex:1 1 auto;min-block-size:0;overflow:hidden}.et-query-devtools-detail{flex:1 1 auto;min-inline-size:0;overflow-y:auto;padding:1rem}.et-query-devtools-detail .et-query-devtools-meta,.et-query-devtools-drawer .et-query-devtools-meta{padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-detail .et-query-devtools-section-row,.et-query-devtools-drawer .et-query-devtools-section-row{padding-block-start:.8rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-filter-chip{display:inline-flex;align-items:center;gap:.6rem;padding:.3rem .35rem .3rem .7rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_et-qdt-accent) 45%,transparent);color:var(--_et-qdt-accent);font-size:1.1rem;font-weight:600;letter-spacing:.02em}.et-query-devtools-filter-icon{font-size:1.3rem;line-height:1}.et-query-devtools-filter-count{border-radius:999px;background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);min-inline-size:1.8rem;padding:0 .5rem;text-align:center}.et-query-devtools-filter-clear{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-filter-clear:hover{border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent);color:var(--_et-qdt-fg)}}.et-query-devtools-scroll{block-size:100%;overflow:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.et-query-devtools-split{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-split .et-query-devtools-scroll{flex:1 1 auto;min-inline-size:0}.et-query-devtools-pane{display:flex;flex-direction:column;flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:hidden}.et-query-devtools-pane>.et-query-devtools-scroll{padding-block:0 1rem}.et-query-devtools-pane-resize{flex:0 0 .5rem;align-self:stretch;cursor:ew-resize;background:transparent;transition:background .12s ease}.et-query-devtools-pane-resize:active{background:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-pane-resize:hover{background:var(--_et-qdt-accent)}}.et-query-devtools-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem;padding:.8rem;position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-scroll>.et-query-devtools-toolbar{inset-block-start:-1rem}.et-query-devtools-toolbar-row{display:flex;align-items:center;flex-wrap:wrap;flex:1 1 100%;gap:.5rem}.et-query-devtools-field{display:inline-flex;align-items:center;gap:.6rem;color:var(--_et-qdt-muted)}.et-query-devtools-select{flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);background:color-mix(in srgb,var(--_et-qdt-interaction) 8%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-select:focus-visible{border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent)}.et-query-devtools-select option{background-color:var(--_et-qdt-bg);color:var(--_et-qdt-fg)}.et-query-devtools-count{color:var(--_et-qdt-subtle)}.et-query-devtools-row{display:flex;align-items:stretch;inline-size:100%;min-block-size:var(--_et-qdt-row-h);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg)}@media(hover:hover){.et-query-devtools-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-method{font-weight:700;font-size:1.1rem;color:var(--_et-qdt-muted);white-space:nowrap}.et-query-devtools-route{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;min-inline-size:0}.et-query-devtools-status{inline-size:.8rem;block-size:.8rem;border-radius:999px;flex:0 0 auto;background:var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-status[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-status[data-status=loading],.et-query-devtools-status[data-status=running]{background:var(--_et-qdt-loading)}.et-query-devtools-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4;white-space:nowrap;cursor:pointer;transition:color .12s ease,background-color .12s ease,border-color .12s ease}@media(hover:hover){.et-query-devtools-btn:hover:not(:disabled){background:var(--_et-qdt-hover);border-color:var(--_et-qdt-line-strong);color:var(--_et-qdt-fg)}}.et-query-devtools-btn:disabled{border-color:var(--_et-qdt-border);color:var(--_et-qdt-subtle);cursor:default;background:transparent;opacity:.6}.et-query-devtools-btn--primary,.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 40%,transparent);color:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 26%,transparent)}}.et-query-devtools-btn--danger{border-color:color-mix(in srgb,var(--_et-qdt-error) 32%,transparent);color:color-mix(in srgb,var(--_et-qdt-error) 55%,var(--_et-qdt-fg))}@media(hover:hover){.et-query-devtools-btn--danger:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}}.et-query-devtools-btn--tampered,.et-query-devtools-btn--tampered:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-icon-btn{inline-size:var(--_et-qdt-control-h);padding-inline:0;font-size:1.3rem}.et-query-devtools-btn-group{display:inline-flex;flex:0 0 auto;border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);overflow:hidden}.et-query-devtools-btn-group>.et-query-devtools-btn{border-radius:0;border-block:0;border-inline-start:0;border-inline-end:1px solid var(--_et-qdt-line)}.et-query-devtools-btn-group>.et-query-devtools-btn:last-child{border-inline-end:0}.et-query-devtools-btn-group>.et-query-devtools-btn:focus-visible{outline-offset:-2px}.et-query-devtools-toolbar-btn{margin-inline-start:auto;flex:0 0 auto}.et-query-devtools-meta{display:grid;grid-template-columns:auto 1fr;gap:.3rem 1rem;margin:0 0 1rem}.et-query-devtools-meta dt{color:var(--_et-qdt-muted)}.et-query-devtools-meta dd{margin:0;overflow-wrap:anywhere}.et-query-devtools-section{margin:1rem 0 .4rem;font-size:1.1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat{padding:.6rem .8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-stat dt{font-size:1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat dd{margin:0;font-size:1.5rem;font-variant-numeric:tabular-nums}.et-query-devtools-stat-sub{display:block;font-size:1rem;color:var(--_et-qdt-subtle)}.et-query-devtools-json{margin:0;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow-x:auto;white-space:pre-wrap;overflow-wrap:anywhere;max-block-size:24rem;overflow-y:auto}.et-query-devtools-json--error{border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-mono{font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.et-query-devtools-url{display:inline-block;max-inline-size:32rem;margin-inline-start:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.et-query-devtools-chips,.et-query-devtools-chip-row{display:flex;flex-wrap:wrap;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-chip{display:inline-flex;align-items:center;gap:.3rem;padding:.2rem .6rem;border-radius:999px;border:1px solid var(--_et-qdt-border);font-size:1.1rem;color:var(--_et-qdt-fg);background:color-mix(in srgb,var(--_et-qdt-interaction) 6%,transparent)}.et-query-devtools-chip--muted{color:var(--_et-qdt-muted)}.et-query-devtools-retry-glyph{font-size:.7em;line-height:1}.et-query-devtools-chip--loading{color:var(--_et-qdt-loading);border-color:color-mix(in srgb,var(--_et-qdt-loading) 50%,transparent)}.et-query-devtools-chip--error{color:var(--_et-qdt-error);border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-chip--success{color:var(--_et-qdt-success);border-color:color-mix(in srgb,var(--_et-qdt-success) 50%,transparent)}button.et-query-devtools-chip--button{appearance:none;border-color:var(--_et-qdt-line);cursor:pointer;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}@media(hover:hover){button.et-query-devtools-chip--button:hover{border-color:var(--_et-qdt-accent);color:var(--_et-qdt-accent)}}.et-query-devtools-facet{appearance:none;border-color:var(--_et-qdt-line);min-block-size:var(--_et-qdt-control-h);padding-inline:.8rem;background:transparent;cursor:pointer;color:var(--_et-qdt-muted);font:inherit;font-size:1.1rem;line-height:1.4}@media(hover:hover){.et-query-devtools-facet:hover:not(:disabled){color:var(--_et-qdt-fg);background:var(--_et-qdt-hover);border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent)}}.et-query-devtools-facet:disabled{color:var(--_et-qdt-subtle);cursor:default}.et-query-devtools-facet--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 14%,transparent)}.et-query-devtools-facet-count{font-variant-numeric:tabular-nums;color:inherit;opacity:.75}.et-query-devtools-card{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);padding:1rem}.et-query-devtools-card--armed{border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-card-head{display:flex;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-inner-queries{display:flex;flex-direction:column;gap:.3rem}.et-query-devtools-inner-row{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.4rem .6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-inner-row:hover:not([disabled]){background:var(--_et-qdt-hover)}}.et-query-devtools-inner-row--active{background:var(--_et-qdt-active);border-color:var(--_et-qdt-accent)}.et-query-devtools-inner-row[disabled]{cursor:default;opacity:.6}.et-query-devtools-step-toggle{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:none;background:transparent;color:var(--_et-qdt-fg);padding:.6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-step-toggle:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-step-index{flex:1 1 auto;min-inline-size:0}.et-query-devtools-step-caret{color:var(--_et-qdt-muted)}.et-query-devtools-table{inline-size:100%;border-collapse:collapse}.et-query-devtools-table-scroll{overflow-x:auto}.et-query-devtools-table-scroll>.et-query-devtools-table{min-inline-size:max-content}.et-query-devtools-table th,.et-query-devtools-table td{text-align:start;padding:.5rem .6rem;border-block-end:1px solid var(--_et-qdt-border);vertical-align:top}.et-query-devtools-table td .et-query-devtools-chip{padding-block:0;line-height:1.4}.et-query-devtools-table th{color:var(--_et-qdt-muted);font-weight:600;position:sticky;inset-block-start:0;background:var(--_et-qdt-bg)}.et-query-devtools-table tr[data-status=error] td{color:var(--_et-qdt-error)}.et-query-devtools-table .et-query-devtools-cell-origin{inline-size:12ch;max-inline-size:12ch;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;overflow-wrap:normal}.et-query-devtools-empty{color:var(--_et-qdt-subtle);padding:1.2rem;text-align:center}.et-query-devtools-cell-actions{display:inline-flex;gap:.4rem;white-space:nowrap}.et-query-devtools-section-row{display:flex;align-items:center;justify-content:space-between;gap:.8rem;margin-block-start:1rem}.et-query-devtools-search{flex:1 1 16rem;min-inline-size:0;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-search:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-row-link{display:inline-flex;align-items:center;gap:.6rem;appearance:none;border:0;background:none;padding:0;color:inherit;font:inherit;text-align:start;cursor:pointer}.et-query-devtools-row-link:focus-visible .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}@media(hover:hover){.et-query-devtools-row-link:hover .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}}.et-query-devtools-hint{flex:1 1 24rem;color:var(--_et-qdt-muted);font-size:1.1rem;margin:0}.et-query-devtools-input{inline-size:100%;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-input:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-input--number{inline-size:8rem;font-variant-numeric:tabular-nums}.et-query-devtools-editor{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);padding:.8rem;margin-block-end:1rem}.et-query-devtools-editor-error{color:var(--_et-qdt-error);margin:.4rem 0 0}.et-query-devtools-btn--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent)}}\n"], dependencies: [{ kind: "component", type: QueryDevtoolsAuthTabComponent, selector: "et-query-devtools-auth-tab" }, { kind: "component", type: QueryDevtoolsBatchesTabComponent, selector: "et-query-devtools-batches-tab" }, { kind: "component", type: QueryDevtoolsCacheTabComponent, selector: "et-query-devtools-cache-tab" }, { kind: "component", type: QueryDevtoolsEventsTabComponent, selector: "et-query-devtools-events-tab" }, { kind: "component", type: QueryDevtoolsAboutComponent, selector: "et-query-devtools-about" }, { kind: "component", type: QueryDevtoolsSettingsComponent, selector: "et-query-devtools-settings" }, { kind: "component", type: QueryDevtoolsFaultsTabComponent, selector: "et-query-devtools-faults-tab" }, { kind: "component", type: QueryDevtoolsFormsTabComponent, selector: "et-query-devtools-forms-tab" }, { kind: "component", type: QueryDevtoolsLocksTabComponent, selector: "et-query-devtools-locks-tab" }, { kind: "component", type: QueryDevtoolsMocksTabComponent, selector: "et-query-devtools-mocks-tab" }, { kind: "component", type: QueryDevtoolsQueriesTabComponent, selector: "et-query-devtools-queries-tab" }, { kind: "component", type: QueryDevtoolsSequencesTabComponent, selector: "et-query-devtools-sequences-tab" }, { kind: "component", type: QueryDevtoolsSocketsTabComponent, selector: "et-query-devtools-sockets-tab" }, { kind: "component", type: QueryDevtoolsStacksTabComponent, selector: "et-query-devtools-stacks-tab" }, { kind: "component", type: QueryDevtoolsTimelineTabComponent, selector: "et-query-devtools-timeline-tab" }, { kind: "component", type: QueryDevtoolsToggleComponent, selector: "et-query-devtools-toggle", inputs: ["tampered"], outputs: ["openChange"] }, { kind: "directive", type: DragHandleDirective, selector: "[etDragHandle]", inputs: ["commitThreshold", "disabled"], outputs: ["dragTapped", "dragStarted", "dragMoved", "dragEnded", "dragCancelled"] }, { kind: "component", type: MenuCheckboxItemComponent, selector: "et-menu-checkbox-item", inputs: ["icon"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "component", type: MenuRadioGroupComponent, selector: "et-menu-radio-group" }, { kind: "component", type: MenuRadioItemComponent, selector: "et-menu-radio-item", inputs: ["icon"] }, { kind: "component", type: MenuSeparatorComponent, selector: "et-menu-separator" }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "component", type: ResizeHandlesComponent, selector: "et-resize-handles", inputs: ["edges", "disabled"], outputs: ["resizeStarted", "resizeMoved", "resizeEnded", "resizeCancelled"] }], encapsulation: i0.ViewEncapsulation.None }); }
7532
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: QueryDevtoolsComponent, isStandalone: true, selector: "et-query-devtools", inputs: { startOpen: { classPropertyName: "startOpen", publicName: "startOpen", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-et-overlay-layer": "2147483020" }, properties: { "attr.data-dock": "dock()" }, classAttribute: "et-query-devtools-host" }, providers: [{ provide: QUERY_DEVTOOLS_HOST, useExisting: QueryDevtoolsComponent }], viewQueries: [{ propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, isSignal: true }, { propertyName: "toggle", first: true, predicate: QueryDevtoolsToggleComponent, descendants: true, isSignal: true }, { propertyName: "tabButtons", predicate: ["tabButton"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <section\n #panel\n [class.et-query-devtools-panel--resizing]=\"resizing()\"\n [attr.data-dock]=\"poppedOut() ? 'popout' : dock()\"\n [attr.data-pane-axis]=\"paneAxis()\"\n [attr.data-parked]=\"floatParked() ? '' : null\"\n [style.block-size.px]=\"panelBlockSize()\"\n [style.inline-size.px]=\"panelInlineSize()\"\n [style.inset-block-start.px]=\"panelInsetBlock()\"\n [style.inset-inline-start.px]=\"panelInsetInline()\"\n [style.--_et-qdt-list-width.px]=\"listWidth()\"\n [style.--_et-qdt-drawer-width.px]=\"drawerWidth()\"\n [style.--_et-qdt-list-height.px]=\"listHeight()\"\n [style.--_et-qdt-drawer-height.px]=\"drawerHeight()\"\n class=\"et-query-devtools-panel\"\n >\n @if (floating()) {\n <et-resize-handles\n [edges]=\"FLOAT_RESIZE_EDGES\"\n [disabled]=\"floatParked()\"\n (resizeStarted)=\"startFloatResize()\"\n (resizeMoved)=\"resizeFloat($event)\"\n (resizeEnded)=\"endFloatResize()\"\n (resizeCancelled)=\"endFloatResize()\"\n />\n <div\n (dragMoved)=\"moveFloat($event)\"\n (dragEnded)=\"endFloatMove()\"\n (dragCancelled)=\"endFloatMove()\"\n (dragTapped)=\"restoreFloat()\"\n class=\"et-query-devtools-move\"\n title=\"Drag to move \u2014 shove it off an edge to park it, click the strip to bring it back\"\n aria-hidden=\"true\"\n etDragHandle\n ></div>\n } @else if (!poppedOut()) {\n <div\n (pointerdown)=\"startResize($event)\"\n class=\"et-query-devtools-resize\"\n title=\"Drag to resize\"\n aria-hidden=\"true\"\n ></div>\n }\n <header class=\"et-query-devtools-header\">\n <nav class=\"et-query-devtools-tabs\" role=\"tablist\">\n @for (tab of visibleTabs(); track tab.id) {\n @let badge = tabBadges()[tab.id];\n <button\n #tabButton\n [class.et-query-devtools-tab--active]=\"activeTab() === tab.id\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n (click)=\"activeTab.set(tab.id)\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (badge.count) {\n <span class=\"et-query-devtools-tab-badge\">{{ badge.count }}</span>\n }\n @if (badge.errors) {\n <span\n class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\"\n title=\"{{ badge.errors }} {{ badge.errorNoun ?? 'failing' }}\"\n >\n {{ badge.errors }}\n </span>\n }\n </button>\n }\n\n @if (overflowTabs().length; as overflowCount) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [title]=\"overflowCount + ' tabs with nothing in them'\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n etMenuTrigger\n >\n More\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n @for (tab of overflowTabs(); track tab.id) {\n <button (activate)=\"activeTab.set(tab.id)\" et-menu-item type=\"button\">{{ tab.label }}</button>\n }\n </et-menu>\n </ng-template>\n </div>\n }\n </nav>\n\n <div class=\"et-query-devtools-header-actions\">\n <button\n [class.et-query-devtools-inspect-btn--active]=\"inspectActive()\"\n [attr.aria-pressed]=\"inspectActive()\"\n (click)=\"toggleInspect()\"\n class=\"et-query-devtools-btn et-query-devtools-inspect-btn\"\n type=\"button\"\n title=\"Inspect: hover the UI to find its query\"\n >\n <svg\n class=\"et-query-devtools-inspect-icon\"\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle class=\"et-query-devtools-inspect-icon-ring\" cx=\"8\" cy=\"8\" r=\"4.25\" />\n <circle class=\"et-query-devtools-inspect-icon-dot\" cx=\"8\" cy=\"8\" r=\"1.15\" />\n <path d=\"M8 0.9v2.1M8 13v2.1M0.9 8h2.1M13 8h2.1\" />\n </svg>\n {{ inspectActive() ? 'Inspecting' : 'Inspect' }}\n @if (inspectActive()) {\n <kbd class=\"et-query-devtools-kbd et-query-devtools-kbd--inverse\">Esc</kbd>\n }\n </button>\n <button\n (click)=\"downloadSession()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every registered entry, the event log, the cache totals and anything armed as one JSON file - the attachment for a bug report\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Session\n </button>\n <button\n [class.et-query-devtools-btn--active]=\"activeTab() === 'settings'\"\n [attr.aria-pressed]=\"activeTab() === 'settings'\"\n (click)=\"toggleSettings()\"\n class=\"et-query-devtools-btn et-query-devtools-icon-btn\"\n type=\"button\"\n title=\"Settings: where panel state is kept, and the limits it holds\"\n aria-label=\"Settings\"\n >\n <span aria-hidden=\"true\">\u2699</span>\n </button>\n @if (!poppedOut()) {\n @let layout = currentLayout();\n <div class=\"et-query-devtools-menu\" etMenu placement=\"bottom-end\">\n <button class=\"et-query-devtools-btn\" title=\"Where the panel sits\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ layout.glyph }}</span>\n {{ layout.label }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <et-menu-radio-group [value]=\"dock()\">\n @for (option of LAYOUTS; track option.id) {\n <!-- eslint-disable ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <et-menu-radio-item\n [value]=\"option.id\"\n [title]=\"option.hint\"\n [closeOnActivate]=\"true\"\n (activate)=\"selectLayout(option.id)\"\n >\n <!-- eslint-enable ethlete/prefer-static-boolean-properties -->\n <span class=\"et-query-devtools-menu-item-glyph\" aria-hidden=\"true\">{{ option.glyph }}</span>\n {{ option.label }}\n </et-menu-radio-item>\n }\n </et-menu-radio-group>\n <et-menu-separator />\n <et-menu-checkbox-item\n [checked]=\"reservesSpace()\"\n [disabled]=\"floating()\"\n (checkedChange)=\"reservesSpace.set($event)\"\n title=\"The page gives up the room the panel covers, so its last rows can still be scrolled to. Docks only - a float sits wherever it was dragged.\"\n >\n Reserve page space\n </et-menu-checkbox-item>\n </et-menu>\n </ng-template>\n </div>\n }\n <span class=\"et-query-devtools-header-divider\" aria-hidden=\"true\"></span>\n <button\n (click)=\"toggleOpen()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n title=\"{{ poppedOut() ? 'Bring the panel back into the app window' : 'Close devtools (' + shortcut + ')' }}\"\n >\n @if (poppedOut()) {\n <span aria-hidden=\"true\">\u29C8</span>\n Dock back\n } @else {\n <span aria-hidden=\"true\">\u2715</span>\n Close\n <kbd class=\"et-query-devtools-kbd\">{{ shortcut }}</kbd>\n }\n </button>\n </div>\n </header>\n\n @if (popOutBlocked()) {\n <div class=\"et-query-devtools-notice-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-text\">\n The browser blocked the pop-up window. Allow pop-ups for this site, or float the panel over the page instead \u2014\n a float needs no permission.\n </span>\n <button (click)=\"floatPanel()\" class=\"et-query-devtools-btn\" type=\"button\">Float instead</button>\n <button (click)=\"popOutBlocked.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Dismiss</button>\n </div>\n }\n\n @if (armedFaultClients(); as armed) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Faults armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ armed.join(', ') }}</span>\n \u2014 every failure and delay you see from\n {{ armed.length === 1 ? 'this client' : 'these clients' }} is injected, not the API.\n @if (faultsRestored()) {\n They came back from your last page load \u2014 set <em>Armed faults</em> back to <em>none</em> in Settings to\n stop that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'faults'\"\n (click)=\"activeTab.set('faults')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"CLEAR_FAULTS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (armedMockRoutes(); as mocked) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Mocks armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ mocked.join(', ') }}</span>\n \u2014 {{ mocked.length === 1 ? 'that route is' : 'those routes are' }} answered by the panel, so nothing they show\n reached the API.\n @if (mocksRestored()) {\n They came back from your last page load \u2014 set <em>Armed mocks</em> back to <em>none</em> in Settings to stop\n that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'mocks'\"\n (click)=\"activeTab.set('mocks')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"DISARM_MOCKS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (restoredOverrides(); as restored) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n @if (restored.ops) {\n <strong>Overrides re-armed</strong> \u2014 {{ restored.ops }} {{ restored.ops === 1 ? 'edit' : 'edits' }} from\n your last page load {{ restored.ops === 1 ? 'is' : 'are' }} back on {{ restored.queries }}\n {{ restored.queries === 1 ? 'query' : 'queries' }}, so those responses are not what the API sent.\n @if (restored.fromLocalStorage) {\n They came back from <strong>localStorage</strong>, so they outlive closing this tab \u2014 clear them, or set\n overrides back to <em>session</em> in Settings.\n }\n } @else {\n <strong>Overrides could not be re-armed.</strong>\n }\n @if (restored.orphaned.length) {\n <span class=\"et-query-devtools-armed-orphans\">\n {{ restored.orphaned.length }} stored\n {{ restored.orphaned.length === 1 ? 'override' : 'overrides' }} matched no query \u2014\n <span class=\"et-query-devtools-mono\">{{ restored.orphaned.join(', ') }}</span>\n </span>\n }\n </span>\n @if (restored.firstId; as firstId) {\n <button (click)=\"reviewRestoredOverrides(firstId)\" class=\"et-query-devtools-btn\" type=\"button\">Review</button>\n }\n <button (click)=\"DROP_RESTORED_OVERRIDES()\" class=\"et-query-devtools-btn\" type=\"button\">Drop all</button>\n </div>\n }\n\n <div class=\"et-query-devtools-body\">\n @switch (activeTab()) {\n @case ('queries') {\n <et-query-devtools-queries-tab />\n }\n\n @case ('stacks') {\n <et-query-devtools-stacks-tab />\n }\n\n @case ('sequences') {\n <et-query-devtools-sequences-tab />\n }\n\n @case ('batches') {\n <et-query-devtools-batches-tab />\n }\n\n @case ('forms') {\n <et-query-devtools-forms-tab />\n }\n\n @case ('auth') {\n <et-query-devtools-auth-tab />\n }\n\n @case ('ws') {\n <et-query-devtools-sockets-tab />\n }\n\n @case ('cache') {\n <et-query-devtools-cache-tab />\n }\n\n @case ('locks') {\n <et-query-devtools-locks-tab />\n }\n\n @case ('timeline') {\n <et-query-devtools-timeline-tab />\n }\n\n @case ('events') {\n <et-query-devtools-events-tab />\n }\n\n @case ('faults') {\n <et-query-devtools-faults-tab />\n }\n\n @case ('mocks') {\n <et-query-devtools-mocks-tab />\n }\n\n @case ('about') {\n <et-query-devtools-about />\n }\n\n @case ('settings') {\n <et-query-devtools-settings />\n }\n }\n </div>\n </section>\n}\n\n@if (!open()) {\n <et-query-devtools-toggle [tampered]=\"panelTampered()\" (openChange)=\"toggleOpen()\" />\n}\n\n@if (inspectActive() && inspectHover(); as hover) {\n <div\n [style.left.px]=\"hover.rect.left\"\n [style.top.px]=\"hover.rect.top\"\n [style.width.px]=\"hover.rect.width\"\n [style.height.px]=\"hover.rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">{{ inspectLabel(hover.entries) }}</span>\n </div>\n}\n\n@if (locatedRect(); as rect) {\n <div\n [style.left.px]=\"rect.left\"\n [style.top.px]=\"rect.top\"\n [style.width.px]=\"rect.width\"\n [style.height.px]=\"rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">created here</span>\n </div>\n}\n", styles: ["@layer components{.et-query-devtools-host{--_et-qdt-bg: var(--et-surface-background-solid, rgb(24 24 27));--_et-qdt-fg: var(--et-surface-color-solid, rgb(244 244 245));--_et-qdt-muted: var(--et-surface-color-muted-solid, rgb(161 161 170));--_et-qdt-subtle: var(--et-surface-color-subtle-solid, rgb(113 113 122));--_et-qdt-border: var(--et-surface-border-solid, rgb(255 255 255 / .12));--_et-qdt-interaction: var(--et-surface-interaction-solid, rgb(255 255 255));--_et-qdt-line: color-mix(in srgb, var(--_et-qdt-interaction) 24%, transparent);--_et-qdt-line-strong: color-mix(in srgb, var(--_et-qdt-interaction) 42%, transparent);--_et-qdt-accent: var(--et-theme-color-primary-solid, rgb(96 165 250));--_et-qdt-on-accent: var(--et-theme-color-on-primary, #09090b);--_et-qdt-hover: color-mix(in srgb, var(--_et-qdt-interaction) 10%, transparent);--_et-qdt-field: color-mix(in srgb, var(--_et-qdt-interaction) 8%, transparent);--_et-qdt-active: color-mix(in srgb, var(--_et-qdt-interaction) 18%, transparent);--_et-qdt-success: rgb(34 197 94);--_et-qdt-error: rgb(239 68 68);--_et-qdt-loading: rgb(234 179 8);--_et-qdt-title-bar: 2.4rem;--_et-qdt-radius-sm: .3rem;--_et-qdt-radius: .5rem;--_et-qdt-radius-lg: .6rem;--_et-qdt-control-h: 2.4rem;--_et-qdt-row-h: 3.6rem;position:fixed;inset-inline:0;inset-block-end:0;z-index:2147483010;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,Liberation Mono,monospace;font-size:1.2rem;line-height:1.4;pointer-events:none}.et-query-devtools-host>*{pointer-events:auto}@media(pointer:coarse){.et-query-devtools-host{--_et-qdt-control-h: 3.4rem;--_et-qdt-row-h: 4.4rem}}.et-query-devtools-panel{position:relative;display:flex;flex-direction:column;inline-size:100%;min-block-size:20rem;max-block-size:90vh;background:var(--_et-qdt-bg);color:var(--_et-qdt-fg);border-block-start:1px solid var(--_et-qdt-border);box-shadow:0 -.4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=right]){inset-block:0;inset-inline-start:auto}.et-query-devtools-panel:where([data-dock=right]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-start:1px solid var(--_et-qdt-border);box-shadow:-.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=float]){inset:0}.et-query-devtools-panel:where([data-dock=float]){--_et-qdt-frame: .8rem;--et-resize-handles-edge-size: var(--_et-qdt-frame);--et-resize-handles-touch-edge-size: var(--_et-qdt-frame);--et-resize-handles-corner-size: 1.6rem;--et-resize-handles-touch-corner-size: 1.6rem;--et-resize-handles-edge-inset: 1.6rem;--et-resize-handles-side-top: var(--_et-qdt-title-bar);--et-resize-handles-side-bottom: 1.6rem;--et-resize-handles-z-index: 3;position:absolute;inline-size:auto;min-block-size:0;max-block-size:none;padding-block-start:var(--_et-qdt-title-bar);padding-inline:var(--_et-qdt-frame);padding-block-end:var(--_et-qdt-frame);border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);box-shadow:0 1rem 4rem #00000073;overflow:hidden}.et-query-devtools-move{position:absolute;inset-inline:0;inset-block-start:0;block-size:var(--_et-qdt-title-bar);cursor:move;z-index:2}.et-query-devtools-panel:where([data-dock=float]) .et-query-devtools-body{border-radius:var(--_et-qdt-radius-sm);overflow:hidden}.et-query-devtools-move:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.9rem;inline-size:3rem;margin-inline-start:-1.5rem;block-size:.6rem;background-image:radial-gradient(currentcolor 40%,transparent 42%);background-size:.4rem .3rem;color:var(--_et-qdt-subtle)}@media(hover:hover){.et-query-devtools-move:hover:after{color:var(--_et-qdt-accent)}}.et-query-devtools-panel:where([data-dock=float][data-parked]){opacity:.85}@media(hover:hover){.et-query-devtools-panel:where([data-dock=float][data-parked]):hover{opacity:1}}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move{cursor:grab;background:var(--_et-qdt-active)}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move:after{color:var(--_et-qdt-accent)}.et-query-devtools-host:where([data-dock=left]){inset-block:0;inset-inline-end:auto}.et-query-devtools-panel:where([data-dock=left]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-end:1px solid var(--_et-qdt-border);box-shadow:.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=top]){inset-block-start:0;inset-block-end:auto}.et-query-devtools-panel:where([data-dock=top]){border-block-start:0;border-block-end:1px solid var(--_et-qdt-border);box-shadow:0 .4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=popout]){position:static;inline-size:100%;block-size:100%}.et-query-devtools-panel:where([data-dock=popout]){block-size:100%;max-block-size:none;border:0;box-shadow:none}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-header{flex-wrap:wrap}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions){flex:1 1 auto;flex-wrap:nowrap;min-inline-size:0;overflow-x:auto}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions)>*{flex:none}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-master-detail,.et-query-devtools-split){flex-direction:column}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-list,.et-query-devtools-detail,.et-query-devtools-drawer,.et-query-devtools-split .et-query-devtools-scroll){flex:1 1 50%;min-inline-size:0;min-block-size:0;max-inline-size:none;border-inline-start:0;border-inline-end:0}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-detail,.et-query-devtools-drawer){border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-master-detail>.et-query-devtools-list{flex:0 1 var(--_et-qdt-list-height, 50%);min-block-size:var(--_et-qdt-list-height, 0);max-block-size:var(--_et-qdt-list-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-split .et-query-devtools-drawer{flex:0 1 var(--_et-qdt-drawer-height, 50%);min-block-size:var(--_et-qdt-drawer-height, 0);max-block-size:var(--_et-qdt-drawer-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-pane-resize{cursor:ns-resize}.et-query-devtools-panel--resizing{-webkit-user-select:none;user-select:none}.et-query-devtools-resize,.et-query-devtools-pane-resize{touch-action:none}.et-query-devtools-resize{position:absolute;inset-inline:0;inset-block-start:0;block-size:.6rem;cursor:ns-resize;z-index:1}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize{inset-inline:0 auto;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize{inset-inline:auto 0;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize{inset-block:auto 0}.et-query-devtools-resize:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.2rem;inline-size:4rem;margin-inline-start:-2rem;block-size:.2rem;border-radius:999px;background:var(--_et-qdt-border)}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize:after{inset-inline:.2rem auto;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize:after{inset-inline:auto .2rem;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize:after{inset-block:auto .2rem}@media(hover:hover){.et-query-devtools-resize:hover:after{background:var(--_et-qdt-accent)}}.et-query-devtools-header{display:flex;align-items:center;justify-content:space-between;gap:.8rem;padding-inline:.8rem;border-block-end:1px solid var(--_et-qdt-border);flex:0 0 auto}.et-query-devtools-armed-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-block-end:1px solid color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-armed-text{flex:1 1 auto;min-inline-size:0}.et-query-devtools-notice-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:var(--_et-qdt-hover);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg);font-size:1.1rem}.et-query-devtools-notice-bar .et-query-devtools-btn{flex:0 0 auto}.et-query-devtools-armed-orphans{display:block;opacity:.85}.et-query-devtools-armed-dot{flex:0 0 auto;inline-size:.8rem;block-size:.8rem;border-radius:50%;background:var(--_et-qdt-error);animation:et-query-devtools-armed-pulse 1.6s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.et-query-devtools-armed-dot{animation:none}}@keyframes et-query-devtools-armed-pulse{50%{opacity:.25}}.et-query-devtools-armed-bar .et-query-devtools-btn{flex:0 0 auto;border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-tabs{display:flex;flex-wrap:wrap;gap:.2rem}.et-query-devtools-tab{appearance:none;display:inline-flex;align-items:center;gap:.5rem;border:none;background:transparent;color:var(--_et-qdt-muted);padding:.9rem 1rem;cursor:pointer;border-block-end:2px solid transparent;font:inherit}@media(hover:hover){.et-query-devtools-tab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-tab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-tab-badge{display:inline-block;padding-inline:.45rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-interaction) 12%,transparent);color:var(--_et-qdt-muted);font-size:1rem;font-variant-numeric:tabular-nums}.et-query-devtools-tab-badge--error{background:color-mix(in srgb,var(--_et-qdt-error) 25%,transparent);color:var(--_et-qdt-fg)}.et-query-devtools-menu{display:contents}.et-query-devtools-menu-caret{font-size:.9em;opacity:.7}.et-query-devtools-menu-glyph{display:inline-block;min-inline-size:1.2rem;text-align:center}.et-query-devtools-menu>[data-menu-open]{background:var(--_et-qdt-hover);color:var(--_et-qdt-fg)}.et-menu .et-query-devtools-menu-item-glyph{display:inline-block;inline-size:16px;text-align:center}.et-menu-item-content:has(.et-query-devtools-menu-item-note){display:flex;flex-direction:column;align-items:start;gap:2px;padding-block:8px}.et-query-devtools-menu-item-note{color:var(--et-surface-color-muted-solid, rgb(255 255 255 / .55));font-size:12px}.et-query-devtools-header-actions{display:flex;align-items:center;gap:.2rem;flex:0 0 auto}.et-query-devtools-header-divider{inline-size:1px;block-size:1.6rem;margin-inline:.4rem;background:var(--_et-qdt-border)}.et-query-devtools-inspect-btn{position:relative}.et-query-devtools-inspect-icon{inline-size:1.4rem;block-size:1.4rem;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.25;stroke-linecap:round}.et-query-devtools-inspect-icon-dot{fill:currentColor;stroke:none}.et-query-devtools-btn.et-query-devtools-inspect-btn--active,.et-query-devtools-btn.et-query-devtools-inspect-btn--active:hover{color:var(--_et-qdt-on-accent);background:var(--_et-qdt-accent);border-color:var(--_et-qdt-accent)}.et-query-devtools-inspect-btn--active:after{content:\"\";position:absolute;inset:-.3rem;border:1px solid var(--_et-qdt-accent);border-radius:calc(var(--_et-qdt-radius) + .3rem);pointer-events:none;animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}@keyframes et-query-devtools-inspect-pulse{0%,to{opacity:.2}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.et-query-devtools-inspect-btn--active:after,.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:none;opacity:1}}.et-query-devtools-kbd{border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-hover);box-shadow:inset 0 0 0 1px var(--_et-qdt-border);color:var(--_et-qdt-muted);padding:.15rem .4rem;font:inherit;font-size:1.1rem;line-height:1.2;white-space:nowrap}.et-query-devtools-kbd--inverse{background:#00000026;box-shadow:inset 0 0 0 1px #00000040;color:inherit}@media(hover:none)and (pointer:coarse){.et-query-devtools-kbd{display:none}}.et-query-devtools-inspect-box{position:fixed;z-index:2147483002;pointer-events:none;border:2px solid var(--_et-qdt-accent);background:color-mix(in srgb,var(--_et-qdt-accent) 15%,transparent);border-radius:var(--_et-qdt-radius-sm)}.et-query-devtools-inspect-tag{position:absolute;inset-block-start:100%;inset-inline-start:0;margin-block-start:.2rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);font-family:ui-monospace,monospace;font-size:1.1rem;font-weight:600;white-space:nowrap}.et-query-devtools-panel :is(a,button,input,select,summary,textarea,[tabindex]):focus-visible{outline:2px solid var(--_et-qdt-accent);outline-offset:1px}.et-query-devtools-body{flex:1 1 auto;min-block-size:0;overflow:hidden}.et-query-devtools-detail{flex:1 1 auto;min-inline-size:0;overflow-y:auto;padding:1rem}.et-query-devtools-detail .et-query-devtools-meta,.et-query-devtools-drawer .et-query-devtools-meta{padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-detail .et-query-devtools-section-row,.et-query-devtools-drawer .et-query-devtools-section-row{padding-block-start:.8rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-filter-chip{display:inline-flex;align-items:center;gap:.6rem;padding:.3rem .35rem .3rem .7rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_et-qdt-accent) 45%,transparent);color:var(--_et-qdt-accent);font-size:1.1rem;font-weight:600;letter-spacing:.02em}.et-query-devtools-filter-icon{font-size:1.3rem;line-height:1}.et-query-devtools-filter-count{border-radius:999px;background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);min-inline-size:1.8rem;padding:0 .5rem;text-align:center}.et-query-devtools-filter-clear{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-filter-clear:hover{border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent);color:var(--_et-qdt-fg)}}.et-query-devtools-scroll{block-size:100%;overflow:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.et-query-devtools-split{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-split .et-query-devtools-scroll{flex:1 1 auto;min-inline-size:0}.et-query-devtools-pane{display:flex;flex-direction:column;flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:hidden}.et-query-devtools-pane>.et-query-devtools-scroll{padding-block:0 1rem}.et-query-devtools-pane-resize{flex:0 0 .5rem;align-self:stretch;cursor:ew-resize;background:transparent;transition:background .12s ease}.et-query-devtools-pane-resize:active{background:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-pane-resize:hover{background:var(--_et-qdt-accent)}}.et-query-devtools-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem;padding:.8rem;position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-scroll>.et-query-devtools-toolbar{inset-block-start:-1rem}.et-query-devtools-toolbar-row{display:flex;align-items:center;flex-wrap:wrap;flex:1 1 100%;gap:.5rem}.et-query-devtools-field{display:inline-flex;align-items:center;gap:.6rem;color:var(--_et-qdt-muted)}.et-query-devtools-select{flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);background:color-mix(in srgb,var(--_et-qdt-interaction) 8%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-select:focus-visible{border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent)}.et-query-devtools-select option{background-color:var(--_et-qdt-bg);color:var(--_et-qdt-fg)}.et-query-devtools-count{color:var(--_et-qdt-subtle)}.et-query-devtools-row{display:flex;align-items:stretch;inline-size:100%;min-block-size:var(--_et-qdt-row-h);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg)}@media(hover:hover){.et-query-devtools-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-method{font-weight:700;font-size:1.1rem;color:var(--_et-qdt-muted);white-space:nowrap}.et-query-devtools-route{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;min-inline-size:0}.et-query-devtools-status{inline-size:.8rem;block-size:.8rem;border-radius:999px;flex:0 0 auto;background:var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-status[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-status[data-status=parked]{background:transparent;box-shadow:inset 0 0 0 2px var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=loading],.et-query-devtools-status[data-status=running]{background:var(--_et-qdt-loading)}.et-query-devtools-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4;white-space:nowrap;cursor:pointer;transition:color .12s ease,background-color .12s ease,border-color .12s ease}@media(hover:hover){.et-query-devtools-btn:hover:not(:disabled){background:var(--_et-qdt-hover);border-color:var(--_et-qdt-line-strong);color:var(--_et-qdt-fg)}}.et-query-devtools-btn:disabled{border-color:var(--_et-qdt-border);color:var(--_et-qdt-subtle);cursor:default;background:transparent;opacity:.6}.et-query-devtools-btn--primary,.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 40%,transparent);color:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 26%,transparent)}}.et-query-devtools-btn--danger{border-color:color-mix(in srgb,var(--_et-qdt-error) 32%,transparent);color:color-mix(in srgb,var(--_et-qdt-error) 55%,var(--_et-qdt-fg))}@media(hover:hover){.et-query-devtools-btn--danger:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}}.et-query-devtools-btn--tampered,.et-query-devtools-btn--tampered:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-icon-btn{inline-size:var(--_et-qdt-control-h);padding-inline:0;font-size:1.3rem}.et-query-devtools-btn-group{display:inline-flex;flex:0 0 auto;border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);overflow:hidden}.et-query-devtools-btn-group>.et-query-devtools-btn{border-radius:0;border-block:0;border-inline-start:0;border-inline-end:1px solid var(--_et-qdt-line)}.et-query-devtools-btn-group>.et-query-devtools-btn:last-child{border-inline-end:0}.et-query-devtools-btn-group>.et-query-devtools-btn:focus-visible{outline-offset:-2px}.et-query-devtools-toolbar-btn{margin-inline-start:auto;flex:0 0 auto}.et-query-devtools-meta{display:grid;grid-template-columns:auto 1fr;gap:.3rem 1rem;margin:0 0 1rem}.et-query-devtools-meta dt{color:var(--_et-qdt-muted)}.et-query-devtools-meta dd{margin:0;overflow-wrap:anywhere}.et-query-devtools-section{margin:1rem 0 .4rem;font-size:1.1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat{padding:.6rem .8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-stat dt{font-size:1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat dd{margin:0;font-size:1.5rem;font-variant-numeric:tabular-nums}.et-query-devtools-stat-sub{display:block;font-size:1rem;color:var(--_et-qdt-subtle)}.et-query-devtools-json{margin:0;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow-x:auto;white-space:pre-wrap;overflow-wrap:anywhere;max-block-size:24rem;overflow-y:auto}.et-query-devtools-json--error{border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-mono{font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.et-query-devtools-url{display:inline-block;max-inline-size:32rem;margin-inline-start:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.et-query-devtools-chips,.et-query-devtools-chip-row{display:flex;flex-wrap:wrap;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-chip{display:inline-flex;align-items:center;gap:.3rem;padding:.2rem .6rem;border-radius:999px;border:1px solid var(--_et-qdt-border);font-size:1.1rem;color:var(--_et-qdt-fg);background:color-mix(in srgb,var(--_et-qdt-interaction) 6%,transparent)}.et-query-devtools-chip--muted{color:var(--_et-qdt-muted)}.et-query-devtools-retry-glyph{font-size:.7em;line-height:1}.et-query-devtools-chip--loading{color:var(--_et-qdt-loading);border-color:color-mix(in srgb,var(--_et-qdt-loading) 50%,transparent)}.et-query-devtools-chip--error{color:var(--_et-qdt-error);border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-chip--success{color:var(--_et-qdt-success);border-color:color-mix(in srgb,var(--_et-qdt-success) 50%,transparent)}button.et-query-devtools-chip--button{appearance:none;border-color:var(--_et-qdt-line);cursor:pointer;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}@media(hover:hover){button.et-query-devtools-chip--button:hover{border-color:var(--_et-qdt-accent);color:var(--_et-qdt-accent)}}.et-query-devtools-facet{appearance:none;border-color:var(--_et-qdt-line);min-block-size:var(--_et-qdt-control-h);padding-inline:.8rem;background:transparent;cursor:pointer;color:var(--_et-qdt-muted);font:inherit;font-size:1.1rem;line-height:1.4}@media(hover:hover){.et-query-devtools-facet:hover:not(:disabled){color:var(--_et-qdt-fg);background:var(--_et-qdt-hover);border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent)}}.et-query-devtools-facet:disabled{color:var(--_et-qdt-subtle);cursor:default}.et-query-devtools-facet--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 14%,transparent)}.et-query-devtools-facet-count{font-variant-numeric:tabular-nums;color:inherit;opacity:.75}.et-query-devtools-card{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);padding:1rem}.et-query-devtools-card--armed{border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-card-head{display:flex;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-inner-queries{display:flex;flex-direction:column;gap:.3rem}.et-query-devtools-inner-row{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.4rem .6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-inner-row:hover:not([disabled]){background:var(--_et-qdt-hover)}}.et-query-devtools-inner-row--active{background:var(--_et-qdt-active);border-color:var(--_et-qdt-accent)}.et-query-devtools-inner-row[disabled]{cursor:default;opacity:.6}.et-query-devtools-step-toggle{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:none;background:transparent;color:var(--_et-qdt-fg);padding:.6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-step-toggle:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-step-index{flex:1 1 auto;min-inline-size:0}.et-query-devtools-step-caret{color:var(--_et-qdt-muted)}.et-query-devtools-table{inline-size:100%;border-collapse:collapse}.et-query-devtools-table-scroll{overflow-x:auto}.et-query-devtools-table-scroll>.et-query-devtools-table{min-inline-size:max-content}.et-query-devtools-table th,.et-query-devtools-table td{text-align:start;padding:.5rem .6rem;border-block-end:1px solid var(--_et-qdt-border);vertical-align:top}.et-query-devtools-table td .et-query-devtools-chip{padding-block:0;line-height:1.4}.et-query-devtools-table th{color:var(--_et-qdt-muted);font-weight:600;position:sticky;inset-block-start:0;background:var(--_et-qdt-bg)}.et-query-devtools-table tr[data-status=error] td{color:var(--_et-qdt-error)}.et-query-devtools-table .et-query-devtools-cell-origin{inline-size:12ch;max-inline-size:12ch;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;overflow-wrap:normal}.et-query-devtools-empty{color:var(--_et-qdt-subtle);padding:1.2rem;text-align:center}.et-query-devtools-cell-actions{display:inline-flex;gap:.4rem;white-space:nowrap}.et-query-devtools-section-row{display:flex;align-items:center;justify-content:space-between;gap:.8rem;margin-block-start:1rem}.et-query-devtools-search{flex:1 1 16rem;min-inline-size:0;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-search:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-row-link{display:inline-flex;align-items:center;gap:.6rem;appearance:none;border:0;background:none;padding:0;color:inherit;font:inherit;text-align:start;cursor:pointer}.et-query-devtools-row-link:focus-visible .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}@media(hover:hover){.et-query-devtools-row-link:hover .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}}.et-query-devtools-hint{flex:1 1 24rem;color:var(--_et-qdt-muted);font-size:1.1rem;margin:0}.et-query-devtools-input{inline-size:100%;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-input:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-input--number{inline-size:8rem;font-variant-numeric:tabular-nums}.et-query-devtools-editor{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);padding:.8rem;margin-block-end:1rem}.et-query-devtools-editor-error{color:var(--_et-qdt-error);margin:.4rem 0 0}.et-query-devtools-btn--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent)}}\n"], dependencies: [{ kind: "component", type: QueryDevtoolsAuthTabComponent, selector: "et-query-devtools-auth-tab" }, { kind: "component", type: QueryDevtoolsBatchesTabComponent, selector: "et-query-devtools-batches-tab" }, { kind: "component", type: QueryDevtoolsCacheTabComponent, selector: "et-query-devtools-cache-tab" }, { kind: "component", type: QueryDevtoolsEventsTabComponent, selector: "et-query-devtools-events-tab" }, { kind: "component", type: QueryDevtoolsAboutComponent, selector: "et-query-devtools-about" }, { kind: "component", type: QueryDevtoolsSettingsComponent, selector: "et-query-devtools-settings" }, { kind: "component", type: QueryDevtoolsFaultsTabComponent, selector: "et-query-devtools-faults-tab" }, { kind: "component", type: QueryDevtoolsFormsTabComponent, selector: "et-query-devtools-forms-tab" }, { kind: "component", type: QueryDevtoolsLocksTabComponent, selector: "et-query-devtools-locks-tab" }, { kind: "component", type: QueryDevtoolsMocksTabComponent, selector: "et-query-devtools-mocks-tab" }, { kind: "component", type: QueryDevtoolsQueriesTabComponent, selector: "et-query-devtools-queries-tab" }, { kind: "component", type: QueryDevtoolsSequencesTabComponent, selector: "et-query-devtools-sequences-tab" }, { kind: "component", type: QueryDevtoolsSocketsTabComponent, selector: "et-query-devtools-sockets-tab" }, { kind: "component", type: QueryDevtoolsStacksTabComponent, selector: "et-query-devtools-stacks-tab" }, { kind: "component", type: QueryDevtoolsTimelineTabComponent, selector: "et-query-devtools-timeline-tab" }, { kind: "component", type: QueryDevtoolsToggleComponent, selector: "et-query-devtools-toggle", inputs: ["tampered", "loadFailed"], outputs: ["openChange"] }, { kind: "directive", type: DragHandleDirective, selector: "[etDragHandle]", inputs: ["commitThreshold", "disabled"], outputs: ["dragTapped", "dragStarted", "dragMoved", "dragEnded", "dragCancelled"] }, { kind: "component", type: MenuCheckboxItemComponent, selector: "et-menu-checkbox-item", inputs: ["icon"] }, { kind: "component", type: MenuComponent, selector: "et-menu" }, { kind: "directive", type: MenuDirective, selector: "[etMenu]", inputs: ["placement", "fallbackPlacements", "offset", "viewportPadding", "arrow", "arrowPadding", "autoFocus", "hoverOpen", "loop", "hoverOpenDelay", "hoverCloseDelay", "disabled", "open"], outputs: ["openChange"], exportAs: ["etMenu"] }, { kind: "component", type: MenuItemComponent, selector: "button[et-menu-item], a[et-menu-item]", inputs: ["variant"] }, { kind: "component", type: MenuRadioGroupComponent, selector: "et-menu-radio-group" }, { kind: "component", type: MenuRadioItemComponent, selector: "et-menu-radio-item", inputs: ["icon"] }, { kind: "component", type: MenuSeparatorComponent, selector: "et-menu-separator" }, { kind: "directive", type: MenuSurfaceDirective, selector: "ng-template[etMenuSurface]", exportAs: ["etMenuSurface"] }, { kind: "directive", type: MenuTriggerDirective, selector: "[etMenuTrigger]", exportAs: ["etMenuTrigger"] }, { kind: "component", type: ResizeHandlesComponent, selector: "et-resize-handles", inputs: ["edges", "disabled"], outputs: ["resizeStarted", "resizeMoved", "resizeEnded", "resizeCancelled"] }], encapsulation: i0.ViewEncapsulation.None }); }
7446
7533
  }
7447
7534
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: QueryDevtoolsComponent, decorators: [{
7448
7535
  type: Component,
@@ -7481,8 +7568,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
7481
7568
  // the panel's own z-index, which is itself above the default overlay layer. Both numbers live in
7482
7569
  // query-devtools.component.css; keep them in step.
7483
7570
  'data-et-overlay-layer': '2147483020',
7484
- }, template: "@if (open()) {\n <section\n #panel\n [class.et-query-devtools-panel--resizing]=\"resizing()\"\n [attr.data-dock]=\"poppedOut() ? 'popout' : dock()\"\n [attr.data-pane-axis]=\"paneAxis()\"\n [attr.data-parked]=\"floatParked() ? '' : null\"\n [style.block-size.px]=\"panelBlockSize()\"\n [style.inline-size.px]=\"panelInlineSize()\"\n [style.inset-block-start.px]=\"panelInsetBlock()\"\n [style.inset-inline-start.px]=\"panelInsetInline()\"\n [style.--_et-qdt-list-width.px]=\"listWidth()\"\n [style.--_et-qdt-drawer-width.px]=\"drawerWidth()\"\n [style.--_et-qdt-list-height.px]=\"listHeight()\"\n [style.--_et-qdt-drawer-height.px]=\"drawerHeight()\"\n class=\"et-query-devtools-panel\"\n >\n @if (floating()) {\n <et-resize-handles\n [edges]=\"FLOAT_RESIZE_EDGES\"\n [disabled]=\"floatParked()\"\n (resizeStarted)=\"startFloatResize()\"\n (resizeMoved)=\"resizeFloat($event)\"\n (resizeEnded)=\"endFloatResize()\"\n (resizeCancelled)=\"endFloatResize()\"\n />\n <div\n (dragMoved)=\"moveFloat($event)\"\n (dragEnded)=\"endFloatMove()\"\n (dragCancelled)=\"endFloatMove()\"\n (dragTapped)=\"restoreFloat()\"\n class=\"et-query-devtools-move\"\n title=\"Drag to move \u2014 shove it off an edge to park it, click the strip to bring it back\"\n aria-hidden=\"true\"\n etDragHandle\n ></div>\n } @else if (!poppedOut()) {\n <div\n (pointerdown)=\"startResize($event)\"\n class=\"et-query-devtools-resize\"\n title=\"Drag to resize\"\n aria-hidden=\"true\"\n ></div>\n }\n <header class=\"et-query-devtools-header\">\n <nav class=\"et-query-devtools-tabs\" role=\"tablist\">\n @for (tab of visibleTabs(); track tab.id) {\n @let badge = tabBadges()[tab.id];\n <button\n [class.et-query-devtools-tab--active]=\"activeTab() === tab.id\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n (click)=\"activeTab.set(tab.id)\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (badge.count) {\n <span class=\"et-query-devtools-tab-badge\">{{ badge.count }}</span>\n }\n @if (badge.errors) {\n <span\n class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\"\n title=\"{{ badge.errors }} {{ badge.errorNoun ?? 'failing' }}\"\n >\n {{ badge.errors }}\n </span>\n }\n </button>\n }\n\n @if (overflowTabs().length; as overflowCount) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [title]=\"overflowCount + ' tabs with nothing in them'\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n etMenuTrigger\n >\n More\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n @for (tab of overflowTabs(); track tab.id) {\n <button (activate)=\"activeTab.set(tab.id)\" et-menu-item type=\"button\">{{ tab.label }}</button>\n }\n </et-menu>\n </ng-template>\n </div>\n }\n </nav>\n\n <div class=\"et-query-devtools-header-actions\">\n <button\n [class.et-query-devtools-inspect-btn--active]=\"inspectActive()\"\n [attr.aria-pressed]=\"inspectActive()\"\n (click)=\"toggleInspect()\"\n class=\"et-query-devtools-btn et-query-devtools-inspect-btn\"\n type=\"button\"\n title=\"Inspect: hover the UI to find its query\"\n >\n <svg\n class=\"et-query-devtools-inspect-icon\"\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle class=\"et-query-devtools-inspect-icon-ring\" cx=\"8\" cy=\"8\" r=\"4.25\" />\n <circle class=\"et-query-devtools-inspect-icon-dot\" cx=\"8\" cy=\"8\" r=\"1.15\" />\n <path d=\"M8 0.9v2.1M8 13v2.1M0.9 8h2.1M13 8h2.1\" />\n </svg>\n {{ inspectActive() ? 'Inspecting' : 'Inspect' }}\n @if (inspectActive()) {\n <kbd class=\"et-query-devtools-kbd et-query-devtools-kbd--inverse\">Esc</kbd>\n }\n </button>\n <button\n (click)=\"downloadSession()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every registered entry, the event log, the cache totals and anything armed as one JSON file - the attachment for a bug report\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Session\n </button>\n <button\n [class.et-query-devtools-btn--active]=\"activeTab() === 'settings'\"\n [attr.aria-pressed]=\"activeTab() === 'settings'\"\n (click)=\"toggleSettings()\"\n class=\"et-query-devtools-btn et-query-devtools-icon-btn\"\n type=\"button\"\n title=\"Settings: where panel state is kept, and the limits it holds\"\n aria-label=\"Settings\"\n >\n <span aria-hidden=\"true\">\u2699</span>\n </button>\n @if (!poppedOut()) {\n @let layout = currentLayout();\n <div class=\"et-query-devtools-menu\" etMenu placement=\"bottom-end\">\n <button class=\"et-query-devtools-btn\" title=\"Where the panel sits\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ layout.glyph }}</span>\n {{ layout.label }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <et-menu-radio-group [value]=\"dock()\">\n @for (option of LAYOUTS; track option.id) {\n <!-- eslint-disable ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <et-menu-radio-item\n [value]=\"option.id\"\n [title]=\"option.hint\"\n [closeOnActivate]=\"true\"\n (activate)=\"selectLayout(option.id)\"\n >\n <!-- eslint-enable ethlete/prefer-static-boolean-properties -->\n <span class=\"et-query-devtools-menu-item-glyph\" aria-hidden=\"true\">{{ option.glyph }}</span>\n {{ option.label }}\n </et-menu-radio-item>\n }\n </et-menu-radio-group>\n <et-menu-separator />\n <et-menu-checkbox-item\n [checked]=\"reservesSpace()\"\n [disabled]=\"floating()\"\n (checkedChange)=\"reservesSpace.set($event)\"\n title=\"The page gives up the room the panel covers, so its last rows can still be scrolled to. Docks only - a float sits wherever it was dragged.\"\n >\n Reserve page space\n </et-menu-checkbox-item>\n </et-menu>\n </ng-template>\n </div>\n }\n <span class=\"et-query-devtools-header-divider\" aria-hidden=\"true\"></span>\n <button\n (click)=\"toggleOpen()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n title=\"{{ poppedOut() ? 'Bring the panel back into the app window' : 'Close devtools (' + shortcut + ')' }}\"\n >\n @if (poppedOut()) {\n <span aria-hidden=\"true\">\u29C8</span>\n Dock back\n } @else {\n <span aria-hidden=\"true\">\u2715</span>\n Close\n <kbd class=\"et-query-devtools-kbd\">{{ shortcut }}</kbd>\n }\n </button>\n </div>\n </header>\n\n @if (popOutBlocked()) {\n <div class=\"et-query-devtools-notice-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-text\">\n The browser blocked the pop-up window. Allow pop-ups for this site, or float the panel over the page instead \u2014\n a float needs no permission.\n </span>\n <button (click)=\"floatPanel()\" class=\"et-query-devtools-btn\" type=\"button\">Float instead</button>\n <button (click)=\"popOutBlocked.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Dismiss</button>\n </div>\n }\n\n @if (armedFaultClients(); as armed) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Faults armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ armed.join(', ') }}</span>\n \u2014 every failure and delay you see from\n {{ armed.length === 1 ? 'this client' : 'these clients' }} is injected, not the API.\n @if (faultsRestored()) {\n They came back from your last page load \u2014 set <em>Armed faults</em> back to <em>none</em> in Settings to\n stop that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'faults'\"\n (click)=\"activeTab.set('faults')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"CLEAR_FAULTS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (armedMockRoutes(); as mocked) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Mocks armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ mocked.join(', ') }}</span>\n \u2014 {{ mocked.length === 1 ? 'that route is' : 'those routes are' }} answered by the panel, so nothing they show\n reached the API.\n @if (mocksRestored()) {\n They came back from your last page load \u2014 set <em>Armed mocks</em> back to <em>none</em> in Settings to stop\n that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'mocks'\"\n (click)=\"activeTab.set('mocks')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"DISARM_MOCKS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (restoredOverrides(); as restored) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n @if (restored.ops) {\n <strong>Overrides re-armed</strong> \u2014 {{ restored.ops }} {{ restored.ops === 1 ? 'edit' : 'edits' }} from\n your last page load {{ restored.ops === 1 ? 'is' : 'are' }} back on {{ restored.queries }}\n {{ restored.queries === 1 ? 'query' : 'queries' }}, so those responses are not what the API sent.\n @if (restored.fromLocalStorage) {\n They came back from <strong>localStorage</strong>, so they outlive closing this tab \u2014 clear them, or set\n overrides back to <em>session</em> in Settings.\n }\n } @else {\n <strong>Overrides could not be re-armed.</strong>\n }\n @if (restored.orphaned.length) {\n <span class=\"et-query-devtools-armed-orphans\">\n {{ restored.orphaned.length }} stored\n {{ restored.orphaned.length === 1 ? 'override' : 'overrides' }} matched no query \u2014\n <span class=\"et-query-devtools-mono\">{{ restored.orphaned.join(', ') }}</span>\n </span>\n }\n </span>\n @if (restored.firstId; as firstId) {\n <button (click)=\"reviewRestoredOverrides(firstId)\" class=\"et-query-devtools-btn\" type=\"button\">Review</button>\n }\n <button (click)=\"DROP_RESTORED_OVERRIDES()\" class=\"et-query-devtools-btn\" type=\"button\">Drop all</button>\n </div>\n }\n\n <div class=\"et-query-devtools-body\">\n @switch (activeTab()) {\n @case ('queries') {\n <et-query-devtools-queries-tab />\n }\n\n @case ('stacks') {\n <et-query-devtools-stacks-tab />\n }\n\n @case ('sequences') {\n <et-query-devtools-sequences-tab />\n }\n\n @case ('batches') {\n <et-query-devtools-batches-tab />\n }\n\n @case ('forms') {\n <et-query-devtools-forms-tab />\n }\n\n @case ('auth') {\n <et-query-devtools-auth-tab />\n }\n\n @case ('ws') {\n <et-query-devtools-sockets-tab />\n }\n\n @case ('cache') {\n <et-query-devtools-cache-tab />\n }\n\n @case ('locks') {\n <et-query-devtools-locks-tab />\n }\n\n @case ('timeline') {\n <et-query-devtools-timeline-tab />\n }\n\n @case ('events') {\n <et-query-devtools-events-tab />\n }\n\n @case ('faults') {\n <et-query-devtools-faults-tab />\n }\n\n @case ('mocks') {\n <et-query-devtools-mocks-tab />\n }\n\n @case ('about') {\n <et-query-devtools-about />\n }\n\n @case ('settings') {\n <et-query-devtools-settings />\n }\n }\n </div>\n </section>\n}\n\n@if (!open()) {\n <et-query-devtools-toggle [tampered]=\"panelTampered()\" (openChange)=\"toggleOpen()\" />\n}\n\n@if (inspectActive() && inspectHover(); as hover) {\n <div\n [style.left.px]=\"hover.rect.left\"\n [style.top.px]=\"hover.rect.top\"\n [style.width.px]=\"hover.rect.width\"\n [style.height.px]=\"hover.rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">{{ inspectLabel(hover.entries) }}</span>\n </div>\n}\n\n@if (locatedRect(); as rect) {\n <div\n [style.left.px]=\"rect.left\"\n [style.top.px]=\"rect.top\"\n [style.width.px]=\"rect.width\"\n [style.height.px]=\"rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">created here</span>\n </div>\n}\n", styles: ["@layer components{.et-query-devtools-host{--_et-qdt-bg: var(--et-surface-background-solid, rgb(24 24 27));--_et-qdt-fg: var(--et-surface-color-solid, rgb(244 244 245));--_et-qdt-muted: var(--et-surface-color-muted-solid, rgb(161 161 170));--_et-qdt-subtle: var(--et-surface-color-subtle-solid, rgb(113 113 122));--_et-qdt-border: var(--et-surface-border-solid, rgb(255 255 255 / .12));--_et-qdt-interaction: var(--et-surface-interaction-solid, rgb(255 255 255));--_et-qdt-line: color-mix(in srgb, var(--_et-qdt-interaction) 24%, transparent);--_et-qdt-line-strong: color-mix(in srgb, var(--_et-qdt-interaction) 42%, transparent);--_et-qdt-accent: var(--et-theme-color-primary-solid, rgb(96 165 250));--_et-qdt-on-accent: var(--et-theme-color-on-primary, #09090b);--_et-qdt-hover: color-mix(in srgb, var(--_et-qdt-interaction) 10%, transparent);--_et-qdt-field: color-mix(in srgb, var(--_et-qdt-interaction) 8%, transparent);--_et-qdt-active: color-mix(in srgb, var(--_et-qdt-interaction) 18%, transparent);--_et-qdt-success: rgb(34 197 94);--_et-qdt-error: rgb(239 68 68);--_et-qdt-loading: rgb(234 179 8);--_et-qdt-title-bar: 2.4rem;--_et-qdt-radius-sm: .3rem;--_et-qdt-radius: .5rem;--_et-qdt-radius-lg: .6rem;--_et-qdt-control-h: 2.4rem;--_et-qdt-row-h: 3.6rem;position:fixed;inset-inline:0;inset-block-end:0;z-index:2147483010;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,Liberation Mono,monospace;font-size:1.2rem;line-height:1.4;pointer-events:none}.et-query-devtools-host>*{pointer-events:auto}@media(pointer:coarse){.et-query-devtools-host{--_et-qdt-control-h: 3.4rem;--_et-qdt-row-h: 4.4rem}}.et-query-devtools-panel{position:relative;display:flex;flex-direction:column;inline-size:100%;min-block-size:20rem;max-block-size:90vh;background:var(--_et-qdt-bg);color:var(--_et-qdt-fg);border-block-start:1px solid var(--_et-qdt-border);box-shadow:0 -.4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=right]){inset-block:0;inset-inline-start:auto}.et-query-devtools-panel:where([data-dock=right]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-start:1px solid var(--_et-qdt-border);box-shadow:-.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=float]){inset:0}.et-query-devtools-panel:where([data-dock=float]){--_et-qdt-frame: .8rem;--et-resize-handles-edge-size: var(--_et-qdt-frame);--et-resize-handles-touch-edge-size: var(--_et-qdt-frame);--et-resize-handles-corner-size: 1.6rem;--et-resize-handles-touch-corner-size: 1.6rem;--et-resize-handles-edge-inset: 1.6rem;--et-resize-handles-side-top: var(--_et-qdt-title-bar);--et-resize-handles-side-bottom: 1.6rem;--et-resize-handles-z-index: 3;position:absolute;inline-size:auto;min-block-size:0;max-block-size:none;padding-block-start:var(--_et-qdt-title-bar);padding-inline:var(--_et-qdt-frame);padding-block-end:var(--_et-qdt-frame);border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);box-shadow:0 1rem 4rem #00000073;overflow:hidden}.et-query-devtools-move{position:absolute;inset-inline:0;inset-block-start:0;block-size:var(--_et-qdt-title-bar);cursor:move;z-index:2}.et-query-devtools-panel:where([data-dock=float]) .et-query-devtools-body{border-radius:var(--_et-qdt-radius-sm);overflow:hidden}.et-query-devtools-move:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.9rem;inline-size:3rem;margin-inline-start:-1.5rem;block-size:.6rem;background-image:radial-gradient(currentcolor 40%,transparent 42%);background-size:.4rem .3rem;color:var(--_et-qdt-subtle)}@media(hover:hover){.et-query-devtools-move:hover:after{color:var(--_et-qdt-accent)}}.et-query-devtools-panel:where([data-dock=float][data-parked]){opacity:.85}@media(hover:hover){.et-query-devtools-panel:where([data-dock=float][data-parked]):hover{opacity:1}}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move{cursor:grab;background:var(--_et-qdt-active)}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move:after{color:var(--_et-qdt-accent)}.et-query-devtools-host:where([data-dock=left]){inset-block:0;inset-inline-end:auto}.et-query-devtools-panel:where([data-dock=left]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-end:1px solid var(--_et-qdt-border);box-shadow:.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=top]){inset-block-start:0;inset-block-end:auto}.et-query-devtools-panel:where([data-dock=top]){border-block-start:0;border-block-end:1px solid var(--_et-qdt-border);box-shadow:0 .4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=popout]){position:static;inline-size:100%;block-size:100%}.et-query-devtools-panel:where([data-dock=popout]){block-size:100%;max-block-size:none;border:0;box-shadow:none}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-header{flex-wrap:wrap}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions){flex:1 1 auto;flex-wrap:nowrap;min-inline-size:0;overflow-x:auto}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions)>*{flex:none}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-master-detail,.et-query-devtools-split){flex-direction:column}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-list,.et-query-devtools-detail,.et-query-devtools-drawer,.et-query-devtools-split .et-query-devtools-scroll){flex:1 1 50%;min-inline-size:0;min-block-size:0;max-inline-size:none;border-inline-start:0;border-inline-end:0}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-detail,.et-query-devtools-drawer){border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-master-detail>.et-query-devtools-list{flex:0 1 var(--_et-qdt-list-height, 50%);min-block-size:var(--_et-qdt-list-height, 0);max-block-size:var(--_et-qdt-list-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-split .et-query-devtools-drawer{flex:0 1 var(--_et-qdt-drawer-height, 50%);min-block-size:var(--_et-qdt-drawer-height, 0);max-block-size:var(--_et-qdt-drawer-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-pane-resize{cursor:ns-resize}.et-query-devtools-panel--resizing{-webkit-user-select:none;user-select:none}.et-query-devtools-resize,.et-query-devtools-pane-resize{touch-action:none}.et-query-devtools-resize{position:absolute;inset-inline:0;inset-block-start:0;block-size:.6rem;cursor:ns-resize;z-index:1}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize{inset-inline:0 auto;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize{inset-inline:auto 0;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize{inset-block:auto 0}.et-query-devtools-resize:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.2rem;inline-size:4rem;margin-inline-start:-2rem;block-size:.2rem;border-radius:999px;background:var(--_et-qdt-border)}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize:after{inset-inline:.2rem auto;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize:after{inset-inline:auto .2rem;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize:after{inset-block:auto .2rem}@media(hover:hover){.et-query-devtools-resize:hover:after{background:var(--_et-qdt-accent)}}.et-query-devtools-header{display:flex;align-items:center;justify-content:space-between;gap:.8rem;padding-inline:.8rem;border-block-end:1px solid var(--_et-qdt-border);flex:0 0 auto}.et-query-devtools-armed-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-block-end:1px solid color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-armed-text{flex:1 1 auto;min-inline-size:0}.et-query-devtools-notice-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:var(--_et-qdt-hover);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg);font-size:1.1rem}.et-query-devtools-notice-bar .et-query-devtools-btn{flex:0 0 auto}.et-query-devtools-armed-orphans{display:block;opacity:.85}.et-query-devtools-armed-dot{flex:0 0 auto;inline-size:.8rem;block-size:.8rem;border-radius:50%;background:var(--_et-qdt-error);animation:et-query-devtools-armed-pulse 1.6s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.et-query-devtools-armed-dot{animation:none}}@keyframes et-query-devtools-armed-pulse{50%{opacity:.25}}.et-query-devtools-armed-bar .et-query-devtools-btn{flex:0 0 auto;border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-tabs{display:flex;flex-wrap:wrap;gap:.2rem}.et-query-devtools-tab{appearance:none;display:inline-flex;align-items:center;gap:.5rem;border:none;background:transparent;color:var(--_et-qdt-muted);padding:.9rem 1rem;cursor:pointer;border-block-end:2px solid transparent;font:inherit}@media(hover:hover){.et-query-devtools-tab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-tab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-tab-badge{display:inline-block;padding-inline:.45rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-interaction) 12%,transparent);color:var(--_et-qdt-muted);font-size:1rem;font-variant-numeric:tabular-nums}.et-query-devtools-tab-badge--error{background:color-mix(in srgb,var(--_et-qdt-error) 25%,transparent);color:var(--_et-qdt-fg)}.et-query-devtools-menu{display:contents}.et-query-devtools-menu-caret{font-size:.9em;opacity:.7}.et-query-devtools-menu-glyph{display:inline-block;min-inline-size:1.2rem;text-align:center}.et-query-devtools-menu>[data-menu-open]{background:var(--_et-qdt-hover);color:var(--_et-qdt-fg)}.et-menu .et-query-devtools-menu-item-glyph{display:inline-block;inline-size:16px;text-align:center}.et-menu-item-content:has(.et-query-devtools-menu-item-note){display:flex;flex-direction:column;align-items:start;gap:2px;padding-block:8px}.et-query-devtools-menu-item-note{color:var(--et-surface-color-muted-solid, rgb(255 255 255 / .55));font-size:12px}.et-query-devtools-header-actions{display:flex;align-items:center;gap:.2rem;flex:0 0 auto}.et-query-devtools-header-divider{inline-size:1px;block-size:1.6rem;margin-inline:.4rem;background:var(--_et-qdt-border)}.et-query-devtools-inspect-btn{position:relative}.et-query-devtools-inspect-icon{inline-size:1.4rem;block-size:1.4rem;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.25;stroke-linecap:round}.et-query-devtools-inspect-icon-dot{fill:currentColor;stroke:none}.et-query-devtools-btn.et-query-devtools-inspect-btn--active,.et-query-devtools-btn.et-query-devtools-inspect-btn--active:hover{color:var(--_et-qdt-on-accent);background:var(--_et-qdt-accent);border-color:var(--_et-qdt-accent)}.et-query-devtools-inspect-btn--active:after{content:\"\";position:absolute;inset:-.3rem;border:1px solid var(--_et-qdt-accent);border-radius:calc(var(--_et-qdt-radius) + .3rem);pointer-events:none;animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}@keyframes et-query-devtools-inspect-pulse{0%,to{opacity:.2}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.et-query-devtools-inspect-btn--active:after,.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:none;opacity:1}}.et-query-devtools-kbd{border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-hover);box-shadow:inset 0 0 0 1px var(--_et-qdt-border);color:var(--_et-qdt-muted);padding:.15rem .4rem;font:inherit;font-size:1.1rem;line-height:1.2;white-space:nowrap}.et-query-devtools-kbd--inverse{background:#00000026;box-shadow:inset 0 0 0 1px #00000040;color:inherit}@media(hover:none)and (pointer:coarse){.et-query-devtools-kbd{display:none}}.et-query-devtools-inspect-box{position:fixed;z-index:2147483002;pointer-events:none;border:2px solid var(--_et-qdt-accent);background:color-mix(in srgb,var(--_et-qdt-accent) 15%,transparent);border-radius:var(--_et-qdt-radius-sm)}.et-query-devtools-inspect-tag{position:absolute;inset-block-start:100%;inset-inline-start:0;margin-block-start:.2rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);font-family:ui-monospace,monospace;font-size:1.1rem;font-weight:600;white-space:nowrap}.et-query-devtools-panel :is(a,button,input,select,summary,textarea,[tabindex]):focus-visible{outline:2px solid var(--_et-qdt-accent);outline-offset:1px}.et-query-devtools-body{flex:1 1 auto;min-block-size:0;overflow:hidden}.et-query-devtools-detail{flex:1 1 auto;min-inline-size:0;overflow-y:auto;padding:1rem}.et-query-devtools-detail .et-query-devtools-meta,.et-query-devtools-drawer .et-query-devtools-meta{padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-detail .et-query-devtools-section-row,.et-query-devtools-drawer .et-query-devtools-section-row{padding-block-start:.8rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-filter-chip{display:inline-flex;align-items:center;gap:.6rem;padding:.3rem .35rem .3rem .7rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_et-qdt-accent) 45%,transparent);color:var(--_et-qdt-accent);font-size:1.1rem;font-weight:600;letter-spacing:.02em}.et-query-devtools-filter-icon{font-size:1.3rem;line-height:1}.et-query-devtools-filter-count{border-radius:999px;background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);min-inline-size:1.8rem;padding:0 .5rem;text-align:center}.et-query-devtools-filter-clear{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-filter-clear:hover{border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent);color:var(--_et-qdt-fg)}}.et-query-devtools-scroll{block-size:100%;overflow:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.et-query-devtools-split{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-split .et-query-devtools-scroll{flex:1 1 auto;min-inline-size:0}.et-query-devtools-pane{display:flex;flex-direction:column;flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:hidden}.et-query-devtools-pane>.et-query-devtools-scroll{padding-block:0 1rem}.et-query-devtools-pane-resize{flex:0 0 .5rem;align-self:stretch;cursor:ew-resize;background:transparent;transition:background .12s ease}.et-query-devtools-pane-resize:active{background:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-pane-resize:hover{background:var(--_et-qdt-accent)}}.et-query-devtools-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem;padding:.8rem;position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-scroll>.et-query-devtools-toolbar{inset-block-start:-1rem}.et-query-devtools-toolbar-row{display:flex;align-items:center;flex-wrap:wrap;flex:1 1 100%;gap:.5rem}.et-query-devtools-field{display:inline-flex;align-items:center;gap:.6rem;color:var(--_et-qdt-muted)}.et-query-devtools-select{flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);background:color-mix(in srgb,var(--_et-qdt-interaction) 8%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-select:focus-visible{border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent)}.et-query-devtools-select option{background-color:var(--_et-qdt-bg);color:var(--_et-qdt-fg)}.et-query-devtools-count{color:var(--_et-qdt-subtle)}.et-query-devtools-row{display:flex;align-items:stretch;inline-size:100%;min-block-size:var(--_et-qdt-row-h);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg)}@media(hover:hover){.et-query-devtools-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-method{font-weight:700;font-size:1.1rem;color:var(--_et-qdt-muted);white-space:nowrap}.et-query-devtools-route{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;min-inline-size:0}.et-query-devtools-status{inline-size:.8rem;block-size:.8rem;border-radius:999px;flex:0 0 auto;background:var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-status[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-status[data-status=loading],.et-query-devtools-status[data-status=running]{background:var(--_et-qdt-loading)}.et-query-devtools-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4;white-space:nowrap;cursor:pointer;transition:color .12s ease,background-color .12s ease,border-color .12s ease}@media(hover:hover){.et-query-devtools-btn:hover:not(:disabled){background:var(--_et-qdt-hover);border-color:var(--_et-qdt-line-strong);color:var(--_et-qdt-fg)}}.et-query-devtools-btn:disabled{border-color:var(--_et-qdt-border);color:var(--_et-qdt-subtle);cursor:default;background:transparent;opacity:.6}.et-query-devtools-btn--primary,.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 40%,transparent);color:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 26%,transparent)}}.et-query-devtools-btn--danger{border-color:color-mix(in srgb,var(--_et-qdt-error) 32%,transparent);color:color-mix(in srgb,var(--_et-qdt-error) 55%,var(--_et-qdt-fg))}@media(hover:hover){.et-query-devtools-btn--danger:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}}.et-query-devtools-btn--tampered,.et-query-devtools-btn--tampered:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-icon-btn{inline-size:var(--_et-qdt-control-h);padding-inline:0;font-size:1.3rem}.et-query-devtools-btn-group{display:inline-flex;flex:0 0 auto;border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);overflow:hidden}.et-query-devtools-btn-group>.et-query-devtools-btn{border-radius:0;border-block:0;border-inline-start:0;border-inline-end:1px solid var(--_et-qdt-line)}.et-query-devtools-btn-group>.et-query-devtools-btn:last-child{border-inline-end:0}.et-query-devtools-btn-group>.et-query-devtools-btn:focus-visible{outline-offset:-2px}.et-query-devtools-toolbar-btn{margin-inline-start:auto;flex:0 0 auto}.et-query-devtools-meta{display:grid;grid-template-columns:auto 1fr;gap:.3rem 1rem;margin:0 0 1rem}.et-query-devtools-meta dt{color:var(--_et-qdt-muted)}.et-query-devtools-meta dd{margin:0;overflow-wrap:anywhere}.et-query-devtools-section{margin:1rem 0 .4rem;font-size:1.1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat{padding:.6rem .8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-stat dt{font-size:1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat dd{margin:0;font-size:1.5rem;font-variant-numeric:tabular-nums}.et-query-devtools-stat-sub{display:block;font-size:1rem;color:var(--_et-qdt-subtle)}.et-query-devtools-json{margin:0;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow-x:auto;white-space:pre-wrap;overflow-wrap:anywhere;max-block-size:24rem;overflow-y:auto}.et-query-devtools-json--error{border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-mono{font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.et-query-devtools-url{display:inline-block;max-inline-size:32rem;margin-inline-start:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.et-query-devtools-chips,.et-query-devtools-chip-row{display:flex;flex-wrap:wrap;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-chip{display:inline-flex;align-items:center;gap:.3rem;padding:.2rem .6rem;border-radius:999px;border:1px solid var(--_et-qdt-border);font-size:1.1rem;color:var(--_et-qdt-fg);background:color-mix(in srgb,var(--_et-qdt-interaction) 6%,transparent)}.et-query-devtools-chip--muted{color:var(--_et-qdt-muted)}.et-query-devtools-retry-glyph{font-size:.7em;line-height:1}.et-query-devtools-chip--loading{color:var(--_et-qdt-loading);border-color:color-mix(in srgb,var(--_et-qdt-loading) 50%,transparent)}.et-query-devtools-chip--error{color:var(--_et-qdt-error);border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-chip--success{color:var(--_et-qdt-success);border-color:color-mix(in srgb,var(--_et-qdt-success) 50%,transparent)}button.et-query-devtools-chip--button{appearance:none;border-color:var(--_et-qdt-line);cursor:pointer;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}@media(hover:hover){button.et-query-devtools-chip--button:hover{border-color:var(--_et-qdt-accent);color:var(--_et-qdt-accent)}}.et-query-devtools-facet{appearance:none;border-color:var(--_et-qdt-line);min-block-size:var(--_et-qdt-control-h);padding-inline:.8rem;background:transparent;cursor:pointer;color:var(--_et-qdt-muted);font:inherit;font-size:1.1rem;line-height:1.4}@media(hover:hover){.et-query-devtools-facet:hover:not(:disabled){color:var(--_et-qdt-fg);background:var(--_et-qdt-hover);border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent)}}.et-query-devtools-facet:disabled{color:var(--_et-qdt-subtle);cursor:default}.et-query-devtools-facet--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 14%,transparent)}.et-query-devtools-facet-count{font-variant-numeric:tabular-nums;color:inherit;opacity:.75}.et-query-devtools-card{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);padding:1rem}.et-query-devtools-card--armed{border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-card-head{display:flex;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-inner-queries{display:flex;flex-direction:column;gap:.3rem}.et-query-devtools-inner-row{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.4rem .6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-inner-row:hover:not([disabled]){background:var(--_et-qdt-hover)}}.et-query-devtools-inner-row--active{background:var(--_et-qdt-active);border-color:var(--_et-qdt-accent)}.et-query-devtools-inner-row[disabled]{cursor:default;opacity:.6}.et-query-devtools-step-toggle{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:none;background:transparent;color:var(--_et-qdt-fg);padding:.6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-step-toggle:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-step-index{flex:1 1 auto;min-inline-size:0}.et-query-devtools-step-caret{color:var(--_et-qdt-muted)}.et-query-devtools-table{inline-size:100%;border-collapse:collapse}.et-query-devtools-table-scroll{overflow-x:auto}.et-query-devtools-table-scroll>.et-query-devtools-table{min-inline-size:max-content}.et-query-devtools-table th,.et-query-devtools-table td{text-align:start;padding:.5rem .6rem;border-block-end:1px solid var(--_et-qdt-border);vertical-align:top}.et-query-devtools-table td .et-query-devtools-chip{padding-block:0;line-height:1.4}.et-query-devtools-table th{color:var(--_et-qdt-muted);font-weight:600;position:sticky;inset-block-start:0;background:var(--_et-qdt-bg)}.et-query-devtools-table tr[data-status=error] td{color:var(--_et-qdt-error)}.et-query-devtools-table .et-query-devtools-cell-origin{inline-size:12ch;max-inline-size:12ch;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;overflow-wrap:normal}.et-query-devtools-empty{color:var(--_et-qdt-subtle);padding:1.2rem;text-align:center}.et-query-devtools-cell-actions{display:inline-flex;gap:.4rem;white-space:nowrap}.et-query-devtools-section-row{display:flex;align-items:center;justify-content:space-between;gap:.8rem;margin-block-start:1rem}.et-query-devtools-search{flex:1 1 16rem;min-inline-size:0;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-search:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-row-link{display:inline-flex;align-items:center;gap:.6rem;appearance:none;border:0;background:none;padding:0;color:inherit;font:inherit;text-align:start;cursor:pointer}.et-query-devtools-row-link:focus-visible .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}@media(hover:hover){.et-query-devtools-row-link:hover .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}}.et-query-devtools-hint{flex:1 1 24rem;color:var(--_et-qdt-muted);font-size:1.1rem;margin:0}.et-query-devtools-input{inline-size:100%;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-input:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-input--number{inline-size:8rem;font-variant-numeric:tabular-nums}.et-query-devtools-editor{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);padding:.8rem;margin-block-end:1rem}.et-query-devtools-editor-error{color:var(--_et-qdt-error);margin:.4rem 0 0}.et-query-devtools-btn--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent)}}\n"] }]
7485
- }], ctorParameters: () => [], propDecorators: { startOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "startOpen", required: false }] }], panelEl: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
7571
+ }, template: "@if (open()) {\n <section\n #panel\n [class.et-query-devtools-panel--resizing]=\"resizing()\"\n [attr.data-dock]=\"poppedOut() ? 'popout' : dock()\"\n [attr.data-pane-axis]=\"paneAxis()\"\n [attr.data-parked]=\"floatParked() ? '' : null\"\n [style.block-size.px]=\"panelBlockSize()\"\n [style.inline-size.px]=\"panelInlineSize()\"\n [style.inset-block-start.px]=\"panelInsetBlock()\"\n [style.inset-inline-start.px]=\"panelInsetInline()\"\n [style.--_et-qdt-list-width.px]=\"listWidth()\"\n [style.--_et-qdt-drawer-width.px]=\"drawerWidth()\"\n [style.--_et-qdt-list-height.px]=\"listHeight()\"\n [style.--_et-qdt-drawer-height.px]=\"drawerHeight()\"\n class=\"et-query-devtools-panel\"\n >\n @if (floating()) {\n <et-resize-handles\n [edges]=\"FLOAT_RESIZE_EDGES\"\n [disabled]=\"floatParked()\"\n (resizeStarted)=\"startFloatResize()\"\n (resizeMoved)=\"resizeFloat($event)\"\n (resizeEnded)=\"endFloatResize()\"\n (resizeCancelled)=\"endFloatResize()\"\n />\n <div\n (dragMoved)=\"moveFloat($event)\"\n (dragEnded)=\"endFloatMove()\"\n (dragCancelled)=\"endFloatMove()\"\n (dragTapped)=\"restoreFloat()\"\n class=\"et-query-devtools-move\"\n title=\"Drag to move \u2014 shove it off an edge to park it, click the strip to bring it back\"\n aria-hidden=\"true\"\n etDragHandle\n ></div>\n } @else if (!poppedOut()) {\n <div\n (pointerdown)=\"startResize($event)\"\n class=\"et-query-devtools-resize\"\n title=\"Drag to resize\"\n aria-hidden=\"true\"\n ></div>\n }\n <header class=\"et-query-devtools-header\">\n <nav class=\"et-query-devtools-tabs\" role=\"tablist\">\n @for (tab of visibleTabs(); track tab.id) {\n @let badge = tabBadges()[tab.id];\n <button\n #tabButton\n [class.et-query-devtools-tab--active]=\"activeTab() === tab.id\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n (click)=\"activeTab.set(tab.id)\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (badge.count) {\n <span class=\"et-query-devtools-tab-badge\">{{ badge.count }}</span>\n }\n @if (badge.errors) {\n <span\n class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\"\n title=\"{{ badge.errors }} {{ badge.errorNoun ?? 'failing' }}\"\n >\n {{ badge.errors }}\n </span>\n }\n </button>\n }\n\n @if (overflowTabs().length; as overflowCount) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [title]=\"overflowCount + ' tabs with nothing in them'\"\n class=\"et-query-devtools-tab\"\n type=\"button\"\n etMenuTrigger\n >\n More\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n @for (tab of overflowTabs(); track tab.id) {\n <button (activate)=\"activeTab.set(tab.id)\" et-menu-item type=\"button\">{{ tab.label }}</button>\n }\n </et-menu>\n </ng-template>\n </div>\n }\n </nav>\n\n <div class=\"et-query-devtools-header-actions\">\n <button\n [class.et-query-devtools-inspect-btn--active]=\"inspectActive()\"\n [attr.aria-pressed]=\"inspectActive()\"\n (click)=\"toggleInspect()\"\n class=\"et-query-devtools-btn et-query-devtools-inspect-btn\"\n type=\"button\"\n title=\"Inspect: hover the UI to find its query\"\n >\n <svg\n class=\"et-query-devtools-inspect-icon\"\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle class=\"et-query-devtools-inspect-icon-ring\" cx=\"8\" cy=\"8\" r=\"4.25\" />\n <circle class=\"et-query-devtools-inspect-icon-dot\" cx=\"8\" cy=\"8\" r=\"1.15\" />\n <path d=\"M8 0.9v2.1M8 13v2.1M0.9 8h2.1M13 8h2.1\" />\n </svg>\n {{ inspectActive() ? 'Inspecting' : 'Inspect' }}\n @if (inspectActive()) {\n <kbd class=\"et-query-devtools-kbd et-query-devtools-kbd--inverse\">Esc</kbd>\n }\n </button>\n <button\n (click)=\"downloadSession()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Download every registered entry, the event log, the cache totals and anything armed as one JSON file - the attachment for a bug report\"\n >\n <span aria-hidden=\"true\">\u2913</span>\n Session\n </button>\n <button\n [class.et-query-devtools-btn--active]=\"activeTab() === 'settings'\"\n [attr.aria-pressed]=\"activeTab() === 'settings'\"\n (click)=\"toggleSettings()\"\n class=\"et-query-devtools-btn et-query-devtools-icon-btn\"\n type=\"button\"\n title=\"Settings: where panel state is kept, and the limits it holds\"\n aria-label=\"Settings\"\n >\n <span aria-hidden=\"true\">\u2699</span>\n </button>\n @if (!poppedOut()) {\n @let layout = currentLayout();\n <div class=\"et-query-devtools-menu\" etMenu placement=\"bottom-end\">\n <button class=\"et-query-devtools-btn\" title=\"Where the panel sits\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ layout.glyph }}</span>\n {{ layout.label }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <et-menu-radio-group [value]=\"dock()\">\n @for (option of LAYOUTS; track option.id) {\n <!-- eslint-disable ethlete/prefer-static-boolean-properties -- closeOnActivate is tri-state (boolean | undefined); a transform would collapse its unset state -->\n <et-menu-radio-item\n [value]=\"option.id\"\n [title]=\"option.hint\"\n [closeOnActivate]=\"true\"\n (activate)=\"selectLayout(option.id)\"\n >\n <!-- eslint-enable ethlete/prefer-static-boolean-properties -->\n <span class=\"et-query-devtools-menu-item-glyph\" aria-hidden=\"true\">{{ option.glyph }}</span>\n {{ option.label }}\n </et-menu-radio-item>\n }\n </et-menu-radio-group>\n <et-menu-separator />\n <et-menu-checkbox-item\n [checked]=\"reservesSpace()\"\n [disabled]=\"floating()\"\n (checkedChange)=\"reservesSpace.set($event)\"\n title=\"The page gives up the room the panel covers, so its last rows can still be scrolled to. Docks only - a float sits wherever it was dragged.\"\n >\n Reserve page space\n </et-menu-checkbox-item>\n </et-menu>\n </ng-template>\n </div>\n }\n <span class=\"et-query-devtools-header-divider\" aria-hidden=\"true\"></span>\n <button\n (click)=\"toggleOpen()\"\n class=\"et-query-devtools-btn et-query-devtools-btn--danger\"\n type=\"button\"\n title=\"{{ poppedOut() ? 'Bring the panel back into the app window' : 'Close devtools (' + shortcut + ')' }}\"\n >\n @if (poppedOut()) {\n <span aria-hidden=\"true\">\u29C8</span>\n Dock back\n } @else {\n <span aria-hidden=\"true\">\u2715</span>\n Close\n <kbd class=\"et-query-devtools-kbd\">{{ shortcut }}</kbd>\n }\n </button>\n </div>\n </header>\n\n @if (popOutBlocked()) {\n <div class=\"et-query-devtools-notice-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-text\">\n The browser blocked the pop-up window. Allow pop-ups for this site, or float the panel over the page instead \u2014\n a float needs no permission.\n </span>\n <button (click)=\"floatPanel()\" class=\"et-query-devtools-btn\" type=\"button\">Float instead</button>\n <button (click)=\"popOutBlocked.set(false)\" class=\"et-query-devtools-btn\" type=\"button\">Dismiss</button>\n </div>\n }\n\n @if (armedFaultClients(); as armed) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Faults armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ armed.join(', ') }}</span>\n \u2014 every failure and delay you see from\n {{ armed.length === 1 ? 'this client' : 'these clients' }} is injected, not the API.\n @if (faultsRestored()) {\n They came back from your last page load \u2014 set <em>Armed faults</em> back to <em>none</em> in Settings to\n stop that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'faults'\"\n (click)=\"activeTab.set('faults')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"CLEAR_FAULTS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (armedMockRoutes(); as mocked) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n <strong>Mocks armed</strong> on\n <span class=\"et-query-devtools-mono\">{{ mocked.join(', ') }}</span>\n \u2014 {{ mocked.length === 1 ? 'that route is' : 'those routes are' }} answered by the panel, so nothing they show\n reached the API.\n @if (mocksRestored()) {\n They came back from your last page load \u2014 set <em>Armed mocks</em> back to <em>none</em> in Settings to stop\n that.\n }\n </span>\n <button\n [disabled]=\"activeTab() === 'mocks'\"\n (click)=\"activeTab.set('mocks')\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n Review\n </button>\n <button (click)=\"DISARM_MOCKS()\" class=\"et-query-devtools-btn\" type=\"button\">Disarm all</button>\n </div>\n }\n\n @if (restoredOverrides(); as restored) {\n <div class=\"et-query-devtools-armed-bar\" role=\"status\">\n <span class=\"et-query-devtools-armed-dot\" aria-hidden=\"true\"></span>\n <span class=\"et-query-devtools-armed-text\">\n @if (restored.ops) {\n <strong>Overrides re-armed</strong> \u2014 {{ restored.ops }} {{ restored.ops === 1 ? 'edit' : 'edits' }} from\n your last page load {{ restored.ops === 1 ? 'is' : 'are' }} back on {{ restored.queries }}\n {{ restored.queries === 1 ? 'query' : 'queries' }}, so those responses are not what the API sent.\n @if (restored.fromLocalStorage) {\n They came back from <strong>localStorage</strong>, so they outlive closing this tab \u2014 clear them, or set\n overrides back to <em>session</em> in Settings.\n }\n } @else {\n <strong>Overrides could not be re-armed.</strong>\n }\n @if (restored.orphaned.length) {\n <span class=\"et-query-devtools-armed-orphans\">\n {{ restored.orphaned.length }} stored\n {{ restored.orphaned.length === 1 ? 'override' : 'overrides' }} matched no query \u2014\n <span class=\"et-query-devtools-mono\">{{ restored.orphaned.join(', ') }}</span>\n </span>\n }\n </span>\n @if (restored.firstId; as firstId) {\n <button (click)=\"reviewRestoredOverrides(firstId)\" class=\"et-query-devtools-btn\" type=\"button\">Review</button>\n }\n <button (click)=\"DROP_RESTORED_OVERRIDES()\" class=\"et-query-devtools-btn\" type=\"button\">Drop all</button>\n </div>\n }\n\n <div class=\"et-query-devtools-body\">\n @switch (activeTab()) {\n @case ('queries') {\n <et-query-devtools-queries-tab />\n }\n\n @case ('stacks') {\n <et-query-devtools-stacks-tab />\n }\n\n @case ('sequences') {\n <et-query-devtools-sequences-tab />\n }\n\n @case ('batches') {\n <et-query-devtools-batches-tab />\n }\n\n @case ('forms') {\n <et-query-devtools-forms-tab />\n }\n\n @case ('auth') {\n <et-query-devtools-auth-tab />\n }\n\n @case ('ws') {\n <et-query-devtools-sockets-tab />\n }\n\n @case ('cache') {\n <et-query-devtools-cache-tab />\n }\n\n @case ('locks') {\n <et-query-devtools-locks-tab />\n }\n\n @case ('timeline') {\n <et-query-devtools-timeline-tab />\n }\n\n @case ('events') {\n <et-query-devtools-events-tab />\n }\n\n @case ('faults') {\n <et-query-devtools-faults-tab />\n }\n\n @case ('mocks') {\n <et-query-devtools-mocks-tab />\n }\n\n @case ('about') {\n <et-query-devtools-about />\n }\n\n @case ('settings') {\n <et-query-devtools-settings />\n }\n }\n </div>\n </section>\n}\n\n@if (!open()) {\n <et-query-devtools-toggle [tampered]=\"panelTampered()\" (openChange)=\"toggleOpen()\" />\n}\n\n@if (inspectActive() && inspectHover(); as hover) {\n <div\n [style.left.px]=\"hover.rect.left\"\n [style.top.px]=\"hover.rect.top\"\n [style.width.px]=\"hover.rect.width\"\n [style.height.px]=\"hover.rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">{{ inspectLabel(hover.entries) }}</span>\n </div>\n}\n\n@if (locatedRect(); as rect) {\n <div\n [style.left.px]=\"rect.left\"\n [style.top.px]=\"rect.top\"\n [style.width.px]=\"rect.width\"\n [style.height.px]=\"rect.height\"\n class=\"et-query-devtools-inspect-box\"\n >\n <span class=\"et-query-devtools-inspect-tag\">created here</span>\n </div>\n}\n", styles: ["@layer components{.et-query-devtools-host{--_et-qdt-bg: var(--et-surface-background-solid, rgb(24 24 27));--_et-qdt-fg: var(--et-surface-color-solid, rgb(244 244 245));--_et-qdt-muted: var(--et-surface-color-muted-solid, rgb(161 161 170));--_et-qdt-subtle: var(--et-surface-color-subtle-solid, rgb(113 113 122));--_et-qdt-border: var(--et-surface-border-solid, rgb(255 255 255 / .12));--_et-qdt-interaction: var(--et-surface-interaction-solid, rgb(255 255 255));--_et-qdt-line: color-mix(in srgb, var(--_et-qdt-interaction) 24%, transparent);--_et-qdt-line-strong: color-mix(in srgb, var(--_et-qdt-interaction) 42%, transparent);--_et-qdt-accent: var(--et-theme-color-primary-solid, rgb(96 165 250));--_et-qdt-on-accent: var(--et-theme-color-on-primary, #09090b);--_et-qdt-hover: color-mix(in srgb, var(--_et-qdt-interaction) 10%, transparent);--_et-qdt-field: color-mix(in srgb, var(--_et-qdt-interaction) 8%, transparent);--_et-qdt-active: color-mix(in srgb, var(--_et-qdt-interaction) 18%, transparent);--_et-qdt-success: rgb(34 197 94);--_et-qdt-error: rgb(239 68 68);--_et-qdt-loading: rgb(234 179 8);--_et-qdt-title-bar: 2.4rem;--_et-qdt-radius-sm: .3rem;--_et-qdt-radius: .5rem;--_et-qdt-radius-lg: .6rem;--_et-qdt-control-h: 2.4rem;--_et-qdt-row-h: 3.6rem;position:fixed;inset-inline:0;inset-block-end:0;z-index:2147483010;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,Liberation Mono,monospace;font-size:1.2rem;line-height:1.4;pointer-events:none}.et-query-devtools-host>*{pointer-events:auto}@media(pointer:coarse){.et-query-devtools-host{--_et-qdt-control-h: 3.4rem;--_et-qdt-row-h: 4.4rem}}.et-query-devtools-panel{position:relative;display:flex;flex-direction:column;inline-size:100%;min-block-size:20rem;max-block-size:90vh;background:var(--_et-qdt-bg);color:var(--_et-qdt-fg);border-block-start:1px solid var(--_et-qdt-border);box-shadow:0 -.4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=right]){inset-block:0;inset-inline-start:auto}.et-query-devtools-panel:where([data-dock=right]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-start:1px solid var(--_et-qdt-border);box-shadow:-.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=float]){inset:0}.et-query-devtools-panel:where([data-dock=float]){--_et-qdt-frame: .8rem;--et-resize-handles-edge-size: var(--_et-qdt-frame);--et-resize-handles-touch-edge-size: var(--_et-qdt-frame);--et-resize-handles-corner-size: 1.6rem;--et-resize-handles-touch-corner-size: 1.6rem;--et-resize-handles-edge-inset: 1.6rem;--et-resize-handles-side-top: var(--_et-qdt-title-bar);--et-resize-handles-side-bottom: 1.6rem;--et-resize-handles-z-index: 3;position:absolute;inline-size:auto;min-block-size:0;max-block-size:none;padding-block-start:var(--_et-qdt-title-bar);padding-inline:var(--_et-qdt-frame);padding-block-end:var(--_et-qdt-frame);border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);box-shadow:0 1rem 4rem #00000073;overflow:hidden}.et-query-devtools-move{position:absolute;inset-inline:0;inset-block-start:0;block-size:var(--_et-qdt-title-bar);cursor:move;z-index:2}.et-query-devtools-panel:where([data-dock=float]) .et-query-devtools-body{border-radius:var(--_et-qdt-radius-sm);overflow:hidden}.et-query-devtools-move:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.9rem;inline-size:3rem;margin-inline-start:-1.5rem;block-size:.6rem;background-image:radial-gradient(currentcolor 40%,transparent 42%);background-size:.4rem .3rem;color:var(--_et-qdt-subtle)}@media(hover:hover){.et-query-devtools-move:hover:after{color:var(--_et-qdt-accent)}}.et-query-devtools-panel:where([data-dock=float][data-parked]){opacity:.85}@media(hover:hover){.et-query-devtools-panel:where([data-dock=float][data-parked]):hover{opacity:1}}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move{cursor:grab;background:var(--_et-qdt-active)}.et-query-devtools-panel:where([data-dock=float][data-parked]) .et-query-devtools-move:after{color:var(--_et-qdt-accent)}.et-query-devtools-host:where([data-dock=left]){inset-block:0;inset-inline-end:auto}.et-query-devtools-panel:where([data-dock=left]){inline-size:auto;block-size:100%;max-block-size:none;max-inline-size:90vw;border-block-start:0;border-inline-end:1px solid var(--_et-qdt-border);box-shadow:.4rem 0 2rem #00000059}.et-query-devtools-host:where([data-dock=top]){inset-block-start:0;inset-block-end:auto}.et-query-devtools-panel:where([data-dock=top]){border-block-start:0;border-block-end:1px solid var(--_et-qdt-border);box-shadow:0 .4rem 2rem #00000059}.et-query-devtools-host:where([data-dock=popout]){position:static;inline-size:100%;block-size:100%}.et-query-devtools-panel:where([data-dock=popout]){block-size:100%;max-block-size:none;border:0;box-shadow:none}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-header{flex-wrap:wrap}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions){flex:1 1 auto;flex-wrap:nowrap;min-inline-size:0;overflow-x:auto}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-tabs,.et-query-devtools-header-actions)>*{flex:none}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-master-detail,.et-query-devtools-split){flex-direction:column}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-list,.et-query-devtools-detail,.et-query-devtools-drawer,.et-query-devtools-split .et-query-devtools-scroll){flex:1 1 50%;min-inline-size:0;min-block-size:0;max-inline-size:none;border-inline-start:0;border-inline-end:0}.et-query-devtools-panel:where([data-pane-axis=block]) :is(.et-query-devtools-detail,.et-query-devtools-drawer){border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-master-detail>.et-query-devtools-list{flex:0 1 var(--_et-qdt-list-height, 50%);min-block-size:var(--_et-qdt-list-height, 0);max-block-size:var(--_et-qdt-list-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-split .et-query-devtools-drawer{flex:0 1 var(--_et-qdt-drawer-height, 50%);min-block-size:var(--_et-qdt-drawer-height, 0);max-block-size:var(--_et-qdt-drawer-height, none)}.et-query-devtools-panel:where([data-pane-axis=block]) .et-query-devtools-pane-resize{cursor:ns-resize}.et-query-devtools-panel--resizing{-webkit-user-select:none;user-select:none}.et-query-devtools-resize,.et-query-devtools-pane-resize{touch-action:none}.et-query-devtools-resize{position:absolute;inset-inline:0;inset-block-start:0;block-size:.6rem;cursor:ns-resize;z-index:1}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize{inset-inline:0 auto;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize{inset-inline:auto 0;inset-block:0;inline-size:.6rem;block-size:auto;cursor:ew-resize}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize{inset-block:auto 0}.et-query-devtools-resize:after{content:\"\";position:absolute;inset-inline:50%;inset-block-start:.2rem;inline-size:4rem;margin-inline-start:-2rem;block-size:.2rem;border-radius:999px;background:var(--_et-qdt-border)}.et-query-devtools-panel:where([data-dock=right]) .et-query-devtools-resize:after{inset-inline:.2rem auto;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=left]) .et-query-devtools-resize:after{inset-inline:auto .2rem;inset-block:50% auto;inline-size:.2rem;block-size:4rem;margin-inline-start:0;margin-block-start:-2rem}.et-query-devtools-panel:where([data-dock=top]) .et-query-devtools-resize:after{inset-block:auto .2rem}@media(hover:hover){.et-query-devtools-resize:hover:after{background:var(--_et-qdt-accent)}}.et-query-devtools-header{display:flex;align-items:center;justify-content:space-between;gap:.8rem;padding-inline:.8rem;border-block-end:1px solid var(--_et-qdt-border);flex:0 0 auto}.et-query-devtools-armed-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-block-end:1px solid color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error);font-size:1.1rem}.et-query-devtools-armed-text{flex:1 1 auto;min-inline-size:0}.et-query-devtools-notice-bar{display:flex;align-items:center;gap:.8rem;flex:0 0 auto;padding:.6rem .8rem;background:var(--_et-qdt-hover);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg);font-size:1.1rem}.et-query-devtools-notice-bar .et-query-devtools-btn{flex:0 0 auto}.et-query-devtools-armed-orphans{display:block;opacity:.85}.et-query-devtools-armed-dot{flex:0 0 auto;inline-size:.8rem;block-size:.8rem;border-radius:50%;background:var(--_et-qdt-error);animation:et-query-devtools-armed-pulse 1.6s ease-in-out infinite}@media(prefers-reduced-motion:reduce){.et-query-devtools-armed-dot{animation:none}}@keyframes et-query-devtools-armed-pulse{50%{opacity:.25}}.et-query-devtools-armed-bar .et-query-devtools-btn{flex:0 0 auto;border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-tabs{display:flex;flex-wrap:wrap;gap:.2rem}.et-query-devtools-tab{appearance:none;display:inline-flex;align-items:center;gap:.5rem;border:none;background:transparent;color:var(--_et-qdt-muted);padding:.9rem 1rem;cursor:pointer;border-block-end:2px solid transparent;font:inherit}@media(hover:hover){.et-query-devtools-tab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-tab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-tab-badge{display:inline-block;padding-inline:.45rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-interaction) 12%,transparent);color:var(--_et-qdt-muted);font-size:1rem;font-variant-numeric:tabular-nums}.et-query-devtools-tab-badge--error{background:color-mix(in srgb,var(--_et-qdt-error) 25%,transparent);color:var(--_et-qdt-fg)}.et-query-devtools-menu{display:contents}.et-query-devtools-menu-caret{font-size:.9em;opacity:.7}.et-query-devtools-menu-glyph{display:inline-block;min-inline-size:1.2rem;text-align:center}.et-query-devtools-menu>[data-menu-open]{background:var(--_et-qdt-hover);color:var(--_et-qdt-fg)}.et-menu .et-query-devtools-menu-item-glyph{display:inline-block;inline-size:16px;text-align:center}.et-menu-item-content:has(.et-query-devtools-menu-item-note){display:flex;flex-direction:column;align-items:start;gap:2px;padding-block:8px}.et-query-devtools-menu-item-note{color:var(--et-surface-color-muted-solid, rgb(255 255 255 / .55));font-size:12px}.et-query-devtools-header-actions{display:flex;align-items:center;gap:.2rem;flex:0 0 auto}.et-query-devtools-header-divider{inline-size:1px;block-size:1.6rem;margin-inline:.4rem;background:var(--_et-qdt-border)}.et-query-devtools-inspect-btn{position:relative}.et-query-devtools-inspect-icon{inline-size:1.4rem;block-size:1.4rem;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.25;stroke-linecap:round}.et-query-devtools-inspect-icon-dot{fill:currentColor;stroke:none}.et-query-devtools-btn.et-query-devtools-inspect-btn--active,.et-query-devtools-btn.et-query-devtools-inspect-btn--active:hover{color:var(--_et-qdt-on-accent);background:var(--_et-qdt-accent);border-color:var(--_et-qdt-accent)}.et-query-devtools-inspect-btn--active:after{content:\"\";position:absolute;inset:-.3rem;border:1px solid var(--_et-qdt-accent);border-radius:calc(var(--_et-qdt-radius) + .3rem);pointer-events:none;animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:et-query-devtools-inspect-pulse 1.4s ease-in-out infinite}@keyframes et-query-devtools-inspect-pulse{0%,to{opacity:.2}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.et-query-devtools-inspect-btn--active:after,.et-query-devtools-inspect-btn--active .et-query-devtools-inspect-icon-ring{animation:none;opacity:1}}.et-query-devtools-kbd{border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-hover);box-shadow:inset 0 0 0 1px var(--_et-qdt-border);color:var(--_et-qdt-muted);padding:.15rem .4rem;font:inherit;font-size:1.1rem;line-height:1.2;white-space:nowrap}.et-query-devtools-kbd--inverse{background:#00000026;box-shadow:inset 0 0 0 1px #00000040;color:inherit}@media(hover:none)and (pointer:coarse){.et-query-devtools-kbd{display:none}}.et-query-devtools-inspect-box{position:fixed;z-index:2147483002;pointer-events:none;border:2px solid var(--_et-qdt-accent);background:color-mix(in srgb,var(--_et-qdt-accent) 15%,transparent);border-radius:var(--_et-qdt-radius-sm)}.et-query-devtools-inspect-tag{position:absolute;inset-block-start:100%;inset-inline-start:0;margin-block-start:.2rem;padding:.2rem .5rem;border-radius:var(--_et-qdt-radius-sm);background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);font-family:ui-monospace,monospace;font-size:1.1rem;font-weight:600;white-space:nowrap}.et-query-devtools-panel :is(a,button,input,select,summary,textarea,[tabindex]):focus-visible{outline:2px solid var(--_et-qdt-accent);outline-offset:1px}.et-query-devtools-body{flex:1 1 auto;min-block-size:0;overflow:hidden}.et-query-devtools-detail{flex:1 1 auto;min-inline-size:0;overflow-y:auto;padding:1rem}.et-query-devtools-detail .et-query-devtools-meta,.et-query-devtools-drawer .et-query-devtools-meta{padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-detail .et-query-devtools-section-row,.et-query-devtools-drawer .et-query-devtools-section-row{padding-block-start:.8rem;border-block-start:1px solid var(--_et-qdt-border)}.et-query-devtools-filter-chip{display:inline-flex;align-items:center;gap:.6rem;padding:.3rem .35rem .3rem .7rem;border-radius:999px;background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_et-qdt-accent) 45%,transparent);color:var(--_et-qdt-accent);font-size:1.1rem;font-weight:600;letter-spacing:.02em}.et-query-devtools-filter-icon{font-size:1.3rem;line-height:1}.et-query-devtools-filter-count{border-radius:999px;background:var(--_et-qdt-accent);color:var(--_et-qdt-on-accent);min-inline-size:1.8rem;padding:0 .5rem;text-align:center}.et-query-devtools-filter-clear{appearance:none;display:inline-flex;align-items:center;gap:.5rem;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);cursor:pointer;padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4}@media(hover:hover){.et-query-devtools-filter-clear:hover{border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent);color:var(--_et-qdt-fg)}}.et-query-devtools-scroll{block-size:100%;overflow:auto;padding:1rem;display:flex;flex-direction:column;gap:1rem}.et-query-devtools-split{display:flex;block-size:100%;min-block-size:0}.et-query-devtools-split .et-query-devtools-scroll{flex:1 1 auto;min-inline-size:0}.et-query-devtools-pane{display:flex;flex-direction:column;flex:1 1 auto;block-size:100%;min-inline-size:0;min-block-size:0;overflow:hidden}.et-query-devtools-pane>.et-query-devtools-scroll{padding-block:0 1rem}.et-query-devtools-pane-resize{flex:0 0 .5rem;align-self:stretch;cursor:ew-resize;background:transparent;transition:background .12s ease}.et-query-devtools-pane-resize:active{background:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-pane-resize:hover{background:var(--_et-qdt-accent)}}.et-query-devtools-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.6rem;padding:.8rem;position:sticky;inset-block-start:0;z-index:1;background:var(--_et-qdt-bg);border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-scroll>.et-query-devtools-toolbar{inset-block-start:-1rem}.et-query-devtools-toolbar-row{display:flex;align-items:center;flex-wrap:wrap;flex:1 1 100%;gap:.5rem}.et-query-devtools-field{display:inline-flex;align-items:center;gap:.6rem;color:var(--_et-qdt-muted)}.et-query-devtools-select{flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);background:color-mix(in srgb,var(--_et-qdt-interaction) 8%,var(--_et-qdt-bg));color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-select:focus-visible{border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent)}.et-query-devtools-select option{background-color:var(--_et-qdt-bg);color:var(--_et-qdt-fg)}.et-query-devtools-count{color:var(--_et-qdt-subtle)}.et-query-devtools-row{display:flex;align-items:stretch;inline-size:100%;min-block-size:var(--_et-qdt-row-h);border-block-end:1px solid var(--_et-qdt-border);color:var(--_et-qdt-fg)}@media(hover:hover){.et-query-devtools-row:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-method{font-weight:700;font-size:1.1rem;color:var(--_et-qdt-muted);white-space:nowrap}.et-query-devtools-route{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;min-inline-size:0}.et-query-devtools-status{inline-size:.8rem;block-size:.8rem;border-radius:999px;flex:0 0 auto;background:var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=success]{background:var(--_et-qdt-success)}.et-query-devtools-status[data-status=error]{background:var(--_et-qdt-error)}.et-query-devtools-status[data-status=parked]{background:transparent;box-shadow:inset 0 0 0 2px var(--_et-qdt-subtle)}.et-query-devtools-status[data-status=loading],.et-query-devtools-status[data-status=running]{background:var(--_et-qdt-loading)}.et-query-devtools-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;flex:0 0 auto;min-block-size:var(--_et-qdt-control-h);border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.25rem .7rem;font:inherit;font-size:1.15rem;line-height:1.4;white-space:nowrap;cursor:pointer;transition:color .12s ease,background-color .12s ease,border-color .12s ease}@media(hover:hover){.et-query-devtools-btn:hover:not(:disabled){background:var(--_et-qdt-hover);border-color:var(--_et-qdt-line-strong);color:var(--_et-qdt-fg)}}.et-query-devtools-btn:disabled{border-color:var(--_et-qdt-border);color:var(--_et-qdt-subtle);cursor:default;background:transparent;opacity:.6}.et-query-devtools-btn--primary,.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 40%,transparent);color:var(--_et-qdt-accent)}@media(hover:hover){.et-query-devtools-btn--primary:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-accent) 26%,transparent)}}.et-query-devtools-btn--danger{border-color:color-mix(in srgb,var(--_et-qdt-error) 32%,transparent);color:color-mix(in srgb,var(--_et-qdt-error) 55%,var(--_et-qdt-fg))}@media(hover:hover){.et-query-devtools-btn--danger:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 16%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);color:var(--_et-qdt-error)}}.et-query-devtools-btn--tampered,.et-query-devtools-btn--tampered:hover:not(:disabled){background:color-mix(in srgb,var(--_et-qdt-error) 14%,transparent);border-color:color-mix(in srgb,var(--_et-qdt-error) 45%,transparent);color:var(--_et-qdt-error)}.et-query-devtools-icon-btn{inline-size:var(--_et-qdt-control-h);padding-inline:0;font-size:1.3rem}.et-query-devtools-btn-group{display:inline-flex;flex:0 0 auto;border:1px solid var(--_et-qdt-line);border-radius:var(--_et-qdt-radius);overflow:hidden}.et-query-devtools-btn-group>.et-query-devtools-btn{border-radius:0;border-block:0;border-inline-start:0;border-inline-end:1px solid var(--_et-qdt-line)}.et-query-devtools-btn-group>.et-query-devtools-btn:last-child{border-inline-end:0}.et-query-devtools-btn-group>.et-query-devtools-btn:focus-visible{outline-offset:-2px}.et-query-devtools-toolbar-btn{margin-inline-start:auto;flex:0 0 auto}.et-query-devtools-meta{display:grid;grid-template-columns:auto 1fr;gap:.3rem 1rem;margin:0 0 1rem}.et-query-devtools-meta dt{color:var(--_et-qdt-muted)}.et-query-devtools-meta dd{margin:0;overflow-wrap:anywhere}.et-query-devtools-section{margin:1rem 0 .4rem;font-size:1.1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat{padding:.6rem .8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 3%,transparent)}.et-query-devtools-stat dt{font-size:1rem;text-transform:uppercase;letter-spacing:.05em;color:var(--_et-qdt-muted)}.et-query-devtools-stat dd{margin:0;font-size:1.5rem;font-variant-numeric:tabular-nums}.et-query-devtools-stat-sub{display:block;font-size:1rem;color:var(--_et-qdt-subtle)}.et-query-devtools-json{margin:0;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow-x:auto;white-space:pre-wrap;overflow-wrap:anywhere;max-block-size:24rem;overflow-y:auto}.et-query-devtools-json--error{border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-mono{font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.et-query-devtools-url{display:inline-block;max-inline-size:32rem;margin-inline-start:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.et-query-devtools-chips,.et-query-devtools-chip-row{display:flex;flex-wrap:wrap;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-chip{display:inline-flex;align-items:center;gap:.3rem;padding:.2rem .6rem;border-radius:999px;border:1px solid var(--_et-qdt-border);font-size:1.1rem;color:var(--_et-qdt-fg);background:color-mix(in srgb,var(--_et-qdt-interaction) 6%,transparent)}.et-query-devtools-chip--muted{color:var(--_et-qdt-muted)}.et-query-devtools-retry-glyph{font-size:.7em;line-height:1}.et-query-devtools-chip--loading{color:var(--_et-qdt-loading);border-color:color-mix(in srgb,var(--_et-qdt-loading) 50%,transparent)}.et-query-devtools-chip--error{color:var(--_et-qdt-error);border-color:color-mix(in srgb,var(--_et-qdt-error) 50%,transparent)}.et-query-devtools-chip--success{color:var(--_et-qdt-success);border-color:color-mix(in srgb,var(--_et-qdt-success) 50%,transparent)}button.et-query-devtools-chip--button{appearance:none;border-color:var(--_et-qdt-line);cursor:pointer;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}@media(hover:hover){button.et-query-devtools-chip--button:hover{border-color:var(--_et-qdt-accent);color:var(--_et-qdt-accent)}}.et-query-devtools-facet{appearance:none;border-color:var(--_et-qdt-line);min-block-size:var(--_et-qdt-control-h);padding-inline:.8rem;background:transparent;cursor:pointer;color:var(--_et-qdt-muted);font:inherit;font-size:1.1rem;line-height:1.4}@media(hover:hover){.et-query-devtools-facet:hover:not(:disabled){color:var(--_et-qdt-fg);background:var(--_et-qdt-hover);border-color:color-mix(in srgb,var(--_et-qdt-accent) 60%,transparent)}}.et-query-devtools-facet:disabled{color:var(--_et-qdt-subtle);cursor:default}.et-query-devtools-facet--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 14%,transparent)}.et-query-devtools-facet-count{font-variant-numeric:tabular-nums;color:inherit;opacity:.75}.et-query-devtools-card{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius-lg);padding:1rem}.et-query-devtools-card--armed{border-color:color-mix(in srgb,var(--_et-qdt-error) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-error) 6%,transparent)}.et-query-devtools-card-head{display:flex;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-inner-queries{display:flex;flex-direction:column;gap:.3rem}.et-query-devtools-inner-row{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);background:transparent;color:var(--_et-qdt-fg);padding:.4rem .6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-inner-row:hover:not([disabled]){background:var(--_et-qdt-hover)}}.et-query-devtools-inner-row--active{background:var(--_et-qdt-active);border-color:var(--_et-qdt-accent)}.et-query-devtools-inner-row[disabled]{cursor:default;opacity:.6}.et-query-devtools-step-toggle{display:flex;align-items:center;gap:.6rem;inline-size:100%;text-align:start;appearance:none;border:none;background:transparent;color:var(--_et-qdt-fg);padding:.6rem;cursor:pointer;font:inherit}@media(hover:hover){.et-query-devtools-step-toggle:hover{background:var(--_et-qdt-hover)}}.et-query-devtools-step-index{flex:1 1 auto;min-inline-size:0}.et-query-devtools-step-caret{color:var(--_et-qdt-muted)}.et-query-devtools-table{inline-size:100%;border-collapse:collapse}.et-query-devtools-table-scroll{overflow-x:auto}.et-query-devtools-table-scroll>.et-query-devtools-table{min-inline-size:max-content}.et-query-devtools-table th,.et-query-devtools-table td{text-align:start;padding:.5rem .6rem;border-block-end:1px solid var(--_et-qdt-border);vertical-align:top}.et-query-devtools-table td .et-query-devtools-chip{padding-block:0;line-height:1.4}.et-query-devtools-table th{color:var(--_et-qdt-muted);font-weight:600;position:sticky;inset-block-start:0;background:var(--_et-qdt-bg)}.et-query-devtools-table tr[data-status=error] td{color:var(--_et-qdt-error)}.et-query-devtools-table .et-query-devtools-cell-origin{inline-size:12ch;max-inline-size:12ch;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;overflow-wrap:normal}.et-query-devtools-empty{color:var(--_et-qdt-subtle);padding:1.2rem;text-align:center}.et-query-devtools-cell-actions{display:inline-flex;gap:.4rem;white-space:nowrap}.et-query-devtools-section-row{display:flex;align-items:center;justify-content:space-between;gap:.8rem;margin-block-start:1rem}.et-query-devtools-search{flex:1 1 16rem;min-inline-size:0;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-search:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-row-link{display:inline-flex;align-items:center;gap:.6rem;appearance:none;border:0;background:none;padding:0;color:inherit;font:inherit;text-align:start;cursor:pointer}.et-query-devtools-row-link:focus-visible .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}@media(hover:hover){.et-query-devtools-row-link:hover .et-query-devtools-url{color:var(--_et-qdt-accent);text-decoration:underline}}.et-query-devtools-hint{flex:1 1 24rem;color:var(--_et-qdt-muted);font-size:1.1rem;margin:0}.et-query-devtools-input{inline-size:100%;min-block-size:var(--_et-qdt-control-h);background:var(--_et-qdt-field);color:var(--_et-qdt-fg);border:1px solid transparent;border-radius:var(--_et-qdt-radius);padding:.4rem .8rem;font:inherit;font-size:1.15rem}.et-query-devtools-input:focus{outline:none;border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:var(--_et-qdt-bg)}.et-query-devtools-input--number{inline-size:8rem;font-variant-numeric:tabular-nums}.et-query-devtools-editor{border:1px solid var(--_et-qdt-border);border-radius:var(--_et-qdt-radius);padding:.8rem;margin-block-end:1rem}.et-query-devtools-editor-error{color:var(--_et-qdt-error);margin:.4rem 0 0}.et-query-devtools-btn--active{color:var(--_et-qdt-accent);border-color:color-mix(in srgb,var(--_et-qdt-accent) 55%,transparent);background:color-mix(in srgb,var(--_et-qdt-accent) 12%,transparent)}}\n"] }]
7572
+ }], ctorParameters: () => [], propDecorators: { startOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "startOpen", required: false }] }], panelEl: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], toggle: [{ type: i0.ViewChild, args: [i0.forwardRef(() => QueryDevtoolsToggleComponent), { isSignal: true }] }], tabButtons: [{ type: i0.ViewChildren, args: ['tabButton', { isSignal: true }] }] } });
7486
7573
 
7487
7574
  const QUERY_DEVTOOLS_IMPORTS = [QueryDevtoolsComponent];
7488
7575
 
@@ -7490,5 +7577,5 @@ const QUERY_DEVTOOLS_IMPORTS = [QueryDevtoolsComponent];
7490
7577
  * Generated bundle index. Do not edit.
7491
7578
  */
7492
7579
 
7493
- export { QUERY_DEVTOOLS_IMPORTS, QUERY_DEVTOOLS_VERSION, QueryDevtoolsAboutComponent, QueryDevtoolsComponent, QueryDevtoolsJsonComponent, QueryDevtoolsJsonStylesComponent, QueryDevtoolsSettingsComponent, QueryDevtoolsTimelineStylesComponent, clampFloatToPeek, kindOf, resizedFloatRect, settledFloatRect };
7580
+ export { QUERY_DEVTOOLS_IMPORTS, QUERY_DEVTOOLS_VERSION, QueryDevtoolsComponent };
7494
7581
  //# sourceMappingURL=ethlete-query-devtools.mjs.map