@reticlehq/browser 3.7.0 → 3.8.0
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/dist/actions/action-report.d.ts +10 -0
- package/dist/actions/action-report.js +29 -2
- package/dist/actions/actions-dom.d.ts +4 -0
- package/dist/actions/actions-dom.js +20 -4
- package/dist/actions/actions.d.ts +1 -0
- package/dist/actions/actions.js +35 -17
- package/dist/actions/appeared-text.js +2 -2
- package/dist/actions/click-target.d.ts +1 -0
- package/dist/actions/click-target.js +14 -0
- package/dist/actions/danger-context.d.ts +2 -1
- package/dist/actions/danger-context.js +20 -5
- package/dist/activate.d.ts +14 -0
- package/dist/activate.js +43 -0
- package/dist/busy.d.ts +3 -0
- package/dist/busy.js +42 -0
- package/dist/commands/commands.js +45 -17
- package/dist/connect-options.d.ts +12 -1
- package/dist/connect-options.js +18 -1
- package/dist/dom/a11y.d.ts +2 -0
- package/dist/dom/a11y.js +191 -159
- package/dist/dom/chart.d.ts +3 -2
- package/dist/dom/chart.js +3 -2
- package/dist/dom/dom-ignore.d.ts +6 -0
- package/dist/dom/dom-ignore.js +43 -1
- package/dist/dom/layout-audit.d.ts +15 -0
- package/dist/dom/layout-audit.js +208 -0
- package/dist/dom/paint-context.d.ts +15 -0
- package/dist/dom/paint-context.js +78 -0
- package/dist/dom/query.d.ts +2 -1
- package/dist/dom/query.js +97 -34
- package/dist/dom/shadow-registry.d.ts +1 -0
- package/dist/dom/shadow-registry.js +27 -0
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +85 -34
- package/dist/dom/stable-selector.d.ts +1 -0
- package/dist/dom/stable-selector.js +19 -0
- package/dist/dom/text-match.d.ts +12 -0
- package/dist/dom/text-match.js +115 -0
- package/dist/dom/theme.d.ts +1 -0
- package/dist/dom/theme.js +21 -9
- package/dist/dom/virtualized.js +5 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -0
- package/dist/observers/blind-spots.js +3 -2
- package/dist/observers/canvas.d.ts +18 -0
- package/dist/observers/canvas.js +76 -0
- package/dist/observers/dom.js +66 -18
- package/dist/observers/field.d.ts +11 -0
- package/dist/observers/field.js +117 -13
- package/dist/observers/install-all.js +4 -0
- package/dist/observers/media.d.ts +2 -0
- package/dist/observers/media.js +32 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +8 -1
- package/dist/observers/network.js +26 -6
- package/dist/observers/route.d.ts +2 -0
- package/dist/observers/route.js +33 -4
- package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -5
- package/dist/presenter/chrome/presenter-report-copy.js +0 -14
- package/dist/presenter/hud-telemetry.js +1 -1
- package/dist/presenter/presenter-chat-views.d.ts +3 -4
- package/dist/presenter/presenter-chat-views.js +47 -20
- package/dist/presenter/presenter-config.d.ts +1 -0
- package/dist/presenter/presenter-config.js +1 -0
- package/dist/presenter/presenter-frame.d.ts +3 -2
- package/dist/presenter/presenter-frame.js +24 -15
- package/dist/presenter/presenter-harness-row.d.ts +4 -15
- package/dist/presenter/presenter-harness-row.js +11 -50
- package/dist/presenter/presenter-report-styles.js +0 -17
- package/dist/presenter/presenter-report.d.ts +1 -2
- package/dist/presenter/presenter-report.js +4 -54
- package/dist/presenter/presenter-run-state.js +2 -1
- package/dist/presenter/presenter-settings.d.ts +2 -3
- package/dist/presenter/presenter-settings.js +14 -17
- package/dist/presenter/presenter-shell.d.ts +6 -4
- package/dist/presenter/presenter-shell.js +37 -7
- package/dist/presenter/presenter.js +32 -11
- package/dist/registry/store-adapters.d.ts +5 -2
- package/dist/registry/store-adapters.js +40 -10
- package/dist/reticle-inject.js +602 -611
- package/dist/reticle.d.ts +4 -2
- package/dist/reticle.js +36 -6
- package/dist/security/page-location.d.ts +2 -0
- package/dist/security/page-location.js +7 -0
- package/dist/security/serialization.js +1 -1
- package/dist/storage-keys.d.ts +1 -0
- package/dist/storage-keys.js +1 -0
- package/dist/timers/native/native-timers.d.ts +1 -0
- package/dist/timers/native/native-timers.js +5 -0
- package/dist/transport/transport.d.ts +1 -0
- package/dist/transport/transport.js +18 -0
- package/package.json +6 -2
|
@@ -4,7 +4,7 @@ import { HUD_SURFACE_CLASS } from './chrome/presenter-hud-chrome.js';
|
|
|
4
4
|
import { esc, isSafeDashboardUrl } from './chrome/presenter-safe-html.js';
|
|
5
5
|
import { ACCOUNT_SIGNIN_ATTR, ACCOUNT_TEXT, SYNC_BTN_ATTR, accountControlHtml, syncButtonHtml, } from './presenter-account.js';
|
|
6
6
|
import { REPORT_PANEL_ATTR, REPORT_ATTR, REPORT_CLOSE_ATTR } from './presenter-config.js';
|
|
7
|
-
import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS,
|
|
7
|
+
import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS, } from './chrome/presenter-report-copy.js';
|
|
8
8
|
const SCOPE_ATTR = 'data-reticle-report-scope';
|
|
9
9
|
const SCOPE = { PROJECT: 'project', MACHINE: 'machine' };
|
|
10
10
|
const SHARE_X_ATTR = 'data-reticle-share-x';
|
|
@@ -119,49 +119,6 @@ function syncStatusHtml(sync) {
|
|
|
119
119
|
: '';
|
|
120
120
|
return `<span class="reticle-sync-status" data-reticle-sync-status="${esc(String(status))}" title="${esc(said)}">${label}</span>${seeRun}`;
|
|
121
121
|
}
|
|
122
|
-
const capabilityWords = (name) => 'string' === typeof name ? esc(CAPABILITY_WORDS[name] ?? name) : undefined;
|
|
123
|
-
function capabilityItem(state, name, cost = '') {
|
|
124
|
-
const mark = 'seen' === state ? '✓' : 'missing' === state ? '✕' : '○';
|
|
125
|
-
const why = '' === cost ? '' : `<span class="reticle-report-cap-cost">${cost}</span>`;
|
|
126
|
-
return `<li class="reticle-report-cap" data-state="${state}"><span class="reticle-report-cap-mark" aria-hidden="true">${mark}</span><span class="reticle-report-cap-name">${name}</span>${why}</li>`;
|
|
127
|
-
}
|
|
128
|
-
export function instrumentationHtml(instrumentation) {
|
|
129
|
-
if (instrumentation === undefined)
|
|
130
|
-
return '';
|
|
131
|
-
const covered = instrumentation['covered'];
|
|
132
|
-
const total = instrumentation['total'];
|
|
133
|
-
if ('number' !== typeof covered || 'number' !== typeof total)
|
|
134
|
-
return '';
|
|
135
|
-
const list = (key) => {
|
|
136
|
-
const value = instrumentation[key];
|
|
137
|
-
return Array.isArray(value) ? value : [];
|
|
138
|
-
};
|
|
139
|
-
const seen = list('seen').flatMap((n) => {
|
|
140
|
-
const name = capabilityWords(n);
|
|
141
|
-
return name === undefined ? [] : [capabilityItem('seen', name)];
|
|
142
|
-
});
|
|
143
|
-
const missing = list('missing').flatMap((m) => {
|
|
144
|
-
if ('object' !== typeof m || null === m)
|
|
145
|
-
return [];
|
|
146
|
-
const gap = m;
|
|
147
|
-
const name = capabilityWords(gap['capability']);
|
|
148
|
-
const cost = 'string' === typeof gap['cost'] ? esc(gap['cost']) : '';
|
|
149
|
-
return name === undefined ? [] : [capabilityItem('missing', name, cost)];
|
|
150
|
-
});
|
|
151
|
-
const unseen = list('notSeenYet').flatMap((n) => {
|
|
152
|
-
const name = capabilityWords(n);
|
|
153
|
-
return name === undefined ? [] : [capabilityItem('unseen', name)];
|
|
154
|
-
});
|
|
155
|
-
const items = [...missing, ...seen, ...unseen];
|
|
156
|
-
const caps = 0 === items.length
|
|
157
|
-
? ''
|
|
158
|
-
: `<ul class="reticle-report-caps">${items.join('')}</ul>${0 === unseen.length ? '' : `<span class="reticle-report-caps-note">○ ${REPORT_TEXT.NOT_SEEN_YET}</span>`}`;
|
|
159
|
-
const copy = 'string' === typeof instrumentation['prompt']
|
|
160
|
-
? `<button type="button" class="reticle-report-copy-prompt" ${COPY_PROMPT_ATTR}>${REPORT_TEXT.COPY_PROMPT}</button>`
|
|
161
|
-
: '';
|
|
162
|
-
return `<div class="reticle-report-instrumentation" title="${REPORT_TEXT.INSTRUMENTATION_HELP}"><div class="reticle-report-instrumentation-head"><span class="reticle-report-section">${REPORT_TEXT.INSTRUMENTATION}</span><span class="reticle-report-instrumentation-value">${REPORT_TEXT.covered(Math.round(covered), Math.round(total))}</span></div>${caps}${copy}</div>`;
|
|
163
|
-
}
|
|
164
|
-
const COPY_PROMPT_ATTR = 'data-reticle-copy-prompt';
|
|
165
122
|
function coverageHtml(coverage) {
|
|
166
123
|
if (coverage === undefined)
|
|
167
124
|
return '';
|
|
@@ -175,7 +132,7 @@ function coverageHtml(coverage) {
|
|
|
175
132
|
.join('');
|
|
176
133
|
return `<div class="reticle-report-coverage" title="${REPORT_TEXT.COVERAGE_HELP}"><span class="reticle-report-section">${REPORT_TEXT.COVERAGE}</span><span class="reticle-report-coverage-value">${head}</span><div class="reticle-report-coverage-levels">${rows}</div></div>`;
|
|
177
134
|
}
|
|
178
|
-
export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync
|
|
135
|
+
export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync) {
|
|
179
136
|
const c = scope.counts;
|
|
180
137
|
if (0 === c.calls)
|
|
181
138
|
return `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`;
|
|
@@ -199,7 +156,7 @@ export function reportBodyHtml(scope, dashboardUrl, account, projectName, covera
|
|
|
199
156
|
card(compactDuration(scope.savings.minutes.value * 60_000), REPORT_TEXT.SAVED_MINUTES, scope.savings.minutes.basis),
|
|
200
157
|
].join('');
|
|
201
158
|
const identity = `<div class="reticle-report-identity">${accountControlHtml(account, { dashboardUrl, projectName, verdicts: c.verdicts, defects: c.failed })}${syncButtonHtml(dashboardUrl)}${syncStatusHtml(sync)}</div>`;
|
|
202
|
-
return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${
|
|
159
|
+
return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${coverageHtml(coverage)}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
|
|
203
160
|
}
|
|
204
161
|
function localOnly(scope, dashboardUrl, account) {
|
|
205
162
|
if (dashboardUrl !== undefined)
|
|
@@ -271,13 +228,6 @@ export class PresenterReport {
|
|
|
271
228
|
void this.#copy(ACCOUNT_TEXT.SIGNIN_COMMAND, signin);
|
|
272
229
|
return;
|
|
273
230
|
}
|
|
274
|
-
const copyPrompt = target.closest(`[${COPY_PROMPT_ATTR}]`);
|
|
275
|
-
const prompt = this.#snapshot?.instrumentation?.['prompt'];
|
|
276
|
-
if (copyPrompt !== null && 'string' === typeof prompt) {
|
|
277
|
-
e.stopPropagation();
|
|
278
|
-
void this.#copy(prompt, copyPrompt);
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
231
|
const sync = target.closest(`[${SYNC_BTN_ATTR}]`);
|
|
282
232
|
if (sync !== null) {
|
|
283
233
|
e.stopPropagation();
|
|
@@ -340,7 +290,7 @@ export class PresenterReport {
|
|
|
340
290
|
this.#body.innerHTML =
|
|
341
291
|
scope === undefined
|
|
342
292
|
? `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`
|
|
343
|
-
: reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync
|
|
293
|
+
: reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync);
|
|
344
294
|
}
|
|
345
295
|
#openShare(url) {
|
|
346
296
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SessionState } from '@reticlehq/core';
|
|
2
|
+
import { pageHref } from '../security/page-location.js';
|
|
2
3
|
import { LOG_KIND, LOG_RESULT } from './chrome/presenter-log.js';
|
|
3
4
|
import { getCapabilities } from '../registry/capabilities.js';
|
|
4
5
|
export function buildRunState(input) {
|
|
@@ -20,7 +21,7 @@ export function buildRunState(input) {
|
|
|
20
21
|
}
|
|
21
22
|
return {
|
|
22
23
|
session: input.sessionId,
|
|
23
|
-
url: 'undefined' === typeof location ? '' :
|
|
24
|
+
url: 'undefined' === typeof location ? '' : pageHref(),
|
|
24
25
|
state: input.state,
|
|
25
26
|
startedMs: start,
|
|
26
27
|
durationMs: Math.max(0, (input.endMs ?? input.now) - start),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { HarnessConfig } from '@reticlehq/core';
|
|
2
|
-
import type { HarnessGateView } from './presenter-harness-row.js';
|
|
3
2
|
import { SETTINGS_CSS } from './presenter-settings-styles.js';
|
|
4
3
|
import { type Credits } from '@reticlehq/core/hud';
|
|
5
4
|
import type { AccountState } from '@reticlehq/core';
|
|
@@ -45,7 +44,7 @@ export declare function loadPresenterSettings(): PresenterSettings;
|
|
|
45
44
|
export declare const SETTINGS_ACCOUNT_ATTR = "data-reticle-settings-account";
|
|
46
45
|
export declare const HARNESS_LOCKED_HELP = "The Harness is not available to this workspace right now: see Plan in your Reticle dashboard.";
|
|
47
46
|
export declare function creditsLeft(credits: Credits | undefined): string;
|
|
48
|
-
export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined
|
|
47
|
+
export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined): void;
|
|
49
48
|
export declare function paintSettingsAccount(root: HTMLElement, account: AccountState | undefined, dashboardUrl: string | undefined, details?: AccountDetails): void;
|
|
50
49
|
export declare function paintSdkVersion(root: ParentNode, version: string | undefined): void;
|
|
51
50
|
export declare function settingsPanelHtml(): string;
|
|
@@ -63,7 +62,7 @@ export declare class PresenterSettingsPanel {
|
|
|
63
62
|
constructor(host?: SettingsHost);
|
|
64
63
|
contains(node: Node): boolean;
|
|
65
64
|
mount(root: HTMLElement): void;
|
|
66
|
-
paintHarness(config: HarnessConfig | undefined
|
|
65
|
+
paintHarness(config: HarnessConfig | undefined): void;
|
|
67
66
|
teardown(): void;
|
|
68
67
|
isOpen(): boolean;
|
|
69
68
|
open(): void;
|
|
@@ -134,7 +134,10 @@ function settingsHelpIcon() {
|
|
|
134
134
|
}
|
|
135
135
|
const SETTING_TEXT = {
|
|
136
136
|
outputDetail: ['Output detail', 'How much a copied run includes.'],
|
|
137
|
-
autoOpenChat: [
|
|
137
|
+
autoOpenChat: [
|
|
138
|
+
'Open the log automatically',
|
|
139
|
+
'Opens this panel when an agent starts to act in this tab.',
|
|
140
|
+
],
|
|
138
141
|
showTimestamps: ['Show timestamps', 'Shows how long ago each log row happened.'],
|
|
139
142
|
showTally: ['Show pass/fail count', 'A score pill for this session in the toolbar.'],
|
|
140
143
|
reactComponents: ['React component names', 'Adds component names to copied runs.'],
|
|
@@ -144,10 +147,7 @@ const SETTING_TEXT = {
|
|
|
144
147
|
],
|
|
145
148
|
clearOnCopy: ['Clear notes after copying', 'Starts fresh once your notes are copied.'],
|
|
146
149
|
hideUntilRestart: ['Hide until reload', 'Hides the HUD until this page reloads.'],
|
|
147
|
-
harnessEnabled: [
|
|
148
|
-
'Allow Reticle to drive',
|
|
149
|
-
'Off by default. Unlocks at 80% instrumentation; lets Run Harness test this project.',
|
|
150
|
-
],
|
|
150
|
+
harnessEnabled: ['Allow Reticle to drive', 'Off by default. Lets Run Harness test this project.'],
|
|
151
151
|
reduceMotion: ['Reduce motion', 'Fewer HUD animations.'],
|
|
152
152
|
ambientGlow: ['Page glow', 'Tints the page edges while a session runs.'],
|
|
153
153
|
workspace: ['Workspace', 'The Reticle account this machine is signed in to.'],
|
|
@@ -184,7 +184,7 @@ export function creditsLeft(credits) {
|
|
|
184
184
|
return creditsSpent(credits) ? creditsUsedText(credits).said : creditsLeftText(credits);
|
|
185
185
|
}
|
|
186
186
|
const ACCOUNT_HELP = `Whether this machine is signed in to a Reticle workspace. Press ${ACCOUNT_TEXT.SIGNED_OUT} to sign in through your browser.`;
|
|
187
|
-
export function paintHarnessRow(root, config
|
|
187
|
+
export function paintHarnessRow(root, config) {
|
|
188
188
|
const row = root.querySelector(`[${SETTINGS_HARNESS_ROW_ATTR}]`);
|
|
189
189
|
if (!(row instanceof HTMLElement))
|
|
190
190
|
return;
|
|
@@ -196,20 +196,17 @@ export function paintHarnessRow(root, config, gate) {
|
|
|
196
196
|
const toggle = row.querySelector(`[${SETTING_KEY_ATTR}="harnessEnabled"]`);
|
|
197
197
|
if (!(toggle instanceof HTMLElement))
|
|
198
198
|
return;
|
|
199
|
-
const
|
|
200
|
-
const usable = config.harnessEntitled && locked === undefined;
|
|
199
|
+
const usable = config.harnessEntitled;
|
|
201
200
|
toggle.setAttribute('aria-checked', config.harnessEnabled && usable ? 'true' : 'false');
|
|
202
201
|
toggle.setAttribute('aria-disabled', usable ? 'false' : 'true');
|
|
203
202
|
const help = row.querySelector('[data-reticle-settings-help]');
|
|
204
203
|
const credits = creditsLeft(config.credits);
|
|
205
204
|
if (help instanceof HTMLElement)
|
|
206
|
-
help.title =
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
? credits
|
|
212
|
-
: HARNESS_LOCKED_HELP);
|
|
205
|
+
help.title = usable
|
|
206
|
+
? [HARNESS_HELP, credits].filter((t) => 0 < t.length).join(' ')
|
|
207
|
+
: creditsSpent(config.credits)
|
|
208
|
+
? credits
|
|
209
|
+
: HARNESS_LOCKED_HELP;
|
|
213
210
|
}
|
|
214
211
|
export function paintSettingsAccount(root, account, dashboardUrl, details = {}) {
|
|
215
212
|
const row = root.querySelector(`[${SETTINGS_ACCOUNT_ROW_ATTR}]`);
|
|
@@ -502,11 +499,11 @@ export class PresenterSettingsPanel {
|
|
|
502
499
|
applyPresenterSettings(root, activeSettings);
|
|
503
500
|
this.#host.onSettingsChange?.(activeSettings);
|
|
504
501
|
}
|
|
505
|
-
paintHarness(config
|
|
502
|
+
paintHarness(config) {
|
|
506
503
|
const root = this.#panel;
|
|
507
504
|
if (root === undefined)
|
|
508
505
|
return;
|
|
509
|
-
paintHarnessRow(root, config
|
|
506
|
+
paintHarnessRow(root, config);
|
|
510
507
|
}
|
|
511
508
|
teardown() {
|
|
512
509
|
this.#root = undefined;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { AgentLink, HarnessConfig, HarnessDrive } from '@reticlehq/core';
|
|
2
|
-
import type { HarnessGateView } from './presenter-harness-row.js';
|
|
1
|
+
import type { AgentLink, HarnessConfig, HarnessDrive, LastDrive } from '@reticlehq/core';
|
|
3
2
|
import { PresenterReport } from './presenter-report.js';
|
|
4
3
|
import type { AccountState } from '@reticlehq/core';
|
|
5
4
|
import { type AccountDetails } from './presenter-account.js';
|
|
@@ -23,9 +22,9 @@ interface HudShellCallbacks {
|
|
|
23
22
|
export declare class HudShell {
|
|
24
23
|
#private;
|
|
25
24
|
setProjectId(projectId: string | undefined): void;
|
|
26
|
-
paintHarnessDrive(drive: HarnessDrive | undefined): void;
|
|
25
|
+
paintHarnessDrive(drive: HarnessDrive | undefined, last?: LastDrive): void;
|
|
27
26
|
paintAgent(link: AgentLink | undefined): void;
|
|
28
|
-
paintHarness(config: HarnessConfig | undefined
|
|
27
|
+
paintHarness(config: HarnessConfig | undefined): void;
|
|
29
28
|
paintImpact(verdicts: number): void;
|
|
30
29
|
paintAnnotations(items: readonly AnnotationItem[]): void;
|
|
31
30
|
openView(view: ChatView): void;
|
|
@@ -50,5 +49,8 @@ export declare class HudShell {
|
|
|
50
49
|
}
|
|
51
50
|
export declare function wasMinimised(): boolean;
|
|
52
51
|
export declare function rememberMinimised(minimised: boolean): void;
|
|
52
|
+
export declare function wasLeftOpen(): boolean;
|
|
53
|
+
export declare function rememberLeftOpen(open: boolean): void;
|
|
54
|
+
export declare function shouldReopenPanel(): boolean;
|
|
53
55
|
export declare function shouldAutoOpenChat(autoOpenChat: boolean): boolean;
|
|
54
56
|
export {};
|
|
@@ -3,10 +3,10 @@ import { PresenterReport, reportPanelHtml } from './presenter-report.js';
|
|
|
3
3
|
import { paintToolbarAccount, TOOLBAR_ACCOUNT_ATTR } from './presenter-workspace.js';
|
|
4
4
|
import { mountAccountControl, TEAM_SLOT_ATTR } from './presenter-account.js';
|
|
5
5
|
import { paintSettingsAccount } from './presenter-settings.js';
|
|
6
|
-
import { CHAT_MIN_ATTR, CHAT_PILL_ATTR, REPORT_ATTR, ANNOTATE_BTN_ATTR, CHAT_ATTR, CHAT_TOGGLE_ATTR, CHAT_PANEL_ATTR, DOCK_ATTR, FAB_ATTR, MIN_ATTR, SETTINGS_ATTR, SETTINGS_BTN_ATTR, MINIMISED_STORAGE_KEY, } from './presenter-config.js';
|
|
6
|
+
import { CHAT_MIN_ATTR, CHAT_PILL_ATTR, REPORT_ATTR, ANNOTATE_BTN_ATTR, CHAT_ATTR, CHAT_TOGGLE_ATTR, CHAT_PANEL_ATTR, DOCK_ATTR, FAB_ATTR, MIN_ATTR, SETTINGS_ATTR, SETTINGS_BTN_ATTR, MINIMISED_STORAGE_KEY, OPEN_STORAGE_KEY, } from './presenter-config.js';
|
|
7
7
|
import { paintCarousel } from './carousel/carousel.js';
|
|
8
8
|
import { panelSlides } from './carousel/panel-slides.js';
|
|
9
|
-
import { paintRail, RAIL_HTML, RAIL_PROMO_ATTR } from './presenter-frame.js';
|
|
9
|
+
import { paintRail, RAIL_HTML, RAIL_PROMO_ATTR, RAIL_SIGNIN_HTML } from './presenter-frame.js';
|
|
10
10
|
import { FAB_TOGGLE_HTML, MARK_SVG } from './chrome/presenter-brand.js';
|
|
11
11
|
import { settleLogAtLatest } from './chrome/presenter-log.js';
|
|
12
12
|
import { installHudDragHandles, installHudPositionGuards } from './presenter-drag.js';
|
|
@@ -67,16 +67,16 @@ export class HudShell {
|
|
|
67
67
|
setProjectId(projectId) {
|
|
68
68
|
this.#chatViews.setProjectId(projectId);
|
|
69
69
|
}
|
|
70
|
-
paintHarnessDrive(drive) {
|
|
71
|
-
this.#chatViews.paintDrive(drive);
|
|
70
|
+
paintHarnessDrive(drive, last) {
|
|
71
|
+
this.#chatViews.paintDrive(drive, last);
|
|
72
72
|
}
|
|
73
73
|
paintAgent(link) {
|
|
74
74
|
this.#chatViews.paintAgent(link);
|
|
75
75
|
}
|
|
76
|
-
paintHarness(config
|
|
76
|
+
paintHarness(config) {
|
|
77
77
|
this.#pushedHarness = config;
|
|
78
|
-
this.#settings.paintHarness(config
|
|
79
|
-
this.#chatViews.paintHarness(config
|
|
78
|
+
this.#settings.paintHarness(config);
|
|
79
|
+
this.#chatViews.paintHarness(config);
|
|
80
80
|
this.#repaintPromoIfMoved();
|
|
81
81
|
}
|
|
82
82
|
#promoLinks() {
|
|
@@ -174,6 +174,7 @@ export class HudShell {
|
|
|
174
174
|
<div class="${HUD_LOG_WELL_CLASS}"><div ${logAttr}></div></div>
|
|
175
175
|
${flowsHtml}
|
|
176
176
|
</section>
|
|
177
|
+
${RAIL_SIGNIN_HTML}
|
|
177
178
|
${footHtml}
|
|
178
179
|
</div>
|
|
179
180
|
${FLOWS_PAGE_HTML}
|
|
@@ -270,12 +271,14 @@ export class HudShell {
|
|
|
270
271
|
pillEl?.addEventListener('click', (e) => {
|
|
271
272
|
e.preventDefault();
|
|
272
273
|
e.stopPropagation();
|
|
274
|
+
rememberLeftOpen(true);
|
|
273
275
|
this.showChat();
|
|
274
276
|
}, { signal });
|
|
275
277
|
const chatMinEl = root.querySelector(`[${CHAT_MIN_ATTR}]`);
|
|
276
278
|
chatMinEl?.addEventListener('click', (e) => {
|
|
277
279
|
e.preventDefault();
|
|
278
280
|
e.stopPropagation();
|
|
281
|
+
rememberLeftOpen(false);
|
|
279
282
|
this.closeChat();
|
|
280
283
|
}, { signal });
|
|
281
284
|
const collapseEl = root.querySelector('[data-reticle-min-btn]');
|
|
@@ -300,10 +303,12 @@ export class HudShell {
|
|
|
300
303
|
this.#suppressFabClick = false;
|
|
301
304
|
return;
|
|
302
305
|
}
|
|
306
|
+
rememberLeftOpen(true);
|
|
303
307
|
this.expand();
|
|
304
308
|
}, { signal });
|
|
305
309
|
this.#collapseBtn?.addEventListener('click', (e) => {
|
|
306
310
|
e.stopPropagation();
|
|
311
|
+
rememberLeftOpen(false);
|
|
307
312
|
this.collapse();
|
|
308
313
|
}, { signal });
|
|
309
314
|
const toolbarDrag = root.querySelector(`.${DRAG_HANDLE_CLASS}`);
|
|
@@ -455,6 +460,7 @@ export class HudShell {
|
|
|
455
460
|
return;
|
|
456
461
|
}
|
|
457
462
|
if (this.isChatOpen()) {
|
|
463
|
+
rememberLeftOpen(false);
|
|
458
464
|
this.closeChat();
|
|
459
465
|
return;
|
|
460
466
|
}
|
|
@@ -463,6 +469,7 @@ export class HudShell {
|
|
|
463
469
|
return;
|
|
464
470
|
}
|
|
465
471
|
if (!this.isCollapsed()) {
|
|
472
|
+
rememberLeftOpen(false);
|
|
466
473
|
this.collapse();
|
|
467
474
|
}
|
|
468
475
|
};
|
|
@@ -485,6 +492,29 @@ export function rememberMinimised(minimised) {
|
|
|
485
492
|
catch {
|
|
486
493
|
}
|
|
487
494
|
}
|
|
495
|
+
export function wasLeftOpen() {
|
|
496
|
+
try {
|
|
497
|
+
return '1' === globalThis.localStorage.getItem(OPEN_STORAGE_KEY);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
export function rememberLeftOpen(open) {
|
|
504
|
+
try {
|
|
505
|
+
if (open) {
|
|
506
|
+
globalThis.localStorage.setItem(OPEN_STORAGE_KEY, '1');
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
globalThis.localStorage.removeItem(OPEN_STORAGE_KEY);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
export function shouldReopenPanel() {
|
|
516
|
+
return wasLeftOpen() && !wasMinimised();
|
|
517
|
+
}
|
|
488
518
|
export function shouldAutoOpenChat(autoOpenChat) {
|
|
489
519
|
return autoOpenChat && !wasMinimised();
|
|
490
520
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionType, HudCorner, HudVisibility, HumanControlKind, ReticleCommand, PresenterMode, SessionState, isPresenterTone, isSessionState, } from '@reticlehq/core';
|
|
1
|
+
import { ActionType, HudCorner, HudVisibility, HUD_RELOAD_TO_RESTORE, HumanControlKind, ReticleCommand, PresenterMode, SessionState, isPresenterTone, isSessionState, } from '@reticlehq/core';
|
|
2
2
|
import { refs } from '../dom/addressing/refs.js';
|
|
3
3
|
import { UNREACHABLE_HEADLINE, unreachableMessage } from '../transport/unreachable-message.js';
|
|
4
4
|
import { actionVerb } from './chrome/presenter-verbs.js';
|
|
@@ -6,7 +6,7 @@ import { nativeSetTimeout, nativeClearTimeout, nativeNow } from '../timers/nativ
|
|
|
6
6
|
import { LOG_KIND, CHIP_LABEL, LOG_ACTOR, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, clearLogRows, trimLogRows, } from './chrome/presenter-log.js';
|
|
7
7
|
import { PRESENTER_CSS } from './presenter-styles.js';
|
|
8
8
|
import { HudShell } from './presenter-shell.js';
|
|
9
|
-
import { HARNESS_LOG_ATTR
|
|
9
|
+
import { HARNESS_LOG_ATTR } from './presenter-harness-row.js';
|
|
10
10
|
import { platformDetails } from './presenter-account.js';
|
|
11
11
|
import { parseImpactSnapshot } from './chrome/presenter-report-copy.js';
|
|
12
12
|
import { scheduleSyncDockLayout } from './presenter-dock-layout.js';
|
|
@@ -20,7 +20,7 @@ import { renderTally } from './chrome/presenter-tally.js';
|
|
|
20
20
|
import { CONTROLS_BANNER_HTML, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML, CONTROLS_STATUS_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
|
|
21
21
|
import { statusTheme, blockerHtml, getPresenterSettings, OutputDetail, syncPageBlocker, paintSdkVersion, } from './presenter-settings.js';
|
|
22
22
|
import { Annotator } from '../review/annotator.js';
|
|
23
|
-
import { shouldAutoOpenChat } from './presenter-shell.js';
|
|
23
|
+
import { shouldAutoOpenChat, shouldReopenPanel } from './presenter-shell.js';
|
|
24
24
|
import { installHudTelemetry } from './hud-telemetry.js';
|
|
25
25
|
import { PlanBoard, parsePlanView } from './presenter-plan.js';
|
|
26
26
|
import { claimLog, readRememberedLog, rememberLog, } from './chrome/log-memory.js';
|
|
@@ -56,6 +56,7 @@ export class Presenter {
|
|
|
56
56
|
#endMs;
|
|
57
57
|
#runLog = [];
|
|
58
58
|
#sessionActive = false;
|
|
59
|
+
#agentOpened = false;
|
|
59
60
|
#logMax;
|
|
60
61
|
#log;
|
|
61
62
|
#harnessLog;
|
|
@@ -70,6 +71,7 @@ export class Presenter {
|
|
|
70
71
|
#panel;
|
|
71
72
|
#shell;
|
|
72
73
|
#annotator;
|
|
74
|
+
#removed = false;
|
|
73
75
|
constructor(options = {}) {
|
|
74
76
|
this.#paceMs = effectivePaceMs(options.paceMs);
|
|
75
77
|
this.#now = options.now ?? nativeNow;
|
|
@@ -161,8 +163,8 @@ export class Presenter {
|
|
|
161
163
|
if (snapshot !== undefined) {
|
|
162
164
|
this.#shell.report.setSnapshot(snapshot);
|
|
163
165
|
this.#shell.paintNotices(snapshot.notices);
|
|
164
|
-
this.#shell.paintHarness(snapshot.harnessConfig
|
|
165
|
-
this.#shell.paintHarnessDrive(snapshot.harnessDrive);
|
|
166
|
+
this.#shell.paintHarness(snapshot.harnessConfig);
|
|
167
|
+
this.#shell.paintHarnessDrive(snapshot.harnessDrive, snapshot.lastDrive);
|
|
166
168
|
this.#paintHarnessRun(snapshot.harnessDrive);
|
|
167
169
|
this.#shell.paintAgent(snapshot.agent);
|
|
168
170
|
this.#shell.paintImpact(snapshot.project.counts.verdicts);
|
|
@@ -201,7 +203,7 @@ export class Presenter {
|
|
|
201
203
|
document.head.appendChild(style);
|
|
202
204
|
const root = document.createElement('div');
|
|
203
205
|
root.setAttribute('data-reticle-overlay', '');
|
|
204
|
-
const actStrip = `<div class="reticle-act-strip" data-liveness="idle"><span class="reticle-act-dot" aria-hidden="true"></span><span class="reticle-act">${ACT_STRIP.READY}</span>${CONTROLS_BANNER_HTML}<span class="reticle-chip" data-reticle-chip></span><div class="reticle-act-actions">${CONTROLS_STATUS_HTML}</div></div>`;
|
|
206
|
+
const actStrip = `<div class="reticle-act-strip" data-liveness="idle"><span class="reticle-act-dot" aria-hidden="true"></span><span class="reticle-act" data-reticle-act-line>${ACT_STRIP.READY}</span>${CONTROLS_BANNER_HTML}<span class="reticle-chip" data-reticle-chip></span><div class="reticle-act-actions">${CONTROLS_STATUS_HTML}</div></div>`;
|
|
205
207
|
root.innerHTML = `
|
|
206
208
|
${blockerHtml()}
|
|
207
209
|
<div data-reticle-glow></div>
|
|
@@ -340,7 +342,7 @@ export class Presenter {
|
|
|
340
342
|
this.#showSession();
|
|
341
343
|
this.#glowCtl.resetActivity(this.#now());
|
|
342
344
|
this.#startHeartbeat();
|
|
343
|
-
if (
|
|
345
|
+
if (shouldReopenPanel()) {
|
|
344
346
|
this.#shell.openChat();
|
|
345
347
|
}
|
|
346
348
|
}
|
|
@@ -354,8 +356,9 @@ export class Presenter {
|
|
|
354
356
|
this.#lastActionText = UNREACHABLE_HEADLINE;
|
|
355
357
|
this.#paintActStrip(this.#lastActionText, true);
|
|
356
358
|
this.#actLine?.setAttribute('title', unreachableMessage(url, attempts));
|
|
357
|
-
if (
|
|
359
|
+
if (shouldReopenPanel()) {
|
|
358
360
|
this.#shell.openChat();
|
|
361
|
+
}
|
|
359
362
|
}
|
|
360
363
|
#showSession() {
|
|
361
364
|
const dock = this.#root?.querySelector('[data-reticle-dock]');
|
|
@@ -432,11 +435,15 @@ export class Presenter {
|
|
|
432
435
|
this.#paintActStrip(text, false);
|
|
433
436
|
}
|
|
434
437
|
#paintHarnessRun(drive) {
|
|
438
|
+
const log = this.#harnessLog;
|
|
435
439
|
if (drive !== undefined && drive.runId !== this.#harnessRunId) {
|
|
436
440
|
this.#harnessRunId = drive.runId;
|
|
437
|
-
if (
|
|
438
|
-
clearLogRows(
|
|
441
|
+
if (log !== undefined)
|
|
442
|
+
clearLogRows(log);
|
|
439
443
|
}
|
|
444
|
+
if (log !== undefined && 0 === log.childElementCount)
|
|
445
|
+
for (const line of drive?.lines ?? [])
|
|
446
|
+
appendLogRow(log, LOG_KIND.NARRATION, line, '', this.#logMax, LOG_ACTOR.HARNESS);
|
|
440
447
|
const was = this.#harnessSteps;
|
|
441
448
|
this.#harnessSteps = drive?.steps;
|
|
442
449
|
if (drive !== undefined)
|
|
@@ -507,10 +514,14 @@ export class Presenter {
|
|
|
507
514
|
}
|
|
508
515
|
placeHud(visibility, corner) {
|
|
509
516
|
const root = this.#root;
|
|
510
|
-
if (root === undefined)
|
|
517
|
+
if (root === undefined) {
|
|
518
|
+
if (this.#removed)
|
|
519
|
+
return [HUD_RELOAD_TO_RESTORE];
|
|
511
520
|
return [];
|
|
521
|
+
}
|
|
512
522
|
const applied = [];
|
|
513
523
|
if (HudVisibility.REMOVED === visibility) {
|
|
524
|
+
this.#removed = true;
|
|
514
525
|
this.destroy();
|
|
515
526
|
return [visibility];
|
|
516
527
|
}
|
|
@@ -632,6 +643,7 @@ export class Presenter {
|
|
|
632
643
|
while (this.#remembered.length > this.#logMax)
|
|
633
644
|
this.#remembered.shift();
|
|
634
645
|
rememberLog(this.#remembered);
|
|
646
|
+
this.#openForAgent(kind);
|
|
635
647
|
if (this.#shell.isCollapsed())
|
|
636
648
|
this.#shell.pulseFab(true);
|
|
637
649
|
this.#renderTally();
|
|
@@ -645,6 +657,15 @@ export class Presenter {
|
|
|
645
657
|
},
|
|
646
658
|
};
|
|
647
659
|
}
|
|
660
|
+
#openForAgent(kind) {
|
|
661
|
+
if (this.#agentOpened || LOG_KIND.HUMAN === kind) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
this.#agentOpened = true;
|
|
665
|
+
if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat)) {
|
|
666
|
+
this.#shell.openChat();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
648
669
|
#renderTally() {
|
|
649
670
|
if (!getPresenterSettings().showTally) {
|
|
650
671
|
this.#tally?.setAttribute('hidden', '');
|
|
@@ -9,6 +9,7 @@ interface QueryLike {
|
|
|
9
9
|
message?: string;
|
|
10
10
|
} | null;
|
|
11
11
|
data?: unknown;
|
|
12
|
+
isInvalidated?: boolean;
|
|
12
13
|
};
|
|
13
14
|
isStale?: () => boolean;
|
|
14
15
|
}
|
|
@@ -23,16 +24,18 @@ export interface QuerySnapshot {
|
|
|
23
24
|
status: string;
|
|
24
25
|
fetchStatus: string | undefined;
|
|
25
26
|
isStale: boolean | undefined;
|
|
27
|
+
isInvalidated: boolean | undefined;
|
|
26
28
|
dataUpdatedAt: number | undefined;
|
|
27
29
|
error: string | null;
|
|
28
30
|
data: unknown;
|
|
29
31
|
}
|
|
30
32
|
export declare function tanstackQueryStore(client: QueryClientLike): StoreLike;
|
|
33
|
+
type Deferred<T> = [T][T extends unknown ? 0 : never];
|
|
31
34
|
interface JotaiStoreLike<A> {
|
|
32
35
|
get: (atom: A) => unknown;
|
|
33
36
|
sub: (atom: A, listener: () => void) => () => void;
|
|
34
37
|
}
|
|
35
|
-
export declare function jotaiStore<A>(store: JotaiStoreLike<A>, atoms: Record<string, A
|
|
38
|
+
export declare function jotaiStore<A>(store: JotaiStoreLike<A>, atoms: Record<string, Deferred<A>>): StoreLike;
|
|
36
39
|
interface ActorLike {
|
|
37
40
|
getSnapshot: () => unknown;
|
|
38
41
|
subscribe: (listener: () => void) => {
|
|
@@ -54,7 +57,7 @@ export interface RecoilAtomSnapshot {
|
|
|
54
57
|
value: unknown;
|
|
55
58
|
error: string | null;
|
|
56
59
|
}
|
|
57
|
-
export declare function recoilStore<A>(atoms: Record<string, A
|
|
60
|
+
export declare function recoilStore<A>(atoms: Record<string, Deferred<A>>, snapshot: () => RecoilSnapshotLike<A>, subscribe: StoreSubscribe): StoreLike;
|
|
58
61
|
interface SvelteReadable {
|
|
59
62
|
subscribe: (run: (value: unknown) => void) => (() => void) | {
|
|
60
63
|
unsubscribe: () => void;
|
|
@@ -9,37 +9,63 @@ function snapshotLive(value) {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
function copyPlain(value, seen) {
|
|
12
|
-
if ('object' !== typeof value || null === value)
|
|
12
|
+
if ('object' !== typeof value || null === value) {
|
|
13
13
|
return value;
|
|
14
|
+
}
|
|
14
15
|
const done = seen.get(value);
|
|
15
|
-
if (done !== undefined)
|
|
16
|
+
if (done !== undefined) {
|
|
16
17
|
return done;
|
|
18
|
+
}
|
|
17
19
|
if (Array.isArray(value)) {
|
|
18
20
|
const out = [];
|
|
19
21
|
seen.set(value, out);
|
|
20
|
-
for (const item of value)
|
|
22
|
+
for (const item of value) {
|
|
21
23
|
out.push(copyPlain(item, seen));
|
|
24
|
+
}
|
|
22
25
|
return out;
|
|
23
26
|
}
|
|
24
27
|
const proto = Object.getPrototypeOf(value);
|
|
25
|
-
if (proto !== Object.prototype && proto !== null)
|
|
28
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
26
29
|
return value;
|
|
30
|
+
}
|
|
27
31
|
const out = {};
|
|
28
32
|
seen.set(value, out);
|
|
29
|
-
for (const [key, item] of Object.entries(value))
|
|
33
|
+
for (const [key, item] of Object.entries(value)) {
|
|
30
34
|
out[key] = copyPlain(item, seen);
|
|
35
|
+
}
|
|
31
36
|
return out;
|
|
32
37
|
}
|
|
38
|
+
function queryKeyPart(part) {
|
|
39
|
+
if ('object' !== typeof part || null === part) {
|
|
40
|
+
return String(part);
|
|
41
|
+
}
|
|
42
|
+
return JSON.stringify(part, (_key, value) => {
|
|
43
|
+
if ('object' !== typeof value || null === value || Array.isArray(value)) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
const proto = Object.getPrototypeOf(value);
|
|
47
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
const plain = value;
|
|
51
|
+
const sorted = {};
|
|
52
|
+
for (const key of Object.keys(plain).sort()) {
|
|
53
|
+
sorted[key] = plain[key];
|
|
54
|
+
}
|
|
55
|
+
return sorted;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
33
58
|
export function tanstackQueryStore(client) {
|
|
34
59
|
const store = {
|
|
35
60
|
getState: () => {
|
|
36
61
|
const out = {};
|
|
37
62
|
for (const query of client.getQueryCache().getAll()) {
|
|
38
|
-
const key = query.queryKey.map(
|
|
63
|
+
const key = query.queryKey.map(queryKeyPart).join('/');
|
|
39
64
|
out[key] = {
|
|
40
65
|
status: query.state.status,
|
|
41
66
|
fetchStatus: query.state.fetchStatus,
|
|
42
67
|
isStale: query.isStale?.(),
|
|
68
|
+
isInvalidated: query.state.isInvalidated,
|
|
43
69
|
dataUpdatedAt: query.state.dataUpdatedAt,
|
|
44
70
|
error: query.state.error?.message ?? null,
|
|
45
71
|
data: query.state.data,
|
|
@@ -56,15 +82,17 @@ export function jotaiStore(store, atoms) {
|
|
|
56
82
|
return {
|
|
57
83
|
getState: () => {
|
|
58
84
|
const out = {};
|
|
59
|
-
for (const [name, atom] of Object.entries(atoms))
|
|
85
|
+
for (const [name, atom] of Object.entries(atoms)) {
|
|
60
86
|
out[name] = store.get(atom);
|
|
87
|
+
}
|
|
61
88
|
return out;
|
|
62
89
|
},
|
|
63
90
|
subscribe: (listener) => {
|
|
64
91
|
const unsubs = Object.values(atoms).map((atom) => store.sub(atom, listener));
|
|
65
92
|
return () => {
|
|
66
|
-
for (const unsub of unsubs)
|
|
93
|
+
for (const unsub of unsubs) {
|
|
67
94
|
unsub();
|
|
95
|
+
}
|
|
68
96
|
};
|
|
69
97
|
},
|
|
70
98
|
};
|
|
@@ -151,8 +179,9 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
151
179
|
subscribe: (listener) => {
|
|
152
180
|
let inSubscribeCall = true;
|
|
153
181
|
const handle = readable.subscribe(() => {
|
|
154
|
-
if (!inSubscribeCall)
|
|
182
|
+
if (!inSubscribeCall) {
|
|
155
183
|
listener();
|
|
184
|
+
}
|
|
156
185
|
});
|
|
157
186
|
inSubscribeCall = false;
|
|
158
187
|
return () => stopSubscription(handle);
|
|
@@ -177,8 +206,9 @@ export function pushStore(initial) {
|
|
|
177
206
|
store: { getState: () => current, subscribe },
|
|
178
207
|
push: (value) => {
|
|
179
208
|
current = value;
|
|
180
|
-
for (const listener of listeners)
|
|
209
|
+
for (const listener of listeners) {
|
|
181
210
|
listener();
|
|
211
|
+
}
|
|
182
212
|
},
|
|
183
213
|
};
|
|
184
214
|
}
|