From 8742f53d007a821ef2a37a323dd6a9c1a2a659e5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 18 Feb 2026 00:12:06 -0500 Subject: [PATCH 1/4] wip --- .../Toolbar/V2/useInspectGuideClientStore.ts | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts index c85f15596..60333cefa 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts +++ b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts @@ -198,13 +198,38 @@ const inferSelectOneByTypeReturnStatus = ( const inferSelectAllByTypeReturnStatus = ( _guide: KnockGuide, - _snapshot: StoreStateSnapshot, + snapshot: StoreStateSnapshot, _stage: KnockGuideClientGroupStage, - _query: SelectionResultByQuery, + query: SelectionResultByQuery, ): SelectableStatusPresent["status"] => { - // If queried with useGuides/selectGuides (i.e. can return multiple guides), - // then we need to look up the actual query results to figure out how this - // guide may or may not be included in the result. + const result = query.type!.all!; + if (result.size === 0) { + // This should not happen but here for completeness. + return "queried"; + } + + // If queried with useGuides (i.e. can return multiple guides), then we need + // to look up the actual query results to figure out how this guide may or + // may not be included in the result. + + // If explicitly given the option to ignore throttling, then all guides + // selected in this query should return. + const includeThrottled = !!query.type?.one?.metadata?.opts?.includeThrottled; + if (includeThrottled) { + return "returned"; + } + + const guides = [...result.values()] + const first = guides[0]!; + + // If not throttled, then all guides in the query result should be returned. + if (!snapshot.throttled) { + return "returned" + } + + // If being throttled, then all guides in the query result should be returned. + // const guides = [...result.values()]; + // TODO: Placeholder to follow up. return "returned"; @@ -247,6 +272,7 @@ const toSelectableStatus = ( type: (stage.results.type || {})[guide.type], }; + // There is no query in the current location that can select this guide. const queried = Boolean(query.key || query.type); if (!queried) { // No present query in the current location can select this guide. From 018fdba305dbbe7e738b4e545b404165b8de354e Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 18 Feb 2026 01:30:50 -0500 Subject: [PATCH 2/4] implement inferSelectAllByTypeReturnStatus --- .../Toolbar/V2/useInspectGuideClientStore.ts | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts index 60333cefa..8befb1c40 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts +++ b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts @@ -197,42 +197,30 @@ const inferSelectOneByTypeReturnStatus = ( }; const inferSelectAllByTypeReturnStatus = ( - _guide: KnockGuide, + guide: KnockGuide, snapshot: StoreStateSnapshot, - _stage: KnockGuideClientGroupStage, + stage: KnockGuideClientGroupStage, query: SelectionResultByQuery, ): SelectableStatusPresent["status"] => { const result = query.type!.all!; if (result.size === 0) { - // This should not happen but here for completeness. return "queried"; } - // If queried with useGuides (i.e. can return multiple guides), then we need - // to look up the actual query results to figure out how this guide may or - // may not be included in the result. - - // If explicitly given the option to ignore throttling, then all guides - // selected in this query should return. - const includeThrottled = !!query.type?.one?.metadata?.opts?.includeThrottled; - if (includeThrottled) { - return "returned"; - } - - const guides = [...result.values()] + const guides = [...result.values()]; const first = guides[0]!; - // If not throttled, then all guides in the query result should be returned. - if (!snapshot.throttled) { - return "returned" + // If the first selected guide is unthrottled or resolved, then we should + // have at minimum one guide to return, and potentially more based on whether + // we are throttling currently and which other guides are unthrottled. + if (first.bypass_global_group_limit || first.key === stage.resolved) { + if (snapshot.throttled) { + return guide.bypass_global_group_limit ? "returned" : "throttled"; + } + return "returned"; } - // If being throttled, then all guides in the query result should be returned. - // const guides = [...result.values()]; - - - // TODO: Placeholder to follow up. - return "returned"; + return "queried"; }; const inferSelectReturnStatus = ( From 61379653df4086b8a51fb95d5551f056bec7a884 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 18 Feb 2026 14:38:55 -0500 Subject: [PATCH 3/4] clean up --- .../guide/components/Toolbar/V2/useInspectGuideClientStore.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts index 8befb1c40..2736606f5 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts +++ b/packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts @@ -260,7 +260,6 @@ const toSelectableStatus = ( type: (stage.results.type || {})[guide.type], }; - // There is no query in the current location that can select this guide. const queried = Boolean(query.key || query.type); if (!queried) { // No present query in the current location can select this guide. From d539f63fa190a2b5d0549595a8ca4a3272f637af Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 18 Feb 2026 14:52:21 -0500 Subject: [PATCH 4/4] add tests --- .../V2/useInspectGuideClientStore.test.ts | 209 +++++++++++++++++- 1 file changed, 207 insertions(+), 2 deletions(-) diff --git a/packages/react/test/guide/Toolbar/V2/useInspectGuideClientStore.test.ts b/packages/react/test/guide/Toolbar/V2/useInspectGuideClientStore.test.ts index c78ba59d0..4dc9f92de 100644 --- a/packages/react/test/guide/Toolbar/V2/useInspectGuideClientStore.test.ts +++ b/packages/react/test/guide/Toolbar/V2/useInspectGuideClientStore.test.ts @@ -659,7 +659,7 @@ describe("useInspectGuideClientStore", () => { expect(annotated.annotation.selectable.status).toBe("queried"); }); - test("selectable is 'returned' when queried by type (selectAll)", () => { + test("selectable is 'returned' when queried by type (selectAll) and guide is resolved", () => { const guide = makeGuide({ key: "g1", type: "banner" }); mockGroupStage = { status: "closed", @@ -681,10 +681,215 @@ describe("useInspectGuideClientStore", () => { const result = renderInspect()!; const annotated = result.guides[0] as AnnotatedGuide; - // selectAll placeholder always returns "returned" expect(annotated.annotation.selectable.status).toBe("returned"); }); + test("selectAll: returns 'queried' when result is empty", () => { + const guide = makeGuide({ key: "g1", type: "banner" }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "g1", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("queried"); + }); + + test("selectAll: returns 'returned' when first guide is unthrottled and not throttling", () => { + const guide = makeGuide({ key: "g1", type: "banner" }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "other", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([ + [0, { key: "g1", bypass_global_group_limit: true }], + ]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("returned"); + }); + + test("selectAll: returns 'returned' when throttled but guide bypasses group limit", () => { + mockCheckStateIfThrottled.mockReturnValue(true); + const guide = makeGuide({ + key: "g1", + type: "banner", + bypass_global_group_limit: true, + }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "g1", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([[0, { key: "g1" }]]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("returned"); + }); + + test("selectAll: returns 'throttled' when throttled and guide does not bypass group limit", () => { + mockCheckStateIfThrottled.mockReturnValue(true); + const guide = makeGuide({ + key: "g1", + type: "banner", + bypass_global_group_limit: false, + }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "g1", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([[0, { key: "g1" }]]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("throttled"); + }); + + test("selectAll: returns 'throttled' when first guide is unthrottled, throttled, and current guide is throttled", () => { + mockCheckStateIfThrottled.mockReturnValue(true); + const guide = makeGuide({ + key: "g1", + type: "banner", + bypass_global_group_limit: false, + }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "other", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([ + [0, { key: "first", bypass_global_group_limit: true }], + [1, { key: "g1", bypass_global_group_limit: false }], + ]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("throttled"); + }); + + test("selectAll: returns 'returned' when first guide is unthrottled, throttled, and current guide bypasses group limit", () => { + mockCheckStateIfThrottled.mockReturnValue(true); + const guide = makeGuide({ + key: "g1", + type: "banner", + bypass_global_group_limit: true, + }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "other", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([ + [0, { key: "first", bypass_global_group_limit: true }], + [1, { key: "g1", bypass_global_group_limit: true }], + ]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("returned"); + }); + + test("selectAll: returns 'queried' when first guide is neither resolved nor unthrottled", () => { + const guide = makeGuide({ key: "g1", type: "banner" }); + mockGroupStage = { + status: "closed", + ordered: ["g1"], + resolved: "other", + timeoutId: null, + results: { + type: { + banner: { + all: makeSelectionResult([ + [0, { key: "first", bypass_global_group_limit: false }], + [1, { key: "g1" }], + ]), + }, + }, + }, + }; + setSnapshot({ + guideGroups: [makeGuideGroup(["g1"])], + guides: { g1: guide }, + }); + + const result = renderInspect()!; + const annotated = result.guides[0] as AnnotatedGuide; + expect(annotated.annotation.selectable.status).toBe("queried"); + }); + test("key-based query takes precedence over type-based query", () => { const guide = makeGuide({ key: "g1", type: "banner" }); // Stage has both key and type results, key should take precedence