@ethlete/query-devtools 1.0.0-next.7 → 1.0.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0-next.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#3069](https://github.com/ethlete-io/ethdk/pull/3069) [`0c324b0`](https://github.com/ethlete-io/ethdk/commit/0c324b0d765fb6a07ec9a5766638bd5b52006651) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query devtools: list a query's request headers in their own section, so a secure query's `Authorization` is readable however its args reached it.
|
|
8
|
+
|
|
9
|
+
- [#3069](https://github.com/ethlete-io/ethdk/pull/3069) [`55736ec`](https://github.com/ethlete-io/ethdk/commit/55736ec21189efa86fd107043579fc4c65e4452e) Thanks [@github-actions](https://github.com/apps/github-actions)! - Correct reactive state mutability declarations across Query, Contentful and Query Devtools.
|
|
10
|
+
|
|
3
11
|
## 1.0.0-next.7
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -1856,6 +1856,12 @@ class QueryDevtoolsDetailComponent {
|
|
|
1856
1856
|
/** Whether any of the three exports behind the Copy menu has just landed on the clipboard. */
|
|
1857
1857
|
this.copied = computed(() => this.host.copiedReport() || this.host.copiedCurl() || this.host.copiedInsomnia(), /* @ts-ignore */
|
|
1858
1858
|
...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
|
|
1859
|
+
/**
|
|
1860
|
+
* Memoized rather than read straight from the host in the template: the record is built per read, and
|
|
1861
|
+
* a fresh object on every change-detection pass would re-seed the value explorer each time.
|
|
1862
|
+
*/
|
|
1863
|
+
this.requestHeaders = computed(() => this.host.requestHeaders(this.sel().query), /* @ts-ignore */
|
|
1864
|
+
...(ngDevMode ? [{ debugName: "requestHeaders" }] : /* istanbul ignore next */ []));
|
|
1859
1865
|
this.overrideSetSource = computed(() => {
|
|
1860
1866
|
const sel = this.sel();
|
|
1861
1867
|
const url = this.host.requestUrl(sel.query);
|
|
@@ -1905,7 +1911,7 @@ class QueryDevtoolsDetailComponent {
|
|
|
1905
1911
|
};
|
|
1906
1912
|
}
|
|
1907
1913
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: QueryDevtoolsDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1908
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: QueryDevtoolsDetailComponent, isStandalone: true, selector: "et-query-devtools-detail", inputs: { sel: { classPropertyName: "sel", publicName: "sel", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let s = sel();\n\n<div class=\"et-query-devtools-detail-head\">\n <span class=\"et-query-devtools-method\">{{ s.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(s.entry, s.query)\" />\n </span>\n <button\n [attr.aria-label]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [title]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [class.et-query-devtools-route-copy--copied]=\"host.copiedRoute()\"\n (click)=\"host.copyRoute(s.entry, s.query)\"\n class=\"et-query-devtools-route-copy\"\n type=\"button\"\n >\n {{ host.copiedRoute() ? '\u2713' : '\u29C9' }}\n </button>\n @if (host.isTampered(s.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 @if (isGone()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">gone</span>\n }\n</div>\n\n@if (s.entry.destroyedAt; as destroyedAt) {\n <p class=\"et-query-devtools-gone-note\">\n Destroyed at {{ host.formatTime(destroyedAt) }}. This is the last state the query held - nothing here updates, and\n it cannot be run again.\n </p>\n}\n\n@if (host.requestProgress(s.query); as live) {\n <div class=\"et-query-devtools-live\">\n @if (live.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"The retry policy is backing off before it tries again. A query stuck loading with this chip is waiting, not slow.\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n attempt {{ retry.attempt }} in {{ host.formatCountdown(live.retryInMs) }}\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.retryCause(retry.status) }} \u00B7 backing off {{ host.formatDuration(retry.delayMs) }}\n </span>\n } @else if (live.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"How many HTTP attempts the last execution took - the retry policy fired for the rest\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ live.attempts }} attempts\n </span>\n }\n\n @if (live.progress; as progress) {\n <span\n [attr.aria-valuenow]=\"progress.percentage\"\n class=\"et-query-devtools-progress\"\n role=\"progressbar\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=\"Transfer progress\"\n >\n <span [style.inline-size.%]=\"progress.percentage\" class=\"et-query-devtools-progress-bar\"></span>\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.formatPercent(progress.percentage) }} \u00B7 {{ host.formatBytes(progress.loaded) }} of\n {{ host.formatBytes(progress.total) }}\n @if (progress.speed !== null) {\n \u00B7 {{ host.formatSpeed(progress.speed) }}\n }\n @if (progress.remainingTime !== null) {\n \u00B7 {{ host.formatDuration(progress.remainingTime) }} left\n }\n </span>\n }\n </div>\n}\n\n<!-- One row, one primary action. Everything a query can be *made* to do lives behind Override, and\n everything that leaves the panel behind Copy - a flat row of all twelve read as a wall of equal\n buttons in which Execute was no easier to find than Clear. -->\n<div class=\"et-query-devtools-actions\">\n @if (!isGone()) {\n <div class=\"et-query-devtools-btn-group\">\n <button\n (click)=\"host.executeQuery(s, false)\"\n class=\"et-query-devtools-btn et-query-devtools-btn--primary\"\n type=\"button\"\n title=\"Run the query again, ignoring the cache\"\n >\n <span aria-hidden=\"true\">\u25B6</span>\n Execute\n </button>\n <button\n (click)=\"host.executeQuery(s, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Run it the way the app would - a fresh enough cached response is used instead of a request\"\n >\n Cached\n </button>\n <button\n (click)=\"host.resetQuery(s.query)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Drop this query's state back to idle\"\n >\n Reset\n </button>\n </div>\n }\n @let locatable = host.locatableElement(s.entry);\n <button\n [disabled]=\"!locatable\"\n [class.et-query-devtools-btn--active]=\"host.locateState() === 'located'\"\n [title]=\"\n locatable\n ? 'Scroll to and outline the element this query was created in. That is where it was created, not necessarily where its data is rendered.'\n : 'This query was created outside a component or directive - a root service, a resolver or a guard - so it has no element to point at.'\n \"\n (click)=\"host.locateQuery(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2316</span>\n @switch (host.locateState()) {\n @case ('located') {\n Created here\n }\n @case ('offscreen') {\n Not on screen\n }\n @default {\n Locate\n }\n }\n </button>\n\n <!-- The tick has to live on the trigger: the menu closes on the pick, so a confirmation inside it\n would be gone before it could be read. -->\n <div class=\"et-query-devtools-menu\" etMenu>\n <button class=\"et-query-devtools-btn\" title=\"Take this request somewhere else\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ copied() ? '\u2713' : '\u29C9' }}</span>\n {{ copied() ? 'Copied' : 'Copy' }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.copyReport(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy report\n <span class=\"et-query-devtools-menu-item-note\">Everything the panel knows, as markdown</span>\n </button>\n <button (activate)=\"host.copyCurlRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy as cURL\n <span class=\"et-query-devtools-menu-item-note\">URL, resolved headers and body</span>\n </button>\n <button (activate)=\"host.copyInsomniaRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy for Insomnia\n <span class=\"et-query-devtools-menu-item-note\">A collection to import from the clipboard</span>\n </button>\n </et-menu>\n </ng-template>\n </div>\n\n @if (!isGone()) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [class.et-query-devtools-btn--tampered]=\"host.isTampered(s.entry)\"\n class=\"et-query-devtools-btn\"\n title=\"Make this query answer with something other than what the API sent\"\n type=\"button\"\n etMenuTrigger\n >\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">\u270E</span>\n Override\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.openResponseEditor(s.query)\" et-menu-item type=\"button\">Edit response\u2026</button>\n <button (activate)=\"host.openArgsEditor(s)\" et-menu-item type=\"button\">Replay with edited args\u2026</button>\n <et-menu-separator />\n <button (activate)=\"host.forceLoading(s.query)\" et-menu-item type=\"button\">Force loading</button>\n <button (activate)=\"host.forceError(s.query)\" et-menu-item type=\"button\">Force error</button>\n <button (activate)=\"host.forceEmpty(s.query)\" et-menu-item type=\"button\">Force empty</button>\n <et-menu-separator />\n <button (activate)=\"host.clearForced(s.query)\" et-menu-item type=\"button\">Clear forced state</button>\n\n @if (s.entry.overrides; as overrides) {\n <et-menu-separator />\n <et-query-devtools-override-set-menu\n [overrides]=\"overrides\"\n [response]=\"s.query.response()\"\n [source]=\"overrideSetSource()\"\n />\n }\n </et-menu>\n </ng-template>\n </div>\n }\n</div>\n\n@if (!isGone() && host.editorMode() !== 'none') {\n <div class=\"et-query-devtools-editor\">\n @if (host.editorMode() === 'response') {\n <h4 class=\"et-query-devtools-section\">Edit response \u2192 setResponse()</h4>\n <textarea\n #respArea\n [value]=\"host.editorSeed\"\n (input)=\"host.responseDraft.set(respArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyResponse(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Apply</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <h4 class=\"et-query-devtools-section\">Replay with edited args \u2192 execute()</h4>\n <textarea\n #argsArea\n [value]=\"host.editorSeed\"\n (input)=\"host.argsDraft.set(argsArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyArgs(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Execute</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n }\n @if (host.editError(); as err) {\n <p class=\"et-query-devtools-editor-error\">{{ err }}</p>\n }\n </div>\n}\n\n@let detailRuns = host.queryRuns(s.entry);\n<nav class=\"et-query-devtools-subtabs\" role=\"tablist\">\n @for (tab of detailTabs; track tab.id) {\n <button\n [class.et-query-devtools-subtab--active]=\"host.detailTab() === tab.id\"\n [attr.aria-selected]=\"host.detailTab() === tab.id\"\n (click)=\"host.detailTab.set(tab.id)\"\n class=\"et-query-devtools-subtab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (tab.id === 'history' && detailRuns.length) {\n <span class=\"et-query-devtools-tab-badge\">{{ detailRuns.length }}</span>\n }\n <!-- The error body lives under Data, so the tab has to say so - a failure must not hide\n behind a tab that is not open. -->\n @if (tab.id === 'data' && s.query.error()) {\n <span class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\">!</span>\n }\n </button>\n }\n</nav>\n\n@switch (host.detailTab()) {\n @case ('overview') {\n <dl class=\"et-query-devtools-meta\">\n <dt>Base URL</dt>\n <dd class=\"et-query-devtools-mono\">\n {{ s.entry.meta.clientBaseUrl || s.entry.meta.clientName || '\u2014' }}\n </dd>\n <dt>Route</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.entry.meta.route || '\u2014' }}</dd>\n <dt>Request URL</dt>\n <dd class=\"et-query-devtools-mono\">{{ host.requestUrl(s.query) || '\u2014' }}</dd>\n <dt>Status</dt>\n <dd>{{ host.queryStatus(s.query) }}</dd>\n <dt>Cache key</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.query.id() || '\u2014' }}</dd>\n <dt>Last executed</dt>\n <dd>{{ host.formatTime(s.query.lastTimeExecutedAt()) }}</dd>\n <dt>Triggered by</dt>\n <dd>{{ s.query.triggeredBy() || 'user' }}</dd>\n @let refreshes = host.refreshesFor(s.entry.id);\n @if (refreshes.length) {\n <dt title=\"Invalidations and mutation refreshes that re-executed this query, as far back as the event log goes\">\n Refetched by\n </dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (refresh of refreshes.slice(0, 5); track refresh.id) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">\n {{ host.formatTime(refresh.timestamp) }} \u00B7 {{ refresh.label }}\n </span>\n }\n @if (refreshes.length > 5) {\n <span class=\"et-query-devtools-hint\">+{{ refreshes.length - 5 }} earlier</span>\n }\n </div>\n </dd>\n }\n @let drivers = host.formsDrivingQuery(s.entry);\n @if (drivers.length) {\n <dt>Args from</dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (driver of drivers; track driver.id) {\n <button\n (click)=\"host.selectForm(driver.id)\"\n class=\"et-query-devtools-chip et-query-devtools-chip--button\"\n type=\"button\"\n title=\"Open the query form in the Forms tab\"\n >\n {{ driver.meta.name }}\n </button>\n }\n </div>\n </dd>\n }\n @if (s.entry.meta.features?.length) {\n <dt>Features</dt>\n <dd>\n <et-query-devtools-features [features]=\"s.entry.meta.features ?? []\" />\n </dd>\n }\n </dl>\n\n @let activity = host.queryActivity(s.entry);\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Activity</h4>\n <button\n [disabled]=\"!activity.hasActivity\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the counters and the run history, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n\n <dl class=\"et-query-devtools-stats\">\n <div class=\"et-query-devtools-stat\" title=\"Every time the query ran, cache hits included\">\n <dt>Refreshes</dt>\n <dd>{{ activity.stats.executions }}</dd>\n @if (activity.cacheServed) {\n <span class=\"et-query-devtools-stat-sub\">{{ activity.cacheServed }} without a request</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\" title=\"Executions that started a request, and how they ended\">\n <dt>Requests</dt>\n <dd>{{ activity.stats.requests }}</dd>\n <span class=\"et-query-devtools-stat-sub\">\n {{ activity.stats.responses }} ok\n @if (activity.stats.errors) {\n \u00B7 {{ activity.stats.errors }} failed\n }\n </span>\n </div>\n <div\n class=\"et-query-devtools-stat\"\n title=\"Total response payload received. Sizes without a content-length header are measured from the decoded body, so they ignore compression.\"\n >\n <dt>Received</dt>\n <dd>{{ host.formatTransferred(activity.stats.receivedBytes, activity.stats.hasEstimatedBytes) }}</dd>\n @if (activity.avgResponseBytes !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatBytes(activity.avgResponseBytes) }} per response</span>\n }\n </div>\n @if (activity.stats.sentBytes) {\n <div class=\"et-query-devtools-stat\" title=\"Total request body sent (headers not counted)\">\n <dt>Sent</dt>\n <dd>{{ host.formatTransferred(activity.stats.sentBytes, activity.stats.hasEstimatedBytes) }}</dd>\n </div>\n }\n @if (activity.stats.retries) {\n <div\n class=\"et-query-devtools-stat\"\n title=\"Attempts the retry policy added on top of the first one. Which run they belong to is under History.\"\n >\n <dt>Retries</dt>\n <dd>{{ activity.stats.retries }}</dd>\n </div>\n }\n <div class=\"et-query-devtools-stat\" title=\"Measured from the execution that preceded each response\">\n <dt>Duration</dt>\n <dd>{{ host.formatDuration(activity.stats.lastDurationMs) }}</dd>\n @if (activity.avgDurationMs !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatDuration(activity.avgDurationMs) }} on average</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\">\n <dt>Last response</dt>\n <dd class=\"et-query-devtools-stat-value--sm\">{{ host.formatTime(activity.stats.lastResponseAt) }}</dd>\n @if (activity.stats.firstExecutedAt !== null) {\n <span class=\"et-query-devtools-stat-sub\"\n >first ran {{ host.formatTime(activity.stats.firstExecutedAt) }}</span\n >\n }\n </div>\n </dl>\n }\n @case ('history') {\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Runs</h4>\n <button\n [disabled]=\"!detailRuns.length\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the run history and the counters, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n @if (detailRuns.length) {\n <table class=\"et-query-devtools-table\">\n <thead>\n <tr>\n <th>Run</th>\n <th>Started</th>\n <th>Duration</th>\n <th>Received</th>\n <th>Body</th>\n </tr>\n </thead>\n <tbody>\n @for (run of runSections().listed.concat(foldedRunsOpen() ? runSections().folded : []); track run.index) {\n <tr [attr.data-status]=\"run.status === 'error' ? 'error' : null\">\n <td>\n <span class=\"et-query-devtools-run-cell\">\n <span\n [attr.data-status]=\"host.runStatus(run)\"\n [title]=\"run.status\"\n class=\"et-query-devtools-status\"\n ></span>\n #{{ run.index }}\n @if (run.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Took {{\n run.attempts\n }} attempts - the duration next to it covers every one of them, backoff included\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ run.attempts }}\n </span>\n }\n @if (!run.didRequest) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"Arrived without a request of this query's own - a poll, another consumer of the same cache entry, or another tab\"\n >\n shared\n </span>\n }\n @if (run.error; as error) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"{{ error.messages.join(' \u00B7 ') || 'The failure carried no message' }}\"\n >\n {{ error.code || 'failed' }}\n </span>\n }\n </span>\n </td>\n <td>{{ host.formatTime(run.startedAt) }}</td>\n <td>\n @if (run.endedAt === null) {\n in flight\n } @else {\n {{ host.formatDuration(run.endedAt - run.startedAt) }}\n }\n </td>\n <td>{{ run.receivedBytes ? host.formatBytes(run.receivedBytes) : '\u2014' }}</td>\n <td>\n <span class=\"et-query-devtools-cell-actions\">\n @if (host.canDiffRun(s.entry, run)) {\n @let role = host.diffRunRole(s.entry, run);\n @let armed = role ? diffRoles[role] : null;\n <button\n [class.et-query-devtools-btn--active]=\"!!armed\"\n [title]=\"\n armed?.title ?? 'Compare this response against another run - click a second row to pick which'\n \"\n (click)=\"host.toggleRunDiff(s.entry, run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ armed?.label ?? 'Diff' }}\n </button>\n } @else if (run.error?.hasBody) {\n <button\n [class.et-query-devtools-btn--active]=\"host.errorRunIndex() === run.index\"\n (click)=\"host.toggleRunError(run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Show the body this failure came with\"\n >\n Error\n </button>\n } @else if (run.hasResponse) {\n <span class=\"et-query-devtools-count\">the only body held</span>\n } @else if (run.status === 'success' || run.error) {\n <span\n class=\"et-query-devtools-count\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so this run can no longer be an end of a diff\"\n >\n body no longer held\n </span>\n } @else {\n <span class=\"et-query-devtools-count\">\u2014</span>\n }\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @let foldedRuns = runSections().folded.length;\n @if (foldedRuns) {\n <button\n [attr.aria-expanded]=\"foldedRunsOpen()\"\n (click)=\"foldedRunsOpen.set(!foldedRunsOpen())\"\n class=\"et-query-devtools-btn et-query-devtools-runs-fold\"\n type=\"button\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so none of these older runs can be an end of a diff\"\n >\n <span aria-hidden=\"true\">{{ foldedRunsOpen() ? '\u25BE' : '\u25B8' }}</span>\n {{ foldedRunsOpen() ? 'Hide' : 'Show' }} {{ foldedRuns }} older run{{ foldedRuns === 1 ? '' : 's' }} with no\n body\n </button>\n }\n\n @if (host.pickedRunError(s.entry); as failure) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Error body \u00B7 run #{{ failure.run.index }} \u00B7 {{ failure.error.code || 'no status' }}\n </h5>\n </div>\n @for (message of failure.error.messages; track message) {\n <p class=\"et-query-devtools-count\">{{ message }}</p>\n }\n <et-query-devtools-json\n [value]=\"failure.error.body\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"runError\"\n />\n }\n\n @if (host.responseDiff(s.entry); as comparison) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Response diff \u00B7 run #{{ comparison.before.index }} \u2192 #{{ comparison.after.index }}\n </h5>\n <span class=\"et-query-devtools-diff-step\">\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, true)\"\n (click)=\"host.stepRunDiff(s.entry, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run older, without going back to the table\"\n >\n \u25C2 Older\n </button>\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, false)\"\n (click)=\"host.stepRunDiff(s.entry, false)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run newer, without going back to the table\"\n >\n Newer \u25B8\n </button>\n </span>\n <span class=\"et-query-devtools-count\">\n @if (host.diffBaseRunIndex() === null) {\n <span\n title=\"Nothing is picked to compare against, so this is the nearest older run that still holds a body - click another run's Diff to pick one\"\n >\n nearest older\n </span>\n \u00B7\n }\n @if (comparison.diff.entries.length) {\n {{ comparison.diff.entries.length }} path{{ comparison.diff.entries.length === 1 ? '' : 's' }}\n @if (comparison.diff.truncated) {\n (capped)\n }\n } @else {\n identical\n }\n </span>\n </div>\n @if (comparison.diff.entries.length) {\n <table class=\"et-query-devtools-table et-query-devtools-diff\">\n <thead>\n <tr>\n <th>Path</th>\n <th>Before</th>\n <th>After</th>\n </tr>\n </thead>\n <tbody>\n @for (change of comparison.diff.entries; track change.path) {\n <tr [attr.data-kind]=\"change.kind\">\n <td class=\"et-query-devtools-mono\">{{ change.path }}</td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-before\">\n {{ change.kind === 'added' ? '\u2014' : host.inlineValue(change.before) }}\n </td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-after\">\n {{ change.kind === 'removed' ? '\u2014' : host.inlineValue(change.after) }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"et-query-devtools-empty\">The two responses are identical.</p>\n }\n }\n } @else {\n <p class=\"et-query-devtools-empty\">No runs recorded yet.</p>\n }\n }\n @case ('data') {\n @if (s.entry.meta.gqlQuery; as gqlQuery) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">GraphQL document</h5>\n <button\n (click)=\"host.copyGqlDocument(gqlQuery)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy the GraphQL document\"\n >\n {{ host.copiedGql() ? '\u2713 Copied' : '\u29C9 Copy' }}\n </button>\n </div>\n <pre class=\"et-query-devtools-code\">{{ host.gqlDocument(gqlQuery) }}</pre>\n }\n\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Value explorer</h4>\n <input\n #jsonSearchInput\n [value]=\"host.jsonSearch()\"\n (input)=\"host.jsonSearch.set(jsonSearchInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter keys / values\u2026\"\n />\n </div>\n\n <h5 class=\"et-query-devtools-section\">Args</h5>\n <et-query-devtools-json\n [value]=\"host.queryArgs(s.query)\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"args\"\n />\n\n @if (s.query.error(); as error) {\n <h5 class=\"et-query-devtools-section\">Error ({{ error.raw.status }})</h5>\n <et-query-devtools-json\n [value]=\"error.isList ? error.errors : error.error\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"error\"\n />\n } @else {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">Response</h5>\n @if (s.entry.overrides?.list()?.length || host.overridesPersist()) {\n <button\n [class.et-query-devtools-btn--active]=\"host.overridesPersist()\"\n [attr.aria-pressed]=\"host.overridesPersist()\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{\n host.overridesPersist()\n ? 'Panel-wide: every armed response override is kept in ' +\n host.overridesScopeLabel() +\n ' and replayed on the next load.'\n : 'Panel-wide: keep every armed response override and replay it on the next load.'\n }} Settings \u2699 chooses the scope. Armed faults are never kept.\"\n >\n Keep across reloads\n </button>\n }\n @if (s.entry.overrides?.list()?.length) {\n <button (click)=\"s.entry.overrides?.clearAll()\" class=\"et-query-devtools-btn\" type=\"button\">\n Reset all overrides ({{ s.entry.overrides?.list()?.length }})\n </button>\n }\n </div>\n <et-query-devtools-json\n [value]=\"s.query.response()\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n [overrides]=\"s.entry.overrides ?? null\"\n path=\"response\"\n />\n }\n }\n}\n", styles: ["@layer components{.et-query-devtools-detail .et-query-devtools-detail-head,.et-query-devtools-drawer .et-query-devtools-detail-head{padding-block-end:.8rem;border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-gone-note{margin:0 0 .8rem;color:var(--_et-qdt-muted);font-size:1.1rem}.et-query-devtools-detail-head{display:flex;align-items:center;gap:.8rem;margin-block-end:.8rem}.et-query-devtools-detail-head .et-query-devtools-route{flex:0 1 auto}.et-query-devtools-route-copy{appearance:none;margin-inline-end:auto;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:2.2rem;block-size:2.2rem;margin-inline-start:-.4rem;border:none;border-radius:.3rem;background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font:inherit;font-size:1.3rem;line-height:1}@media(hover:hover){.et-query-devtools-route-copy:hover:not(.et-query-devtools-route-copy--copied){background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-route-copy--copied{color:var(--_et-qdt-success)}.et-query-devtools-live{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-live-note{color:var(--_et-qdt-muted);font-size:1.15rem}.et-query-devtools-progress{display:block;flex:1 1 12rem;min-inline-size:8rem;max-inline-size:24rem;block-size:.5rem;border-radius:999px;overflow:hidden;background:var(--_et-qdt-border)}.et-query-devtools-progress-bar{display:block;block-size:100%;border-radius:inherit;background:var(--_et-qdt-accent)}.et-query-devtools-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-actions>.et-query-devtools-menu+.et-query-devtools-menu{margin-inline-start:.5rem;padding-inline-start:.9rem;border-inline-start:1px solid var(--_et-qdt-border)}.et-query-devtools-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.6rem;margin:0 0 1rem}.et-query-devtools-stat-value--sm{font-size:1.2rem}.et-query-devtools-code{margin:0 0 .8rem;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:.4rem;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow:auto;white-space:pre;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:1.15rem;max-block-size:20rem}.et-query-devtools-diff-step{display:flex;gap:.4rem;margin-inline-start:auto}.et-query-devtools-runs-fold{margin-block-start:.4rem;color:var(--_et-qdt-muted)}.et-query-devtools-textarea{inline-size:100%;min-block-size:12rem;resize:vertical;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);color:var(--_et-qdt-fg);border:1px solid var(--_et-qdt-border);border-radius:.4rem;padding:.6rem;font-family:inherit;font-size:1.2rem}.et-query-devtools-subtabs{display:flex;flex-wrap:wrap;gap:.2rem;border-block-end:1px solid var(--_et-qdt-border);margin-block:.8rem}.et-query-devtools-subtabs+.et-query-devtools-section-row{padding-block-start:0;border-block-start:0}.et-query-devtools-subtab{appearance:none;display:inline-flex;align-items:center;gap:.4rem;border:0;border-block-end:2px solid transparent;background:transparent;color:var(--_et-qdt-muted);font:inherit;font-size:1.15rem;padding:.4rem .6rem;margin-block-end:-1px;cursor:pointer}@media(hover:hover){.et-query-devtools-subtab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-subtab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-run-cell{display:inline-flex;align-items:center;gap:.5rem}.et-query-devtools-diff td{max-inline-size:28rem;overflow-wrap:anywhere}.et-query-devtools-diff-before{color:var(--_et-qdt-muted)}.et-query-devtools-diff tr[data-kind=removed] .et-query-devtools-diff-before{color:var(--_et-qdt-error)}.et-query-devtools-diff tr[data-kind=added] .et-query-devtools-diff-after{color:var(--_et-qdt-success)}.et-query-devtools-diff tr[data-kind=changed] .et-query-devtools-diff-after{color:var(--_et-qdt-accent)}}\n"], dependencies: [{ 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: 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: QueryDevtoolsFeaturesComponent, selector: "et-query-devtools-features", inputs: ["features"] }, { kind: "component", type: QueryDevtoolsJsonComponent, selector: "et-query-devtools-json", inputs: ["value", "nodeKey", "depth", "search", "chunk", "path", "expandedPaths", "collapsedPaths", "toggleFn", "jsonPath", "parentKind", "overrides", "annotations"] }, { kind: "component", type: QueryDevtoolsOverrideSetMenuComponent, selector: "et-query-devtools-override-set-menu", inputs: ["overrides", "response", "source"] }, { kind: "component", type: QueryDevtoolsRouteComponent, selector: "et-query-devtools-route", inputs: ["segments", "fallback", "trimPrefix"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1914
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: QueryDevtoolsDetailComponent, isStandalone: true, selector: "et-query-devtools-detail", inputs: { sel: { classPropertyName: "sel", publicName: "sel", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let s = sel();\n\n<div class=\"et-query-devtools-detail-head\">\n <span class=\"et-query-devtools-method\">{{ s.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(s.entry, s.query)\" />\n </span>\n <button\n [attr.aria-label]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [title]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [class.et-query-devtools-route-copy--copied]=\"host.copiedRoute()\"\n (click)=\"host.copyRoute(s.entry, s.query)\"\n class=\"et-query-devtools-route-copy\"\n type=\"button\"\n >\n {{ host.copiedRoute() ? '\u2713' : '\u29C9' }}\n </button>\n @if (host.isTampered(s.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 @if (isGone()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">gone</span>\n }\n</div>\n\n@if (s.entry.destroyedAt; as destroyedAt) {\n <p class=\"et-query-devtools-gone-note\">\n Destroyed at {{ host.formatTime(destroyedAt) }}. This is the last state the query held - nothing here updates, and\n it cannot be run again.\n </p>\n}\n\n@if (host.requestProgress(s.query); as live) {\n <div class=\"et-query-devtools-live\">\n @if (live.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"The retry policy is backing off before it tries again. A query stuck loading with this chip is waiting, not slow.\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n attempt {{ retry.attempt }} in {{ host.formatCountdown(live.retryInMs) }}\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.retryCause(retry.status) }} \u00B7 backing off {{ host.formatDuration(retry.delayMs) }}\n </span>\n } @else if (live.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"How many HTTP attempts the last execution took - the retry policy fired for the rest\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ live.attempts }} attempts\n </span>\n }\n\n @if (live.progress; as progress) {\n <span\n [attr.aria-valuenow]=\"progress.percentage\"\n class=\"et-query-devtools-progress\"\n role=\"progressbar\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=\"Transfer progress\"\n >\n <span [style.inline-size.%]=\"progress.percentage\" class=\"et-query-devtools-progress-bar\"></span>\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.formatPercent(progress.percentage) }} \u00B7 {{ host.formatBytes(progress.loaded) }} of\n {{ host.formatBytes(progress.total) }}\n @if (progress.speed !== null) {\n \u00B7 {{ host.formatSpeed(progress.speed) }}\n }\n @if (progress.remainingTime !== null) {\n \u00B7 {{ host.formatDuration(progress.remainingTime) }} left\n }\n </span>\n }\n </div>\n}\n\n<!-- One row, one primary action. Everything a query can be *made* to do lives behind Override, and\n everything that leaves the panel behind Copy - a flat row of all twelve read as a wall of equal\n buttons in which Execute was no easier to find than Clear. -->\n<div class=\"et-query-devtools-actions\">\n @if (!isGone()) {\n <div class=\"et-query-devtools-btn-group\">\n <button\n (click)=\"host.executeQuery(s, false)\"\n class=\"et-query-devtools-btn et-query-devtools-btn--primary\"\n type=\"button\"\n title=\"Run the query again, ignoring the cache\"\n >\n <span aria-hidden=\"true\">\u25B6</span>\n Execute\n </button>\n <button\n (click)=\"host.executeQuery(s, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Run it the way the app would - a fresh enough cached response is used instead of a request\"\n >\n Cached\n </button>\n <button\n (click)=\"host.resetQuery(s.query)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Drop this query's state back to idle\"\n >\n Reset\n </button>\n </div>\n }\n @let locatable = host.locatableElement(s.entry);\n <button\n [disabled]=\"!locatable\"\n [class.et-query-devtools-btn--active]=\"host.locateState() === 'located'\"\n [title]=\"\n locatable\n ? 'Scroll to and outline the element this query was created in. That is where it was created, not necessarily where its data is rendered.'\n : 'This query was created outside a component or directive - a root service, a resolver or a guard - so it has no element to point at.'\n \"\n (click)=\"host.locateQuery(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2316</span>\n @switch (host.locateState()) {\n @case ('located') {\n Created here\n }\n @case ('offscreen') {\n Not on screen\n }\n @default {\n Locate\n }\n }\n </button>\n\n <!-- The tick has to live on the trigger: the menu closes on the pick, so a confirmation inside it\n would be gone before it could be read. -->\n <div class=\"et-query-devtools-menu\" etMenu>\n <button class=\"et-query-devtools-btn\" title=\"Take this request somewhere else\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ copied() ? '\u2713' : '\u29C9' }}</span>\n {{ copied() ? 'Copied' : 'Copy' }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.copyReport(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy report\n <span class=\"et-query-devtools-menu-item-note\">Everything the panel knows, as markdown</span>\n </button>\n <button (activate)=\"host.copyCurlRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy as cURL\n <span class=\"et-query-devtools-menu-item-note\">URL, resolved headers and body</span>\n </button>\n <button (activate)=\"host.copyInsomniaRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy for Insomnia\n <span class=\"et-query-devtools-menu-item-note\">A collection to import from the clipboard</span>\n </button>\n </et-menu>\n </ng-template>\n </div>\n\n @if (!isGone()) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [class.et-query-devtools-btn--tampered]=\"host.isTampered(s.entry)\"\n class=\"et-query-devtools-btn\"\n title=\"Make this query answer with something other than what the API sent\"\n type=\"button\"\n etMenuTrigger\n >\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">\u270E</span>\n Override\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.openResponseEditor(s.query)\" et-menu-item type=\"button\">Edit response\u2026</button>\n <button (activate)=\"host.openArgsEditor(s)\" et-menu-item type=\"button\">Replay with edited args\u2026</button>\n <et-menu-separator />\n <button (activate)=\"host.forceLoading(s.query)\" et-menu-item type=\"button\">Force loading</button>\n <button (activate)=\"host.forceError(s.query)\" et-menu-item type=\"button\">Force error</button>\n <button (activate)=\"host.forceEmpty(s.query)\" et-menu-item type=\"button\">Force empty</button>\n <et-menu-separator />\n <button (activate)=\"host.clearForced(s.query)\" et-menu-item type=\"button\">Clear forced state</button>\n\n @if (s.entry.overrides; as overrides) {\n <et-menu-separator />\n <et-query-devtools-override-set-menu\n [overrides]=\"overrides\"\n [response]=\"s.query.response()\"\n [source]=\"overrideSetSource()\"\n />\n }\n </et-menu>\n </ng-template>\n </div>\n }\n</div>\n\n@if (!isGone() && host.editorMode() !== 'none') {\n <div class=\"et-query-devtools-editor\">\n @if (host.editorMode() === 'response') {\n <h4 class=\"et-query-devtools-section\">Edit response \u2192 setResponse()</h4>\n <textarea\n #respArea\n [value]=\"host.editorSeed\"\n (input)=\"host.responseDraft.set(respArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyResponse(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Apply</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <h4 class=\"et-query-devtools-section\">Replay with edited args \u2192 execute()</h4>\n <textarea\n #argsArea\n [value]=\"host.editorSeed\"\n (input)=\"host.argsDraft.set(argsArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyArgs(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Execute</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n }\n @if (host.editError(); as err) {\n <p class=\"et-query-devtools-editor-error\">{{ err }}</p>\n }\n </div>\n}\n\n@let detailRuns = host.queryRuns(s.entry);\n<nav class=\"et-query-devtools-subtabs\" role=\"tablist\">\n @for (tab of detailTabs; track tab.id) {\n <button\n [class.et-query-devtools-subtab--active]=\"host.detailTab() === tab.id\"\n [attr.aria-selected]=\"host.detailTab() === tab.id\"\n (click)=\"host.detailTab.set(tab.id)\"\n class=\"et-query-devtools-subtab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (tab.id === 'history' && detailRuns.length) {\n <span class=\"et-query-devtools-tab-badge\">{{ detailRuns.length }}</span>\n }\n <!-- The error body lives under Data, so the tab has to say so - a failure must not hide\n behind a tab that is not open. -->\n @if (tab.id === 'data' && s.query.error()) {\n <span class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\">!</span>\n }\n </button>\n }\n</nav>\n\n@switch (host.detailTab()) {\n @case ('overview') {\n <dl class=\"et-query-devtools-meta\">\n <dt>Base URL</dt>\n <dd class=\"et-query-devtools-mono\">\n {{ s.entry.meta.clientBaseUrl || s.entry.meta.clientName || '\u2014' }}\n </dd>\n <dt>Route</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.entry.meta.route || '\u2014' }}</dd>\n <dt>Request URL</dt>\n <dd class=\"et-query-devtools-mono\">{{ host.requestUrl(s.query) || '\u2014' }}</dd>\n <dt>Status</dt>\n <dd>{{ host.queryStatus(s.query) }}</dd>\n <dt>Cache key</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.query.id() || '\u2014' }}</dd>\n <dt>Last executed</dt>\n <dd>{{ host.formatTime(s.query.lastTimeExecutedAt()) }}</dd>\n <dt>Triggered by</dt>\n <dd>{{ s.query.triggeredBy() || 'user' }}</dd>\n @let refreshes = host.refreshesFor(s.entry.id);\n @if (refreshes.length) {\n <dt title=\"Invalidations and mutation refreshes that re-executed this query, as far back as the event log goes\">\n Refetched by\n </dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (refresh of refreshes.slice(0, 5); track refresh.id) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">\n {{ host.formatTime(refresh.timestamp) }} \u00B7 {{ refresh.label }}\n </span>\n }\n @if (refreshes.length > 5) {\n <span class=\"et-query-devtools-hint\">+{{ refreshes.length - 5 }} earlier</span>\n }\n </div>\n </dd>\n }\n @let drivers = host.formsDrivingQuery(s.entry);\n @if (drivers.length) {\n <dt>Args from</dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (driver of drivers; track driver.id) {\n <button\n (click)=\"host.selectForm(driver.id)\"\n class=\"et-query-devtools-chip et-query-devtools-chip--button\"\n type=\"button\"\n title=\"Open the query form in the Forms tab\"\n >\n {{ driver.meta.name }}\n </button>\n }\n </div>\n </dd>\n }\n @if (s.entry.meta.features?.length) {\n <dt>Features</dt>\n <dd>\n <et-query-devtools-features [features]=\"s.entry.meta.features ?? []\" />\n </dd>\n }\n </dl>\n\n @let activity = host.queryActivity(s.entry);\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Activity</h4>\n <button\n [disabled]=\"!activity.hasActivity\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the counters and the run history, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n\n <dl class=\"et-query-devtools-stats\">\n <div class=\"et-query-devtools-stat\" title=\"Every time the query ran, cache hits included\">\n <dt>Refreshes</dt>\n <dd>{{ activity.stats.executions }}</dd>\n @if (activity.cacheServed) {\n <span class=\"et-query-devtools-stat-sub\">{{ activity.cacheServed }} without a request</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\" title=\"Executions that started a request, and how they ended\">\n <dt>Requests</dt>\n <dd>{{ activity.stats.requests }}</dd>\n <span class=\"et-query-devtools-stat-sub\">\n {{ activity.stats.responses }} ok\n @if (activity.stats.errors) {\n \u00B7 {{ activity.stats.errors }} failed\n }\n </span>\n </div>\n <div\n class=\"et-query-devtools-stat\"\n title=\"Total response payload received. Sizes without a content-length header are measured from the decoded body, so they ignore compression.\"\n >\n <dt>Received</dt>\n <dd>{{ host.formatTransferred(activity.stats.receivedBytes, activity.stats.hasEstimatedBytes) }}</dd>\n @if (activity.avgResponseBytes !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatBytes(activity.avgResponseBytes) }} per response</span>\n }\n </div>\n @if (activity.stats.sentBytes) {\n <div class=\"et-query-devtools-stat\" title=\"Total request body sent (headers not counted)\">\n <dt>Sent</dt>\n <dd>{{ host.formatTransferred(activity.stats.sentBytes, activity.stats.hasEstimatedBytes) }}</dd>\n </div>\n }\n @if (activity.stats.retries) {\n <div\n class=\"et-query-devtools-stat\"\n title=\"Attempts the retry policy added on top of the first one. Which run they belong to is under History.\"\n >\n <dt>Retries</dt>\n <dd>{{ activity.stats.retries }}</dd>\n </div>\n }\n <div class=\"et-query-devtools-stat\" title=\"Measured from the execution that preceded each response\">\n <dt>Duration</dt>\n <dd>{{ host.formatDuration(activity.stats.lastDurationMs) }}</dd>\n @if (activity.avgDurationMs !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatDuration(activity.avgDurationMs) }} on average</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\">\n <dt>Last response</dt>\n <dd class=\"et-query-devtools-stat-value--sm\">{{ host.formatTime(activity.stats.lastResponseAt) }}</dd>\n @if (activity.stats.firstExecutedAt !== null) {\n <span class=\"et-query-devtools-stat-sub\"\n >first ran {{ host.formatTime(activity.stats.firstExecutedAt) }}</span\n >\n }\n </div>\n </dl>\n }\n @case ('history') {\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Runs</h4>\n <button\n [disabled]=\"!detailRuns.length\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the run history and the counters, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n @if (detailRuns.length) {\n <table class=\"et-query-devtools-table\">\n <thead>\n <tr>\n <th>Run</th>\n <th>Started</th>\n <th>Duration</th>\n <th>Received</th>\n <th>Body</th>\n </tr>\n </thead>\n <tbody>\n @for (run of runSections().listed.concat(foldedRunsOpen() ? runSections().folded : []); track run.index) {\n <tr [attr.data-status]=\"run.status === 'error' ? 'error' : null\">\n <td>\n <span class=\"et-query-devtools-run-cell\">\n <span\n [attr.data-status]=\"host.runStatus(run)\"\n [title]=\"run.status\"\n class=\"et-query-devtools-status\"\n ></span>\n #{{ run.index }}\n @if (run.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Took {{\n run.attempts\n }} attempts - the duration next to it covers every one of them, backoff included\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ run.attempts }}\n </span>\n }\n @if (!run.didRequest) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"Arrived without a request of this query's own - a poll, another consumer of the same cache entry, or another tab\"\n >\n shared\n </span>\n }\n @if (run.error; as error) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"{{ error.messages.join(' \u00B7 ') || 'The failure carried no message' }}\"\n >\n {{ error.code || 'failed' }}\n </span>\n }\n </span>\n </td>\n <td>{{ host.formatTime(run.startedAt) }}</td>\n <td>\n @if (run.endedAt === null) {\n in flight\n } @else {\n {{ host.formatDuration(run.endedAt - run.startedAt) }}\n }\n </td>\n <td>{{ run.receivedBytes ? host.formatBytes(run.receivedBytes) : '\u2014' }}</td>\n <td>\n <span class=\"et-query-devtools-cell-actions\">\n @if (host.canDiffRun(s.entry, run)) {\n @let role = host.diffRunRole(s.entry, run);\n @let armed = role ? diffRoles[role] : null;\n <button\n [class.et-query-devtools-btn--active]=\"!!armed\"\n [title]=\"\n armed?.title ?? 'Compare this response against another run - click a second row to pick which'\n \"\n (click)=\"host.toggleRunDiff(s.entry, run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ armed?.label ?? 'Diff' }}\n </button>\n } @else if (run.error?.hasBody) {\n <button\n [class.et-query-devtools-btn--active]=\"host.errorRunIndex() === run.index\"\n (click)=\"host.toggleRunError(run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Show the body this failure came with\"\n >\n Error\n </button>\n } @else if (run.hasResponse) {\n <span class=\"et-query-devtools-count\">the only body held</span>\n } @else if (run.status === 'success' || run.error) {\n <span\n class=\"et-query-devtools-count\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so this run can no longer be an end of a diff\"\n >\n body no longer held\n </span>\n } @else {\n <span class=\"et-query-devtools-count\">\u2014</span>\n }\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @let foldedRuns = runSections().folded.length;\n @if (foldedRuns) {\n <button\n [attr.aria-expanded]=\"foldedRunsOpen()\"\n (click)=\"foldedRunsOpen.set(!foldedRunsOpen())\"\n class=\"et-query-devtools-btn et-query-devtools-runs-fold\"\n type=\"button\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so none of these older runs can be an end of a diff\"\n >\n <span aria-hidden=\"true\">{{ foldedRunsOpen() ? '\u25BE' : '\u25B8' }}</span>\n {{ foldedRunsOpen() ? 'Hide' : 'Show' }} {{ foldedRuns }} older run{{ foldedRuns === 1 ? '' : 's' }} with no\n body\n </button>\n }\n\n @if (host.pickedRunError(s.entry); as failure) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Error body \u00B7 run #{{ failure.run.index }} \u00B7 {{ failure.error.code || 'no status' }}\n </h5>\n </div>\n @for (message of failure.error.messages; track message) {\n <p class=\"et-query-devtools-count\">{{ message }}</p>\n }\n <et-query-devtools-json\n [value]=\"failure.error.body\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"runError\"\n />\n }\n\n @if (host.responseDiff(s.entry); as comparison) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Response diff \u00B7 run #{{ comparison.before.index }} \u2192 #{{ comparison.after.index }}\n </h5>\n <span class=\"et-query-devtools-diff-step\">\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, true)\"\n (click)=\"host.stepRunDiff(s.entry, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run older, without going back to the table\"\n >\n \u25C2 Older\n </button>\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, false)\"\n (click)=\"host.stepRunDiff(s.entry, false)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run newer, without going back to the table\"\n >\n Newer \u25B8\n </button>\n </span>\n <span class=\"et-query-devtools-count\">\n @if (host.diffBaseRunIndex() === null) {\n <span\n title=\"Nothing is picked to compare against, so this is the nearest older run that still holds a body - click another run's Diff to pick one\"\n >\n nearest older\n </span>\n \u00B7\n }\n @if (comparison.diff.entries.length) {\n {{ comparison.diff.entries.length }} path{{ comparison.diff.entries.length === 1 ? '' : 's' }}\n @if (comparison.diff.truncated) {\n (capped)\n }\n } @else {\n identical\n }\n </span>\n </div>\n @if (comparison.diff.entries.length) {\n <table class=\"et-query-devtools-table et-query-devtools-diff\">\n <thead>\n <tr>\n <th>Path</th>\n <th>Before</th>\n <th>After</th>\n </tr>\n </thead>\n <tbody>\n @for (change of comparison.diff.entries; track change.path) {\n <tr [attr.data-kind]=\"change.kind\">\n <td class=\"et-query-devtools-mono\">{{ change.path }}</td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-before\">\n {{ change.kind === 'added' ? '\u2014' : host.inlineValue(change.before) }}\n </td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-after\">\n {{ change.kind === 'removed' ? '\u2014' : host.inlineValue(change.after) }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"et-query-devtools-empty\">The two responses are identical.</p>\n }\n }\n } @else {\n <p class=\"et-query-devtools-empty\">No runs recorded yet.</p>\n }\n }\n @case ('data') {\n @if (s.entry.meta.gqlQuery; as gqlQuery) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">GraphQL document</h5>\n <button\n (click)=\"host.copyGqlDocument(gqlQuery)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy the GraphQL document\"\n >\n {{ host.copiedGql() ? '\u2713 Copied' : '\u29C9 Copy' }}\n </button>\n </div>\n <pre class=\"et-query-devtools-code\">{{ host.gqlDocument(gqlQuery) }}</pre>\n }\n\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Value explorer</h4>\n <input\n #jsonSearchInput\n [value]=\"host.jsonSearch()\"\n (input)=\"host.jsonSearch.set(jsonSearchInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter keys / values\u2026\"\n />\n </div>\n\n <h5 class=\"et-query-devtools-section\">Args</h5>\n <et-query-devtools-json\n [value]=\"host.queryArgs(s.query)\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"args\"\n />\n\n @if (requestHeaders(); as headers) {\n <h5\n class=\"et-query-devtools-section\"\n title=\"The headers the last run sent - or, for a query that has not run, the ones its args and its client resolve to now. Headers an HTTP interceptor adds are not visible here.\"\n >\n Request headers\n </h5>\n <et-query-devtools-json\n [value]=\"headers\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"requestHeaders\"\n />\n }\n\n @if (s.query.error(); as error) {\n <h5 class=\"et-query-devtools-section\">Error ({{ error.raw.status }})</h5>\n <et-query-devtools-json\n [value]=\"error.isList ? error.errors : error.error\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"error\"\n />\n } @else {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">Response</h5>\n @if (s.entry.overrides?.list()?.length || host.overridesPersist()) {\n <button\n [class.et-query-devtools-btn--active]=\"host.overridesPersist()\"\n [attr.aria-pressed]=\"host.overridesPersist()\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{\n host.overridesPersist()\n ? 'Panel-wide: every armed response override is kept in ' +\n host.overridesScopeLabel() +\n ' and replayed on the next load.'\n : 'Panel-wide: keep every armed response override and replay it on the next load.'\n }} Settings \u2699 chooses the scope. Armed faults are never kept.\"\n >\n Keep across reloads\n </button>\n }\n @if (s.entry.overrides?.list()?.length) {\n <button (click)=\"s.entry.overrides?.clearAll()\" class=\"et-query-devtools-btn\" type=\"button\">\n Reset all overrides ({{ s.entry.overrides?.list()?.length }})\n </button>\n }\n </div>\n <et-query-devtools-json\n [value]=\"s.query.response()\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n [overrides]=\"s.entry.overrides ?? null\"\n path=\"response\"\n />\n }\n }\n}\n", styles: ["@layer components{.et-query-devtools-detail .et-query-devtools-detail-head,.et-query-devtools-drawer .et-query-devtools-detail-head{padding-block-end:.8rem;border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-gone-note{margin:0 0 .8rem;color:var(--_et-qdt-muted);font-size:1.1rem}.et-query-devtools-detail-head{display:flex;align-items:center;gap:.8rem;margin-block-end:.8rem}.et-query-devtools-detail-head .et-query-devtools-route{flex:0 1 auto}.et-query-devtools-route-copy{appearance:none;margin-inline-end:auto;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:2.2rem;block-size:2.2rem;margin-inline-start:-.4rem;border:none;border-radius:.3rem;background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font:inherit;font-size:1.3rem;line-height:1}@media(hover:hover){.et-query-devtools-route-copy:hover:not(.et-query-devtools-route-copy--copied){background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-route-copy--copied{color:var(--_et-qdt-success)}.et-query-devtools-live{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-live-note{color:var(--_et-qdt-muted);font-size:1.15rem}.et-query-devtools-progress{display:block;flex:1 1 12rem;min-inline-size:8rem;max-inline-size:24rem;block-size:.5rem;border-radius:999px;overflow:hidden;background:var(--_et-qdt-border)}.et-query-devtools-progress-bar{display:block;block-size:100%;border-radius:inherit;background:var(--_et-qdt-accent)}.et-query-devtools-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-actions>.et-query-devtools-menu+.et-query-devtools-menu{margin-inline-start:.5rem;padding-inline-start:.9rem;border-inline-start:1px solid var(--_et-qdt-border)}.et-query-devtools-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.6rem;margin:0 0 1rem}.et-query-devtools-stat-value--sm{font-size:1.2rem}.et-query-devtools-code{margin:0 0 .8rem;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:.4rem;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow:auto;white-space:pre;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:1.15rem;max-block-size:20rem}.et-query-devtools-diff-step{display:flex;gap:.4rem;margin-inline-start:auto}.et-query-devtools-runs-fold{margin-block-start:.4rem;color:var(--_et-qdt-muted)}.et-query-devtools-textarea{inline-size:100%;min-block-size:12rem;resize:vertical;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);color:var(--_et-qdt-fg);border:1px solid var(--_et-qdt-border);border-radius:.4rem;padding:.6rem;font-family:inherit;font-size:1.2rem}.et-query-devtools-subtabs{display:flex;flex-wrap:wrap;gap:.2rem;border-block-end:1px solid var(--_et-qdt-border);margin-block:.8rem}.et-query-devtools-subtabs+.et-query-devtools-section-row{padding-block-start:0;border-block-start:0}.et-query-devtools-subtab{appearance:none;display:inline-flex;align-items:center;gap:.4rem;border:0;border-block-end:2px solid transparent;background:transparent;color:var(--_et-qdt-muted);font:inherit;font-size:1.15rem;padding:.4rem .6rem;margin-block-end:-1px;cursor:pointer}@media(hover:hover){.et-query-devtools-subtab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-subtab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-run-cell{display:inline-flex;align-items:center;gap:.5rem}.et-query-devtools-diff td{max-inline-size:28rem;overflow-wrap:anywhere}.et-query-devtools-diff-before{color:var(--_et-qdt-muted)}.et-query-devtools-diff tr[data-kind=removed] .et-query-devtools-diff-before{color:var(--_et-qdt-error)}.et-query-devtools-diff tr[data-kind=added] .et-query-devtools-diff-after{color:var(--_et-qdt-success)}.et-query-devtools-diff tr[data-kind=changed] .et-query-devtools-diff-after{color:var(--_et-qdt-accent)}}\n"], dependencies: [{ 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: 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: QueryDevtoolsFeaturesComponent, selector: "et-query-devtools-features", inputs: ["features"] }, { kind: "component", type: QueryDevtoolsJsonComponent, selector: "et-query-devtools-json", inputs: ["value", "nodeKey", "depth", "search", "chunk", "path", "expandedPaths", "collapsedPaths", "toggleFn", "jsonPath", "parentKind", "overrides", "annotations"] }, { kind: "component", type: QueryDevtoolsOverrideSetMenuComponent, selector: "et-query-devtools-override-set-menu", inputs: ["overrides", "response", "source"] }, { kind: "component", type: QueryDevtoolsRouteComponent, selector: "et-query-devtools-route", inputs: ["segments", "fallback", "trimPrefix"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1909
1915
|
}
|
|
1910
1916
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: QueryDevtoolsDetailComponent, decorators: [{
|
|
1911
1917
|
type: Component,
|
|
@@ -1920,7 +1926,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
1920
1926
|
QueryDevtoolsJsonComponent,
|
|
1921
1927
|
QueryDevtoolsOverrideSetMenuComponent,
|
|
1922
1928
|
QueryDevtoolsRouteComponent,
|
|
1923
|
-
], template: "@let s = sel();\n\n<div class=\"et-query-devtools-detail-head\">\n <span class=\"et-query-devtools-method\">{{ s.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(s.entry, s.query)\" />\n </span>\n <button\n [attr.aria-label]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [title]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [class.et-query-devtools-route-copy--copied]=\"host.copiedRoute()\"\n (click)=\"host.copyRoute(s.entry, s.query)\"\n class=\"et-query-devtools-route-copy\"\n type=\"button\"\n >\n {{ host.copiedRoute() ? '\u2713' : '\u29C9' }}\n </button>\n @if (host.isTampered(s.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 @if (isGone()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">gone</span>\n }\n</div>\n\n@if (s.entry.destroyedAt; as destroyedAt) {\n <p class=\"et-query-devtools-gone-note\">\n Destroyed at {{ host.formatTime(destroyedAt) }}. This is the last state the query held - nothing here updates, and\n it cannot be run again.\n </p>\n}\n\n@if (host.requestProgress(s.query); as live) {\n <div class=\"et-query-devtools-live\">\n @if (live.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"The retry policy is backing off before it tries again. A query stuck loading with this chip is waiting, not slow.\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n attempt {{ retry.attempt }} in {{ host.formatCountdown(live.retryInMs) }}\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.retryCause(retry.status) }} \u00B7 backing off {{ host.formatDuration(retry.delayMs) }}\n </span>\n } @else if (live.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"How many HTTP attempts the last execution took - the retry policy fired for the rest\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ live.attempts }} attempts\n </span>\n }\n\n @if (live.progress; as progress) {\n <span\n [attr.aria-valuenow]=\"progress.percentage\"\n class=\"et-query-devtools-progress\"\n role=\"progressbar\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=\"Transfer progress\"\n >\n <span [style.inline-size.%]=\"progress.percentage\" class=\"et-query-devtools-progress-bar\"></span>\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.formatPercent(progress.percentage) }} \u00B7 {{ host.formatBytes(progress.loaded) }} of\n {{ host.formatBytes(progress.total) }}\n @if (progress.speed !== null) {\n \u00B7 {{ host.formatSpeed(progress.speed) }}\n }\n @if (progress.remainingTime !== null) {\n \u00B7 {{ host.formatDuration(progress.remainingTime) }} left\n }\n </span>\n }\n </div>\n}\n\n<!-- One row, one primary action. Everything a query can be *made* to do lives behind Override, and\n everything that leaves the panel behind Copy - a flat row of all twelve read as a wall of equal\n buttons in which Execute was no easier to find than Clear. -->\n<div class=\"et-query-devtools-actions\">\n @if (!isGone()) {\n <div class=\"et-query-devtools-btn-group\">\n <button\n (click)=\"host.executeQuery(s, false)\"\n class=\"et-query-devtools-btn et-query-devtools-btn--primary\"\n type=\"button\"\n title=\"Run the query again, ignoring the cache\"\n >\n <span aria-hidden=\"true\">\u25B6</span>\n Execute\n </button>\n <button\n (click)=\"host.executeQuery(s, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Run it the way the app would - a fresh enough cached response is used instead of a request\"\n >\n Cached\n </button>\n <button\n (click)=\"host.resetQuery(s.query)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Drop this query's state back to idle\"\n >\n Reset\n </button>\n </div>\n }\n @let locatable = host.locatableElement(s.entry);\n <button\n [disabled]=\"!locatable\"\n [class.et-query-devtools-btn--active]=\"host.locateState() === 'located'\"\n [title]=\"\n locatable\n ? 'Scroll to and outline the element this query was created in. That is where it was created, not necessarily where its data is rendered.'\n : 'This query was created outside a component or directive - a root service, a resolver or a guard - so it has no element to point at.'\n \"\n (click)=\"host.locateQuery(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2316</span>\n @switch (host.locateState()) {\n @case ('located') {\n Created here\n }\n @case ('offscreen') {\n Not on screen\n }\n @default {\n Locate\n }\n }\n </button>\n\n <!-- The tick has to live on the trigger: the menu closes on the pick, so a confirmation inside it\n would be gone before it could be read. -->\n <div class=\"et-query-devtools-menu\" etMenu>\n <button class=\"et-query-devtools-btn\" title=\"Take this request somewhere else\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ copied() ? '\u2713' : '\u29C9' }}</span>\n {{ copied() ? 'Copied' : 'Copy' }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.copyReport(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy report\n <span class=\"et-query-devtools-menu-item-note\">Everything the panel knows, as markdown</span>\n </button>\n <button (activate)=\"host.copyCurlRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy as cURL\n <span class=\"et-query-devtools-menu-item-note\">URL, resolved headers and body</span>\n </button>\n <button (activate)=\"host.copyInsomniaRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy for Insomnia\n <span class=\"et-query-devtools-menu-item-note\">A collection to import from the clipboard</span>\n </button>\n </et-menu>\n </ng-template>\n </div>\n\n @if (!isGone()) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [class.et-query-devtools-btn--tampered]=\"host.isTampered(s.entry)\"\n class=\"et-query-devtools-btn\"\n title=\"Make this query answer with something other than what the API sent\"\n type=\"button\"\n etMenuTrigger\n >\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">\u270E</span>\n Override\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.openResponseEditor(s.query)\" et-menu-item type=\"button\">Edit response\u2026</button>\n <button (activate)=\"host.openArgsEditor(s)\" et-menu-item type=\"button\">Replay with edited args\u2026</button>\n <et-menu-separator />\n <button (activate)=\"host.forceLoading(s.query)\" et-menu-item type=\"button\">Force loading</button>\n <button (activate)=\"host.forceError(s.query)\" et-menu-item type=\"button\">Force error</button>\n <button (activate)=\"host.forceEmpty(s.query)\" et-menu-item type=\"button\">Force empty</button>\n <et-menu-separator />\n <button (activate)=\"host.clearForced(s.query)\" et-menu-item type=\"button\">Clear forced state</button>\n\n @if (s.entry.overrides; as overrides) {\n <et-menu-separator />\n <et-query-devtools-override-set-menu\n [overrides]=\"overrides\"\n [response]=\"s.query.response()\"\n [source]=\"overrideSetSource()\"\n />\n }\n </et-menu>\n </ng-template>\n </div>\n }\n</div>\n\n@if (!isGone() && host.editorMode() !== 'none') {\n <div class=\"et-query-devtools-editor\">\n @if (host.editorMode() === 'response') {\n <h4 class=\"et-query-devtools-section\">Edit response \u2192 setResponse()</h4>\n <textarea\n #respArea\n [value]=\"host.editorSeed\"\n (input)=\"host.responseDraft.set(respArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyResponse(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Apply</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <h4 class=\"et-query-devtools-section\">Replay with edited args \u2192 execute()</h4>\n <textarea\n #argsArea\n [value]=\"host.editorSeed\"\n (input)=\"host.argsDraft.set(argsArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyArgs(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Execute</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n }\n @if (host.editError(); as err) {\n <p class=\"et-query-devtools-editor-error\">{{ err }}</p>\n }\n </div>\n}\n\n@let detailRuns = host.queryRuns(s.entry);\n<nav class=\"et-query-devtools-subtabs\" role=\"tablist\">\n @for (tab of detailTabs; track tab.id) {\n <button\n [class.et-query-devtools-subtab--active]=\"host.detailTab() === tab.id\"\n [attr.aria-selected]=\"host.detailTab() === tab.id\"\n (click)=\"host.detailTab.set(tab.id)\"\n class=\"et-query-devtools-subtab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (tab.id === 'history' && detailRuns.length) {\n <span class=\"et-query-devtools-tab-badge\">{{ detailRuns.length }}</span>\n }\n <!-- The error body lives under Data, so the tab has to say so - a failure must not hide\n behind a tab that is not open. -->\n @if (tab.id === 'data' && s.query.error()) {\n <span class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\">!</span>\n }\n </button>\n }\n</nav>\n\n@switch (host.detailTab()) {\n @case ('overview') {\n <dl class=\"et-query-devtools-meta\">\n <dt>Base URL</dt>\n <dd class=\"et-query-devtools-mono\">\n {{ s.entry.meta.clientBaseUrl || s.entry.meta.clientName || '\u2014' }}\n </dd>\n <dt>Route</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.entry.meta.route || '\u2014' }}</dd>\n <dt>Request URL</dt>\n <dd class=\"et-query-devtools-mono\">{{ host.requestUrl(s.query) || '\u2014' }}</dd>\n <dt>Status</dt>\n <dd>{{ host.queryStatus(s.query) }}</dd>\n <dt>Cache key</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.query.id() || '\u2014' }}</dd>\n <dt>Last executed</dt>\n <dd>{{ host.formatTime(s.query.lastTimeExecutedAt()) }}</dd>\n <dt>Triggered by</dt>\n <dd>{{ s.query.triggeredBy() || 'user' }}</dd>\n @let refreshes = host.refreshesFor(s.entry.id);\n @if (refreshes.length) {\n <dt title=\"Invalidations and mutation refreshes that re-executed this query, as far back as the event log goes\">\n Refetched by\n </dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (refresh of refreshes.slice(0, 5); track refresh.id) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">\n {{ host.formatTime(refresh.timestamp) }} \u00B7 {{ refresh.label }}\n </span>\n }\n @if (refreshes.length > 5) {\n <span class=\"et-query-devtools-hint\">+{{ refreshes.length - 5 }} earlier</span>\n }\n </div>\n </dd>\n }\n @let drivers = host.formsDrivingQuery(s.entry);\n @if (drivers.length) {\n <dt>Args from</dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (driver of drivers; track driver.id) {\n <button\n (click)=\"host.selectForm(driver.id)\"\n class=\"et-query-devtools-chip et-query-devtools-chip--button\"\n type=\"button\"\n title=\"Open the query form in the Forms tab\"\n >\n {{ driver.meta.name }}\n </button>\n }\n </div>\n </dd>\n }\n @if (s.entry.meta.features?.length) {\n <dt>Features</dt>\n <dd>\n <et-query-devtools-features [features]=\"s.entry.meta.features ?? []\" />\n </dd>\n }\n </dl>\n\n @let activity = host.queryActivity(s.entry);\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Activity</h4>\n <button\n [disabled]=\"!activity.hasActivity\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the counters and the run history, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n\n <dl class=\"et-query-devtools-stats\">\n <div class=\"et-query-devtools-stat\" title=\"Every time the query ran, cache hits included\">\n <dt>Refreshes</dt>\n <dd>{{ activity.stats.executions }}</dd>\n @if (activity.cacheServed) {\n <span class=\"et-query-devtools-stat-sub\">{{ activity.cacheServed }} without a request</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\" title=\"Executions that started a request, and how they ended\">\n <dt>Requests</dt>\n <dd>{{ activity.stats.requests }}</dd>\n <span class=\"et-query-devtools-stat-sub\">\n {{ activity.stats.responses }} ok\n @if (activity.stats.errors) {\n \u00B7 {{ activity.stats.errors }} failed\n }\n </span>\n </div>\n <div\n class=\"et-query-devtools-stat\"\n title=\"Total response payload received. Sizes without a content-length header are measured from the decoded body, so they ignore compression.\"\n >\n <dt>Received</dt>\n <dd>{{ host.formatTransferred(activity.stats.receivedBytes, activity.stats.hasEstimatedBytes) }}</dd>\n @if (activity.avgResponseBytes !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatBytes(activity.avgResponseBytes) }} per response</span>\n }\n </div>\n @if (activity.stats.sentBytes) {\n <div class=\"et-query-devtools-stat\" title=\"Total request body sent (headers not counted)\">\n <dt>Sent</dt>\n <dd>{{ host.formatTransferred(activity.stats.sentBytes, activity.stats.hasEstimatedBytes) }}</dd>\n </div>\n }\n @if (activity.stats.retries) {\n <div\n class=\"et-query-devtools-stat\"\n title=\"Attempts the retry policy added on top of the first one. Which run they belong to is under History.\"\n >\n <dt>Retries</dt>\n <dd>{{ activity.stats.retries }}</dd>\n </div>\n }\n <div class=\"et-query-devtools-stat\" title=\"Measured from the execution that preceded each response\">\n <dt>Duration</dt>\n <dd>{{ host.formatDuration(activity.stats.lastDurationMs) }}</dd>\n @if (activity.avgDurationMs !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatDuration(activity.avgDurationMs) }} on average</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\">\n <dt>Last response</dt>\n <dd class=\"et-query-devtools-stat-value--sm\">{{ host.formatTime(activity.stats.lastResponseAt) }}</dd>\n @if (activity.stats.firstExecutedAt !== null) {\n <span class=\"et-query-devtools-stat-sub\"\n >first ran {{ host.formatTime(activity.stats.firstExecutedAt) }}</span\n >\n }\n </div>\n </dl>\n }\n @case ('history') {\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Runs</h4>\n <button\n [disabled]=\"!detailRuns.length\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the run history and the counters, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n @if (detailRuns.length) {\n <table class=\"et-query-devtools-table\">\n <thead>\n <tr>\n <th>Run</th>\n <th>Started</th>\n <th>Duration</th>\n <th>Received</th>\n <th>Body</th>\n </tr>\n </thead>\n <tbody>\n @for (run of runSections().listed.concat(foldedRunsOpen() ? runSections().folded : []); track run.index) {\n <tr [attr.data-status]=\"run.status === 'error' ? 'error' : null\">\n <td>\n <span class=\"et-query-devtools-run-cell\">\n <span\n [attr.data-status]=\"host.runStatus(run)\"\n [title]=\"run.status\"\n class=\"et-query-devtools-status\"\n ></span>\n #{{ run.index }}\n @if (run.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Took {{\n run.attempts\n }} attempts - the duration next to it covers every one of them, backoff included\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ run.attempts }}\n </span>\n }\n @if (!run.didRequest) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"Arrived without a request of this query's own - a poll, another consumer of the same cache entry, or another tab\"\n >\n shared\n </span>\n }\n @if (run.error; as error) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"{{ error.messages.join(' \u00B7 ') || 'The failure carried no message' }}\"\n >\n {{ error.code || 'failed' }}\n </span>\n }\n </span>\n </td>\n <td>{{ host.formatTime(run.startedAt) }}</td>\n <td>\n @if (run.endedAt === null) {\n in flight\n } @else {\n {{ host.formatDuration(run.endedAt - run.startedAt) }}\n }\n </td>\n <td>{{ run.receivedBytes ? host.formatBytes(run.receivedBytes) : '\u2014' }}</td>\n <td>\n <span class=\"et-query-devtools-cell-actions\">\n @if (host.canDiffRun(s.entry, run)) {\n @let role = host.diffRunRole(s.entry, run);\n @let armed = role ? diffRoles[role] : null;\n <button\n [class.et-query-devtools-btn--active]=\"!!armed\"\n [title]=\"\n armed?.title ?? 'Compare this response against another run - click a second row to pick which'\n \"\n (click)=\"host.toggleRunDiff(s.entry, run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ armed?.label ?? 'Diff' }}\n </button>\n } @else if (run.error?.hasBody) {\n <button\n [class.et-query-devtools-btn--active]=\"host.errorRunIndex() === run.index\"\n (click)=\"host.toggleRunError(run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Show the body this failure came with\"\n >\n Error\n </button>\n } @else if (run.hasResponse) {\n <span class=\"et-query-devtools-count\">the only body held</span>\n } @else if (run.status === 'success' || run.error) {\n <span\n class=\"et-query-devtools-count\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so this run can no longer be an end of a diff\"\n >\n body no longer held\n </span>\n } @else {\n <span class=\"et-query-devtools-count\">\u2014</span>\n }\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @let foldedRuns = runSections().folded.length;\n @if (foldedRuns) {\n <button\n [attr.aria-expanded]=\"foldedRunsOpen()\"\n (click)=\"foldedRunsOpen.set(!foldedRunsOpen())\"\n class=\"et-query-devtools-btn et-query-devtools-runs-fold\"\n type=\"button\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so none of these older runs can be an end of a diff\"\n >\n <span aria-hidden=\"true\">{{ foldedRunsOpen() ? '\u25BE' : '\u25B8' }}</span>\n {{ foldedRunsOpen() ? 'Hide' : 'Show' }} {{ foldedRuns }} older run{{ foldedRuns === 1 ? '' : 's' }} with no\n body\n </button>\n }\n\n @if (host.pickedRunError(s.entry); as failure) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Error body \u00B7 run #{{ failure.run.index }} \u00B7 {{ failure.error.code || 'no status' }}\n </h5>\n </div>\n @for (message of failure.error.messages; track message) {\n <p class=\"et-query-devtools-count\">{{ message }}</p>\n }\n <et-query-devtools-json\n [value]=\"failure.error.body\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"runError\"\n />\n }\n\n @if (host.responseDiff(s.entry); as comparison) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Response diff \u00B7 run #{{ comparison.before.index }} \u2192 #{{ comparison.after.index }}\n </h5>\n <span class=\"et-query-devtools-diff-step\">\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, true)\"\n (click)=\"host.stepRunDiff(s.entry, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run older, without going back to the table\"\n >\n \u25C2 Older\n </button>\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, false)\"\n (click)=\"host.stepRunDiff(s.entry, false)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run newer, without going back to the table\"\n >\n Newer \u25B8\n </button>\n </span>\n <span class=\"et-query-devtools-count\">\n @if (host.diffBaseRunIndex() === null) {\n <span\n title=\"Nothing is picked to compare against, so this is the nearest older run that still holds a body - click another run's Diff to pick one\"\n >\n nearest older\n </span>\n \u00B7\n }\n @if (comparison.diff.entries.length) {\n {{ comparison.diff.entries.length }} path{{ comparison.diff.entries.length === 1 ? '' : 's' }}\n @if (comparison.diff.truncated) {\n (capped)\n }\n } @else {\n identical\n }\n </span>\n </div>\n @if (comparison.diff.entries.length) {\n <table class=\"et-query-devtools-table et-query-devtools-diff\">\n <thead>\n <tr>\n <th>Path</th>\n <th>Before</th>\n <th>After</th>\n </tr>\n </thead>\n <tbody>\n @for (change of comparison.diff.entries; track change.path) {\n <tr [attr.data-kind]=\"change.kind\">\n <td class=\"et-query-devtools-mono\">{{ change.path }}</td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-before\">\n {{ change.kind === 'added' ? '\u2014' : host.inlineValue(change.before) }}\n </td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-after\">\n {{ change.kind === 'removed' ? '\u2014' : host.inlineValue(change.after) }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"et-query-devtools-empty\">The two responses are identical.</p>\n }\n }\n } @else {\n <p class=\"et-query-devtools-empty\">No runs recorded yet.</p>\n }\n }\n @case ('data') {\n @if (s.entry.meta.gqlQuery; as gqlQuery) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">GraphQL document</h5>\n <button\n (click)=\"host.copyGqlDocument(gqlQuery)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy the GraphQL document\"\n >\n {{ host.copiedGql() ? '\u2713 Copied' : '\u29C9 Copy' }}\n </button>\n </div>\n <pre class=\"et-query-devtools-code\">{{ host.gqlDocument(gqlQuery) }}</pre>\n }\n\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Value explorer</h4>\n <input\n #jsonSearchInput\n [value]=\"host.jsonSearch()\"\n (input)=\"host.jsonSearch.set(jsonSearchInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter keys / values\u2026\"\n />\n </div>\n\n <h5 class=\"et-query-devtools-section\">Args</h5>\n <et-query-devtools-json\n [value]=\"host.queryArgs(s.query)\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"args\"\n />\n\n @if (s.query.error(); as error) {\n <h5 class=\"et-query-devtools-section\">Error ({{ error.raw.status }})</h5>\n <et-query-devtools-json\n [value]=\"error.isList ? error.errors : error.error\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"error\"\n />\n } @else {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">Response</h5>\n @if (s.entry.overrides?.list()?.length || host.overridesPersist()) {\n <button\n [class.et-query-devtools-btn--active]=\"host.overridesPersist()\"\n [attr.aria-pressed]=\"host.overridesPersist()\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{\n host.overridesPersist()\n ? 'Panel-wide: every armed response override is kept in ' +\n host.overridesScopeLabel() +\n ' and replayed on the next load.'\n : 'Panel-wide: keep every armed response override and replay it on the next load.'\n }} Settings \u2699 chooses the scope. Armed faults are never kept.\"\n >\n Keep across reloads\n </button>\n }\n @if (s.entry.overrides?.list()?.length) {\n <button (click)=\"s.entry.overrides?.clearAll()\" class=\"et-query-devtools-btn\" type=\"button\">\n Reset all overrides ({{ s.entry.overrides?.list()?.length }})\n </button>\n }\n </div>\n <et-query-devtools-json\n [value]=\"s.query.response()\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n [overrides]=\"s.entry.overrides ?? null\"\n path=\"response\"\n />\n }\n }\n}\n", styles: ["@layer components{.et-query-devtools-detail .et-query-devtools-detail-head,.et-query-devtools-drawer .et-query-devtools-detail-head{padding-block-end:.8rem;border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-gone-note{margin:0 0 .8rem;color:var(--_et-qdt-muted);font-size:1.1rem}.et-query-devtools-detail-head{display:flex;align-items:center;gap:.8rem;margin-block-end:.8rem}.et-query-devtools-detail-head .et-query-devtools-route{flex:0 1 auto}.et-query-devtools-route-copy{appearance:none;margin-inline-end:auto;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:2.2rem;block-size:2.2rem;margin-inline-start:-.4rem;border:none;border-radius:.3rem;background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font:inherit;font-size:1.3rem;line-height:1}@media(hover:hover){.et-query-devtools-route-copy:hover:not(.et-query-devtools-route-copy--copied){background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-route-copy--copied{color:var(--_et-qdt-success)}.et-query-devtools-live{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-live-note{color:var(--_et-qdt-muted);font-size:1.15rem}.et-query-devtools-progress{display:block;flex:1 1 12rem;min-inline-size:8rem;max-inline-size:24rem;block-size:.5rem;border-radius:999px;overflow:hidden;background:var(--_et-qdt-border)}.et-query-devtools-progress-bar{display:block;block-size:100%;border-radius:inherit;background:var(--_et-qdt-accent)}.et-query-devtools-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-actions>.et-query-devtools-menu+.et-query-devtools-menu{margin-inline-start:.5rem;padding-inline-start:.9rem;border-inline-start:1px solid var(--_et-qdt-border)}.et-query-devtools-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.6rem;margin:0 0 1rem}.et-query-devtools-stat-value--sm{font-size:1.2rem}.et-query-devtools-code{margin:0 0 .8rem;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:.4rem;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow:auto;white-space:pre;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:1.15rem;max-block-size:20rem}.et-query-devtools-diff-step{display:flex;gap:.4rem;margin-inline-start:auto}.et-query-devtools-runs-fold{margin-block-start:.4rem;color:var(--_et-qdt-muted)}.et-query-devtools-textarea{inline-size:100%;min-block-size:12rem;resize:vertical;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);color:var(--_et-qdt-fg);border:1px solid var(--_et-qdt-border);border-radius:.4rem;padding:.6rem;font-family:inherit;font-size:1.2rem}.et-query-devtools-subtabs{display:flex;flex-wrap:wrap;gap:.2rem;border-block-end:1px solid var(--_et-qdt-border);margin-block:.8rem}.et-query-devtools-subtabs+.et-query-devtools-section-row{padding-block-start:0;border-block-start:0}.et-query-devtools-subtab{appearance:none;display:inline-flex;align-items:center;gap:.4rem;border:0;border-block-end:2px solid transparent;background:transparent;color:var(--_et-qdt-muted);font:inherit;font-size:1.15rem;padding:.4rem .6rem;margin-block-end:-1px;cursor:pointer}@media(hover:hover){.et-query-devtools-subtab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-subtab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-run-cell{display:inline-flex;align-items:center;gap:.5rem}.et-query-devtools-diff td{max-inline-size:28rem;overflow-wrap:anywhere}.et-query-devtools-diff-before{color:var(--_et-qdt-muted)}.et-query-devtools-diff tr[data-kind=removed] .et-query-devtools-diff-before{color:var(--_et-qdt-error)}.et-query-devtools-diff tr[data-kind=added] .et-query-devtools-diff-after{color:var(--_et-qdt-success)}.et-query-devtools-diff tr[data-kind=changed] .et-query-devtools-diff-after{color:var(--_et-qdt-accent)}}\n"] }]
|
|
1929
|
+
], template: "@let s = sel();\n\n<div class=\"et-query-devtools-detail-head\">\n <span class=\"et-query-devtools-method\">{{ s.entry.meta.method }}</span>\n <span class=\"et-query-devtools-route\">\n <et-query-devtools-route [segments]=\"host.routeSegments(s.entry, s.query)\" />\n </span>\n <button\n [attr.aria-label]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [title]=\"host.copyableRouteTitle(s.entry, s.query)\"\n [class.et-query-devtools-route-copy--copied]=\"host.copiedRoute()\"\n (click)=\"host.copyRoute(s.entry, s.query)\"\n class=\"et-query-devtools-route-copy\"\n type=\"button\"\n >\n {{ host.copiedRoute() ? '\u2713' : '\u29C9' }}\n </button>\n @if (host.isTampered(s.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 @if (isGone()) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">gone</span>\n }\n</div>\n\n@if (s.entry.destroyedAt; as destroyedAt) {\n <p class=\"et-query-devtools-gone-note\">\n Destroyed at {{ host.formatTime(destroyedAt) }}. This is the last state the query held - nothing here updates, and\n it cannot be run again.\n </p>\n}\n\n@if (host.requestProgress(s.query); as live) {\n <div class=\"et-query-devtools-live\">\n @if (live.retry; as retry) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"The retry policy is backing off before it tries again. A query stuck loading with this chip is waiting, not slow.\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n attempt {{ retry.attempt }} in {{ host.formatCountdown(live.retryInMs) }}\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.retryCause(retry.status) }} \u00B7 backing off {{ host.formatDuration(retry.delayMs) }}\n </span>\n } @else if (live.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"How many HTTP attempts the last execution took - the retry policy fired for the rest\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ live.attempts }} attempts\n </span>\n }\n\n @if (live.progress; as progress) {\n <span\n [attr.aria-valuenow]=\"progress.percentage\"\n class=\"et-query-devtools-progress\"\n role=\"progressbar\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=\"Transfer progress\"\n >\n <span [style.inline-size.%]=\"progress.percentage\" class=\"et-query-devtools-progress-bar\"></span>\n </span>\n <span class=\"et-query-devtools-live-note\">\n {{ host.formatPercent(progress.percentage) }} \u00B7 {{ host.formatBytes(progress.loaded) }} of\n {{ host.formatBytes(progress.total) }}\n @if (progress.speed !== null) {\n \u00B7 {{ host.formatSpeed(progress.speed) }}\n }\n @if (progress.remainingTime !== null) {\n \u00B7 {{ host.formatDuration(progress.remainingTime) }} left\n }\n </span>\n }\n </div>\n}\n\n<!-- One row, one primary action. Everything a query can be *made* to do lives behind Override, and\n everything that leaves the panel behind Copy - a flat row of all twelve read as a wall of equal\n buttons in which Execute was no easier to find than Clear. -->\n<div class=\"et-query-devtools-actions\">\n @if (!isGone()) {\n <div class=\"et-query-devtools-btn-group\">\n <button\n (click)=\"host.executeQuery(s, false)\"\n class=\"et-query-devtools-btn et-query-devtools-btn--primary\"\n type=\"button\"\n title=\"Run the query again, ignoring the cache\"\n >\n <span aria-hidden=\"true\">\u25B6</span>\n Execute\n </button>\n <button\n (click)=\"host.executeQuery(s, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Run it the way the app would - a fresh enough cached response is used instead of a request\"\n >\n Cached\n </button>\n <button\n (click)=\"host.resetQuery(s.query)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Drop this query's state back to idle\"\n >\n Reset\n </button>\n </div>\n }\n @let locatable = host.locatableElement(s.entry);\n <button\n [disabled]=\"!locatable\"\n [class.et-query-devtools-btn--active]=\"host.locateState() === 'located'\"\n [title]=\"\n locatable\n ? 'Scroll to and outline the element this query was created in. That is where it was created, not necessarily where its data is rendered.'\n : 'This query was created outside a component or directive - a root service, a resolver or a guard - so it has no element to point at.'\n \"\n (click)=\"host.locateQuery(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">\u2316</span>\n @switch (host.locateState()) {\n @case ('located') {\n Created here\n }\n @case ('offscreen') {\n Not on screen\n }\n @default {\n Locate\n }\n }\n </button>\n\n <!-- The tick has to live on the trigger: the menu closes on the pick, so a confirmation inside it\n would be gone before it could be read. -->\n <div class=\"et-query-devtools-menu\" etMenu>\n <button class=\"et-query-devtools-btn\" title=\"Take this request somewhere else\" type=\"button\" etMenuTrigger>\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">{{ copied() ? '\u2713' : '\u29C9' }}</span>\n {{ copied() ? 'Copied' : 'Copy' }}\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.copyReport(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy report\n <span class=\"et-query-devtools-menu-item-note\">Everything the panel knows, as markdown</span>\n </button>\n <button (activate)=\"host.copyCurlRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy as cURL\n <span class=\"et-query-devtools-menu-item-note\">URL, resolved headers and body</span>\n </button>\n <button (activate)=\"host.copyInsomniaRequest(s.entry, s.query)\" et-menu-item type=\"button\">\n Copy for Insomnia\n <span class=\"et-query-devtools-menu-item-note\">A collection to import from the clipboard</span>\n </button>\n </et-menu>\n </ng-template>\n </div>\n\n @if (!isGone()) {\n <div class=\"et-query-devtools-menu\" etMenu>\n <button\n [class.et-query-devtools-btn--tampered]=\"host.isTampered(s.entry)\"\n class=\"et-query-devtools-btn\"\n title=\"Make this query answer with something other than what the API sent\"\n type=\"button\"\n etMenuTrigger\n >\n <span class=\"et-query-devtools-menu-glyph\" aria-hidden=\"true\">\u270E</span>\n Override\n <span class=\"et-query-devtools-menu-caret\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n <ng-template etMenuSurface>\n <et-menu>\n <button (activate)=\"host.openResponseEditor(s.query)\" et-menu-item type=\"button\">Edit response\u2026</button>\n <button (activate)=\"host.openArgsEditor(s)\" et-menu-item type=\"button\">Replay with edited args\u2026</button>\n <et-menu-separator />\n <button (activate)=\"host.forceLoading(s.query)\" et-menu-item type=\"button\">Force loading</button>\n <button (activate)=\"host.forceError(s.query)\" et-menu-item type=\"button\">Force error</button>\n <button (activate)=\"host.forceEmpty(s.query)\" et-menu-item type=\"button\">Force empty</button>\n <et-menu-separator />\n <button (activate)=\"host.clearForced(s.query)\" et-menu-item type=\"button\">Clear forced state</button>\n\n @if (s.entry.overrides; as overrides) {\n <et-menu-separator />\n <et-query-devtools-override-set-menu\n [overrides]=\"overrides\"\n [response]=\"s.query.response()\"\n [source]=\"overrideSetSource()\"\n />\n }\n </et-menu>\n </ng-template>\n </div>\n }\n</div>\n\n@if (!isGone() && host.editorMode() !== 'none') {\n <div class=\"et-query-devtools-editor\">\n @if (host.editorMode() === 'response') {\n <h4 class=\"et-query-devtools-section\">Edit response \u2192 setResponse()</h4>\n <textarea\n #respArea\n [value]=\"host.editorSeed\"\n (input)=\"host.responseDraft.set(respArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyResponse(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Apply</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n } @else {\n <h4 class=\"et-query-devtools-section\">Replay with edited args \u2192 execute()</h4>\n <textarea\n #argsArea\n [value]=\"host.editorSeed\"\n (input)=\"host.argsDraft.set(argsArea.value)\"\n class=\"et-query-devtools-textarea\"\n spellcheck=\"false\"\n ></textarea>\n <div class=\"et-query-devtools-actions\">\n <button (click)=\"host.applyArgs(s.query)\" class=\"et-query-devtools-btn\" type=\"button\">Execute</button>\n <button (click)=\"host.cancelEditor()\" class=\"et-query-devtools-btn\" type=\"button\">Cancel</button>\n </div>\n }\n @if (host.editError(); as err) {\n <p class=\"et-query-devtools-editor-error\">{{ err }}</p>\n }\n </div>\n}\n\n@let detailRuns = host.queryRuns(s.entry);\n<nav class=\"et-query-devtools-subtabs\" role=\"tablist\">\n @for (tab of detailTabs; track tab.id) {\n <button\n [class.et-query-devtools-subtab--active]=\"host.detailTab() === tab.id\"\n [attr.aria-selected]=\"host.detailTab() === tab.id\"\n (click)=\"host.detailTab.set(tab.id)\"\n class=\"et-query-devtools-subtab\"\n type=\"button\"\n role=\"tab\"\n >\n {{ tab.label }}\n @if (tab.id === 'history' && detailRuns.length) {\n <span class=\"et-query-devtools-tab-badge\">{{ detailRuns.length }}</span>\n }\n <!-- The error body lives under Data, so the tab has to say so - a failure must not hide\n behind a tab that is not open. -->\n @if (tab.id === 'data' && s.query.error()) {\n <span class=\"et-query-devtools-tab-badge et-query-devtools-tab-badge--error\">!</span>\n }\n </button>\n }\n</nav>\n\n@switch (host.detailTab()) {\n @case ('overview') {\n <dl class=\"et-query-devtools-meta\">\n <dt>Base URL</dt>\n <dd class=\"et-query-devtools-mono\">\n {{ s.entry.meta.clientBaseUrl || s.entry.meta.clientName || '\u2014' }}\n </dd>\n <dt>Route</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.entry.meta.route || '\u2014' }}</dd>\n <dt>Request URL</dt>\n <dd class=\"et-query-devtools-mono\">{{ host.requestUrl(s.query) || '\u2014' }}</dd>\n <dt>Status</dt>\n <dd>{{ host.queryStatus(s.query) }}</dd>\n <dt>Cache key</dt>\n <dd class=\"et-query-devtools-mono\">{{ s.query.id() || '\u2014' }}</dd>\n <dt>Last executed</dt>\n <dd>{{ host.formatTime(s.query.lastTimeExecutedAt()) }}</dd>\n <dt>Triggered by</dt>\n <dd>{{ s.query.triggeredBy() || 'user' }}</dd>\n @let refreshes = host.refreshesFor(s.entry.id);\n @if (refreshes.length) {\n <dt title=\"Invalidations and mutation refreshes that re-executed this query, as far back as the event log goes\">\n Refetched by\n </dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (refresh of refreshes.slice(0, 5); track refresh.id) {\n <span class=\"et-query-devtools-chip et-query-devtools-chip--muted\">\n {{ host.formatTime(refresh.timestamp) }} \u00B7 {{ refresh.label }}\n </span>\n }\n @if (refreshes.length > 5) {\n <span class=\"et-query-devtools-hint\">+{{ refreshes.length - 5 }} earlier</span>\n }\n </div>\n </dd>\n }\n @let drivers = host.formsDrivingQuery(s.entry);\n @if (drivers.length) {\n <dt>Args from</dt>\n <dd>\n <div class=\"et-query-devtools-chips\">\n @for (driver of drivers; track driver.id) {\n <button\n (click)=\"host.selectForm(driver.id)\"\n class=\"et-query-devtools-chip et-query-devtools-chip--button\"\n type=\"button\"\n title=\"Open the query form in the Forms tab\"\n >\n {{ driver.meta.name }}\n </button>\n }\n </div>\n </dd>\n }\n @if (s.entry.meta.features?.length) {\n <dt>Features</dt>\n <dd>\n <et-query-devtools-features [features]=\"s.entry.meta.features ?? []\" />\n </dd>\n }\n </dl>\n\n @let activity = host.queryActivity(s.entry);\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Activity</h4>\n <button\n [disabled]=\"!activity.hasActivity\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the counters and the run history, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n\n <dl class=\"et-query-devtools-stats\">\n <div class=\"et-query-devtools-stat\" title=\"Every time the query ran, cache hits included\">\n <dt>Refreshes</dt>\n <dd>{{ activity.stats.executions }}</dd>\n @if (activity.cacheServed) {\n <span class=\"et-query-devtools-stat-sub\">{{ activity.cacheServed }} without a request</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\" title=\"Executions that started a request, and how they ended\">\n <dt>Requests</dt>\n <dd>{{ activity.stats.requests }}</dd>\n <span class=\"et-query-devtools-stat-sub\">\n {{ activity.stats.responses }} ok\n @if (activity.stats.errors) {\n \u00B7 {{ activity.stats.errors }} failed\n }\n </span>\n </div>\n <div\n class=\"et-query-devtools-stat\"\n title=\"Total response payload received. Sizes without a content-length header are measured from the decoded body, so they ignore compression.\"\n >\n <dt>Received</dt>\n <dd>{{ host.formatTransferred(activity.stats.receivedBytes, activity.stats.hasEstimatedBytes) }}</dd>\n @if (activity.avgResponseBytes !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatBytes(activity.avgResponseBytes) }} per response</span>\n }\n </div>\n @if (activity.stats.sentBytes) {\n <div class=\"et-query-devtools-stat\" title=\"Total request body sent (headers not counted)\">\n <dt>Sent</dt>\n <dd>{{ host.formatTransferred(activity.stats.sentBytes, activity.stats.hasEstimatedBytes) }}</dd>\n </div>\n }\n @if (activity.stats.retries) {\n <div\n class=\"et-query-devtools-stat\"\n title=\"Attempts the retry policy added on top of the first one. Which run they belong to is under History.\"\n >\n <dt>Retries</dt>\n <dd>{{ activity.stats.retries }}</dd>\n </div>\n }\n <div class=\"et-query-devtools-stat\" title=\"Measured from the execution that preceded each response\">\n <dt>Duration</dt>\n <dd>{{ host.formatDuration(activity.stats.lastDurationMs) }}</dd>\n @if (activity.avgDurationMs !== null) {\n <span class=\"et-query-devtools-stat-sub\">{{ host.formatDuration(activity.avgDurationMs) }} on average</span>\n }\n </div>\n <div class=\"et-query-devtools-stat\">\n <dt>Last response</dt>\n <dd class=\"et-query-devtools-stat-value--sm\">{{ host.formatTime(activity.stats.lastResponseAt) }}</dd>\n @if (activity.stats.firstExecutedAt !== null) {\n <span class=\"et-query-devtools-stat-sub\"\n >first ran {{ host.formatTime(activity.stats.firstExecutedAt) }}</span\n >\n }\n </div>\n </dl>\n }\n @case ('history') {\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Runs</h4>\n <button\n [disabled]=\"!detailRuns.length\"\n (click)=\"host.resetStats(s.entry)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Clear the run history and the counters, so the next interaction can be measured on its own\"\n >\n \u27F2 Reset\n </button>\n </div>\n @if (detailRuns.length) {\n <table class=\"et-query-devtools-table\">\n <thead>\n <tr>\n <th>Run</th>\n <th>Started</th>\n <th>Duration</th>\n <th>Received</th>\n <th>Body</th>\n </tr>\n </thead>\n <tbody>\n @for (run of runSections().listed.concat(foldedRunsOpen() ? runSections().folded : []); track run.index) {\n <tr [attr.data-status]=\"run.status === 'error' ? 'error' : null\">\n <td>\n <span class=\"et-query-devtools-run-cell\">\n <span\n [attr.data-status]=\"host.runStatus(run)\"\n [title]=\"run.status\"\n class=\"et-query-devtools-status\"\n ></span>\n #{{ run.index }}\n @if (run.attempts > 1) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--loading\"\n title=\"Took {{\n run.attempts\n }} attempts - the duration next to it covers every one of them, backoff included\"\n >\n <span class=\"et-query-devtools-retry-glyph\" aria-hidden=\"true\">\u27F3</span>\n {{ run.attempts }}\n </span>\n }\n @if (!run.didRequest) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--muted\"\n title=\"Arrived without a request of this query's own - a poll, another consumer of the same cache entry, or another tab\"\n >\n shared\n </span>\n }\n @if (run.error; as error) {\n <span\n class=\"et-query-devtools-chip et-query-devtools-chip--error\"\n title=\"{{ error.messages.join(' \u00B7 ') || 'The failure carried no message' }}\"\n >\n {{ error.code || 'failed' }}\n </span>\n }\n </span>\n </td>\n <td>{{ host.formatTime(run.startedAt) }}</td>\n <td>\n @if (run.endedAt === null) {\n in flight\n } @else {\n {{ host.formatDuration(run.endedAt - run.startedAt) }}\n }\n </td>\n <td>{{ run.receivedBytes ? host.formatBytes(run.receivedBytes) : '\u2014' }}</td>\n <td>\n <span class=\"et-query-devtools-cell-actions\">\n @if (host.canDiffRun(s.entry, run)) {\n @let role = host.diffRunRole(s.entry, run);\n @let armed = role ? diffRoles[role] : null;\n <button\n [class.et-query-devtools-btn--active]=\"!!armed\"\n [title]=\"\n armed?.title ?? 'Compare this response against another run - click a second row to pick which'\n \"\n (click)=\"host.toggleRunDiff(s.entry, run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n >\n {{ armed?.label ?? 'Diff' }}\n </button>\n } @else if (run.error?.hasBody) {\n <button\n [class.et-query-devtools-btn--active]=\"host.errorRunIndex() === run.index\"\n (click)=\"host.toggleRunError(run)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Show the body this failure came with\"\n >\n Error\n </button>\n } @else if (run.hasResponse) {\n <span class=\"et-query-devtools-count\">the only body held</span>\n } @else if (run.status === 'success' || run.error) {\n <span\n class=\"et-query-devtools-count\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so this run can no longer be an end of a diff\"\n >\n body no longer held\n </span>\n } @else {\n <span class=\"et-query-devtools-count\">\u2014</span>\n }\n </span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @let foldedRuns = runSections().folded.length;\n @if (foldedRuns) {\n <button\n [attr.aria-expanded]=\"foldedRunsOpen()\"\n (click)=\"foldedRunsOpen.set(!foldedRunsOpen())\"\n class=\"et-query-devtools-btn et-query-devtools-runs-fold\"\n type=\"button\"\n title=\"Only the newest {{\n host.retainedResponseCount()\n }} bodies of a query are kept, so none of these older runs can be an end of a diff\"\n >\n <span aria-hidden=\"true\">{{ foldedRunsOpen() ? '\u25BE' : '\u25B8' }}</span>\n {{ foldedRunsOpen() ? 'Hide' : 'Show' }} {{ foldedRuns }} older run{{ foldedRuns === 1 ? '' : 's' }} with no\n body\n </button>\n }\n\n @if (host.pickedRunError(s.entry); as failure) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Error body \u00B7 run #{{ failure.run.index }} \u00B7 {{ failure.error.code || 'no status' }}\n </h5>\n </div>\n @for (message of failure.error.messages; track message) {\n <p class=\"et-query-devtools-count\">{{ message }}</p>\n }\n <et-query-devtools-json\n [value]=\"failure.error.body\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"runError\"\n />\n }\n\n @if (host.responseDiff(s.entry); as comparison) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">\n Response diff \u00B7 run #{{ comparison.before.index }} \u2192 #{{ comparison.after.index }}\n </h5>\n <span class=\"et-query-devtools-diff-step\">\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, true)\"\n (click)=\"host.stepRunDiff(s.entry, true)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run older, without going back to the table\"\n >\n \u25C2 Older\n </button>\n <button\n [disabled]=\"!host.canStepRunDiff(s.entry, false)\"\n (click)=\"host.stepRunDiff(s.entry, false)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Compare the pair one run newer, without going back to the table\"\n >\n Newer \u25B8\n </button>\n </span>\n <span class=\"et-query-devtools-count\">\n @if (host.diffBaseRunIndex() === null) {\n <span\n title=\"Nothing is picked to compare against, so this is the nearest older run that still holds a body - click another run's Diff to pick one\"\n >\n nearest older\n </span>\n \u00B7\n }\n @if (comparison.diff.entries.length) {\n {{ comparison.diff.entries.length }} path{{ comparison.diff.entries.length === 1 ? '' : 's' }}\n @if (comparison.diff.truncated) {\n (capped)\n }\n } @else {\n identical\n }\n </span>\n </div>\n @if (comparison.diff.entries.length) {\n <table class=\"et-query-devtools-table et-query-devtools-diff\">\n <thead>\n <tr>\n <th>Path</th>\n <th>Before</th>\n <th>After</th>\n </tr>\n </thead>\n <tbody>\n @for (change of comparison.diff.entries; track change.path) {\n <tr [attr.data-kind]=\"change.kind\">\n <td class=\"et-query-devtools-mono\">{{ change.path }}</td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-before\">\n {{ change.kind === 'added' ? '\u2014' : host.inlineValue(change.before) }}\n </td>\n <td class=\"et-query-devtools-mono et-query-devtools-diff-after\">\n {{ change.kind === 'removed' ? '\u2014' : host.inlineValue(change.after) }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"et-query-devtools-empty\">The two responses are identical.</p>\n }\n }\n } @else {\n <p class=\"et-query-devtools-empty\">No runs recorded yet.</p>\n }\n }\n @case ('data') {\n @if (s.entry.meta.gqlQuery; as gqlQuery) {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">GraphQL document</h5>\n <button\n (click)=\"host.copyGqlDocument(gqlQuery)\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"Copy the GraphQL document\"\n >\n {{ host.copiedGql() ? '\u2713 Copied' : '\u29C9 Copy' }}\n </button>\n </div>\n <pre class=\"et-query-devtools-code\">{{ host.gqlDocument(gqlQuery) }}</pre>\n }\n\n <div class=\"et-query-devtools-section-row\">\n <h4 class=\"et-query-devtools-section\">Value explorer</h4>\n <input\n #jsonSearchInput\n [value]=\"host.jsonSearch()\"\n (input)=\"host.jsonSearch.set(jsonSearchInput.value)\"\n class=\"et-query-devtools-search\"\n type=\"search\"\n placeholder=\"filter keys / values\u2026\"\n />\n </div>\n\n <h5 class=\"et-query-devtools-section\">Args</h5>\n <et-query-devtools-json\n [value]=\"host.queryArgs(s.query)\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"args\"\n />\n\n @if (requestHeaders(); as headers) {\n <h5\n class=\"et-query-devtools-section\"\n title=\"The headers the last run sent - or, for a query that has not run, the ones its args and its client resolve to now. Headers an HTTP interceptor adds are not visible here.\"\n >\n Request headers\n </h5>\n <et-query-devtools-json\n [value]=\"headers\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"requestHeaders\"\n />\n }\n\n @if (s.query.error(); as error) {\n <h5 class=\"et-query-devtools-section\">Error ({{ error.raw.status }})</h5>\n <et-query-devtools-json\n [value]=\"error.isList ? error.errors : error.error\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n path=\"error\"\n />\n } @else {\n <div class=\"et-query-devtools-section-row\">\n <h5 class=\"et-query-devtools-section\">Response</h5>\n @if (s.entry.overrides?.list()?.length || host.overridesPersist()) {\n <button\n [class.et-query-devtools-btn--active]=\"host.overridesPersist()\"\n [attr.aria-pressed]=\"host.overridesPersist()\"\n (click)=\"host.toggleOverridesPersist()\"\n class=\"et-query-devtools-btn\"\n type=\"button\"\n title=\"{{\n host.overridesPersist()\n ? 'Panel-wide: every armed response override is kept in ' +\n host.overridesScopeLabel() +\n ' and replayed on the next load.'\n : 'Panel-wide: keep every armed response override and replay it on the next load.'\n }} Settings \u2699 chooses the scope. Armed faults are never kept.\"\n >\n Keep across reloads\n </button>\n }\n @if (s.entry.overrides?.list()?.length) {\n <button (click)=\"s.entry.overrides?.clearAll()\" class=\"et-query-devtools-btn\" type=\"button\">\n Reset all overrides ({{ s.entry.overrides?.list()?.length }})\n </button>\n }\n </div>\n <et-query-devtools-json\n [value]=\"s.query.response()\"\n [search]=\"host.jsonSearchTerm()\"\n [expandedPaths]=\"host.jsonExpandedPaths()\"\n [collapsedPaths]=\"host.jsonCollapsedPaths()\"\n [toggleFn]=\"host.toggleJsonPath\"\n [overrides]=\"s.entry.overrides ?? null\"\n path=\"response\"\n />\n }\n }\n}\n", styles: ["@layer components{.et-query-devtools-detail .et-query-devtools-detail-head,.et-query-devtools-drawer .et-query-devtools-detail-head{padding-block-end:.8rem;border-block-end:1px solid var(--_et-qdt-border)}.et-query-devtools-gone-note{margin:0 0 .8rem;color:var(--_et-qdt-muted);font-size:1.1rem}.et-query-devtools-detail-head{display:flex;align-items:center;gap:.8rem;margin-block-end:.8rem}.et-query-devtools-detail-head .et-query-devtools-route{flex:0 1 auto}.et-query-devtools-route-copy{appearance:none;margin-inline-end:auto;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:2.2rem;block-size:2.2rem;margin-inline-start:-.4rem;border:none;border-radius:.3rem;background:transparent;color:var(--_et-qdt-subtle);cursor:pointer;font:inherit;font-size:1.3rem;line-height:1}@media(hover:hover){.et-query-devtools-route-copy:hover:not(.et-query-devtools-route-copy--copied){background:var(--_et-qdt-active);color:var(--_et-qdt-fg)}}.et-query-devtools-route-copy--copied{color:var(--_et-qdt-success)}.et-query-devtools-live{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin-block-end:.8rem}.et-query-devtools-live-note{color:var(--_et-qdt-muted);font-size:1.15rem}.et-query-devtools-progress{display:block;flex:1 1 12rem;min-inline-size:8rem;max-inline-size:24rem;block-size:.5rem;border-radius:999px;overflow:hidden;background:var(--_et-qdt-border)}.et-query-devtools-progress-bar{display:block;block-size:100%;border-radius:inherit;background:var(--_et-qdt-accent)}.et-query-devtools-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-block-end:.8rem}.et-query-devtools-actions>.et-query-devtools-menu+.et-query-devtools-menu{margin-inline-start:.5rem;padding-inline-start:.9rem;border-inline-start:1px solid var(--_et-qdt-border)}.et-query-devtools-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.6rem;margin:0 0 1rem}.et-query-devtools-stat-value--sm{font-size:1.2rem}.et-query-devtools-code{margin:0 0 .8rem;padding:.8rem;border:1px solid var(--_et-qdt-border);border-radius:.4rem;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);overflow:auto;white-space:pre;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:1.15rem;max-block-size:20rem}.et-query-devtools-diff-step{display:flex;gap:.4rem;margin-inline-start:auto}.et-query-devtools-runs-fold{margin-block-start:.4rem;color:var(--_et-qdt-muted)}.et-query-devtools-textarea{inline-size:100%;min-block-size:12rem;resize:vertical;background:color-mix(in srgb,var(--_et-qdt-interaction) 4%,transparent);color:var(--_et-qdt-fg);border:1px solid var(--_et-qdt-border);border-radius:.4rem;padding:.6rem;font-family:inherit;font-size:1.2rem}.et-query-devtools-subtabs{display:flex;flex-wrap:wrap;gap:.2rem;border-block-end:1px solid var(--_et-qdt-border);margin-block:.8rem}.et-query-devtools-subtabs+.et-query-devtools-section-row{padding-block-start:0;border-block-start:0}.et-query-devtools-subtab{appearance:none;display:inline-flex;align-items:center;gap:.4rem;border:0;border-block-end:2px solid transparent;background:transparent;color:var(--_et-qdt-muted);font:inherit;font-size:1.15rem;padding:.4rem .6rem;margin-block-end:-1px;cursor:pointer}@media(hover:hover){.et-query-devtools-subtab:hover{color:var(--_et-qdt-fg)}}.et-query-devtools-subtab--active{color:var(--_et-qdt-fg);border-block-end-color:var(--_et-qdt-accent)}.et-query-devtools-run-cell{display:inline-flex;align-items:center;gap:.5rem}.et-query-devtools-diff td{max-inline-size:28rem;overflow-wrap:anywhere}.et-query-devtools-diff-before{color:var(--_et-qdt-muted)}.et-query-devtools-diff tr[data-kind=removed] .et-query-devtools-diff-before{color:var(--_et-qdt-error)}.et-query-devtools-diff tr[data-kind=added] .et-query-devtools-diff-after{color:var(--_et-qdt-success)}.et-query-devtools-diff tr[data-kind=changed] .et-query-devtools-diff-after{color:var(--_et-qdt-accent)}}\n"] }]
|
|
1924
1930
|
}], propDecorators: { sel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sel", required: true }] }] } });
|
|
1925
1931
|
|
|
1926
1932
|
/**
|
|
@@ -3239,7 +3245,7 @@ const summarizeLocks = (options) => {
|
|
|
3239
3245
|
|
|
3240
3246
|
// Generated from package.json by tools/scripts/generate-version.js - do not edit.
|
|
3241
3247
|
/** The version of `@ethlete/query-devtools` this build was cut from. */
|
|
3242
|
-
const QUERY_DEVTOOLS_VERSION = '1.0.0-next.
|
|
3248
|
+
const QUERY_DEVTOOLS_VERSION = '1.0.0-next.8';
|
|
3243
3249
|
|
|
3244
3250
|
/* eslint-disable @typescript-eslint/naming-convention -- the `__export_*` keys are Insomnia's file format */
|
|
3245
3251
|
const WORKSPACE_ID = 'wrk_ethlete_query_devtools';
|
|
@@ -4803,6 +4809,7 @@ class QueryDevtoolsComponent {
|
|
|
4803
4809
|
/** "Inspect" mode: hover the live UI to find the query that a component created. */
|
|
4804
4810
|
this.inspectActive = signal(false, /* @ts-ignore */
|
|
4805
4811
|
...(ngDevMode ? [{ debugName: "inspectActive" }] : /* istanbul ignore next */ []));
|
|
4812
|
+
/** @internal */
|
|
4806
4813
|
this.inspectHover = signal(null, /* @ts-ignore */
|
|
4807
4814
|
...(ngDevMode ? [{ debugName: "inspectHover" }] : /* istanbul ignore next */ []));
|
|
4808
4815
|
/** Inspect run backwards: the box drawn over the element the selected query was created in. */
|
|
@@ -5552,6 +5559,25 @@ class QueryDevtoolsComponent {
|
|
|
5552
5559
|
queryArgs(query) {
|
|
5553
5560
|
return query.args() ?? query.subtle.request()?.args ?? null;
|
|
5554
5561
|
}
|
|
5562
|
+
/**
|
|
5563
|
+
* The headers a query's request carries, as a plain `name: value` record, or `null` for a query that
|
|
5564
|
+
* has none the panel can read. The set the last run sent, so it stays readable after the token it
|
|
5565
|
+
* used was replaced; for a query that has not run, what its current args and its client resolve to
|
|
5566
|
+
* now. `null` while a header provider throws - a secure query's needs an access token.
|
|
5567
|
+
*
|
|
5568
|
+
* The args tree cannot answer this on its own: a `withArgs` query reads its args from the feature's
|
|
5569
|
+
* source, which the secure `Authorization` provider is never written back to, and client-level
|
|
5570
|
+
* headers are merged in per execution rather than being part of the args at all.
|
|
5571
|
+
*/
|
|
5572
|
+
requestHeaders(query) {
|
|
5573
|
+
const request = query.subtle.request();
|
|
5574
|
+
const args = this.queryArgs(query);
|
|
5575
|
+
const headers = request?.subtle.lastSentHeaders() ?? this.resolvedHeaders(request, args);
|
|
5576
|
+
if (!headers)
|
|
5577
|
+
return null;
|
|
5578
|
+
const entries = headerEntries(headers);
|
|
5579
|
+
return entries.length ? Object.fromEntries(entries.map(({ k, v }) => [k, v])) : null;
|
|
5580
|
+
}
|
|
5555
5581
|
queryStatus(query) {
|
|
5556
5582
|
const state = query.executionState();
|
|
5557
5583
|
if (!state)
|
|
@@ -6462,6 +6488,23 @@ class QueryDevtoolsComponent {
|
|
|
6462
6488
|
downloadTextFile(file) {
|
|
6463
6489
|
this.download({ content: file.content, filename: file.name, type: file.type });
|
|
6464
6490
|
}
|
|
6491
|
+
/**
|
|
6492
|
+
* The headers an execution of this request would resolve to now: the client's with the per-request
|
|
6493
|
+
* ones merged on top, providers called. `undefined` when a provider throws, which for a secure query
|
|
6494
|
+
* means no access token is available yet.
|
|
6495
|
+
*/
|
|
6496
|
+
resolvedHeaders(request, args) {
|
|
6497
|
+
try {
|
|
6498
|
+
if (request)
|
|
6499
|
+
return request.subtle.resolveHeaders();
|
|
6500
|
+
return typeof args?.headers === 'function'
|
|
6501
|
+
? args.headers()
|
|
6502
|
+
: args?.headers;
|
|
6503
|
+
}
|
|
6504
|
+
catch {
|
|
6505
|
+
return undefined;
|
|
6506
|
+
}
|
|
6507
|
+
}
|
|
6465
6508
|
/**
|
|
6466
6509
|
* The same route rendered from a set of args rather than from a query, which is what a batch item leaves
|
|
6467
6510
|
* behind: the batch destroys its query the moment the item settles.
|
|
@@ -6785,17 +6828,8 @@ class QueryDevtoolsComponent {
|
|
|
6785
6828
|
* (a secure query's needs an access token), in which case the request is exported without them.
|
|
6786
6829
|
*/
|
|
6787
6830
|
insomniaHeaders(request, args) {
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
? request.subtle.resolveHeaders()
|
|
6791
|
-
: typeof args?.headers === 'function'
|
|
6792
|
-
? args.headers()
|
|
6793
|
-
: args?.headers;
|
|
6794
|
-
return (headers?.keys() ?? []).map((name) => ({ name, value: headers?.getAll(name)?.join(', ') ?? '' }));
|
|
6795
|
-
}
|
|
6796
|
-
catch {
|
|
6797
|
-
return [];
|
|
6798
|
-
}
|
|
6831
|
+
const headers = this.resolvedHeaders(request, args);
|
|
6832
|
+
return headers ? headerEntries(headers).map(({ k, v }) => ({ name: k, value: v })) : [];
|
|
6799
6833
|
}
|
|
6800
6834
|
sessionClients() {
|
|
6801
6835
|
return this.cacheView().map((client) => ({
|