From b4a6a547b8776cab25852da26d6dde2160073e05 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 24 Feb 2026 19:42:56 -0500 Subject: [PATCH 1/5] add ignoreDisplayInterval debug setting --- packages/client/src/clients/guide/client.ts | 1 + packages/client/src/clients/guide/helpers.ts | 4 + packages/client/src/clients/guide/types.ts | 1 + .../client/test/clients/guide/guide.test.ts | 93 +++++++++++++++++++ .../Toolbar/V2/GuideContextDetails.tsx | 25 +++++ 5 files changed, 124 insertions(+) diff --git a/packages/client/src/clients/guide/client.ts b/packages/client/src/clients/guide/client.ts index 16566604e..25aad07cf 100644 --- a/packages/client/src/clients/guide/client.ts +++ b/packages/client/src/clients/guide/client.ts @@ -590,6 +590,7 @@ export class KnockGuideClient { ...state, debug: { skipEngagementTracking: true, + ignoreDisplayInterval: true, ...debugOpts, debugging: true, }, diff --git a/packages/client/src/clients/guide/helpers.ts b/packages/client/src/clients/guide/helpers.ts index 63294f218..7e163dcd2 100644 --- a/packages/client/src/clients/guide/helpers.ts +++ b/packages/client/src/clients/guide/helpers.ts @@ -64,6 +64,10 @@ export const findDefaultGroup = (guideGroups: GuideGroupData[]) => ); export const checkStateIfThrottled = (state: StoreState) => { + if (state.debug?.ignoreDisplayInterval) { + return false; + } + const defaultGroup = findDefaultGroup(state.guideGroups); const throttleWindowStartedAt = state.guideGroupDisplayLogs[DEFAULT_GROUP_KEY]; diff --git a/packages/client/src/clients/guide/types.ts b/packages/client/src/clients/guide/types.ts index 725871ce4..9e09efb93 100644 --- a/packages/client/src/clients/guide/types.ts +++ b/packages/client/src/clients/guide/types.ts @@ -234,6 +234,7 @@ export type DebugState = { forcedGuideKey?: string | null; previewSessionId?: string | null; skipEngagementTracking?: boolean; + ignoreDisplayInterval?: boolean; }; export type StoreState = { diff --git a/packages/client/test/clients/guide/guide.test.ts b/packages/client/test/clients/guide/guide.test.ts index 8c0f15134..4bae5b050 100644 --- a/packages/client/test/clients/guide/guide.test.ts +++ b/packages/client/test/clients/guide/guide.test.ts @@ -2363,6 +2363,71 @@ describe("KnockGuideClient", () => { expect(result2!.type).toBe("banner"); }); + test("returns a guide inside a throttle window when ignoreDisplayInterval is true", () => { + const stateWithGuides = { + guideGroups: [ + { + ...mockDefaultGroup, + display_interval: 5 * 60, // 5 minutes + }, + ], + guideGroupDisplayLogs: { + default: new Date().toISOString(), + }, + guides: mockGuides, + ineligibleGuides: {}, + previewGuides: {}, + queries: {}, + location: undefined, + counter: 0, + debug: { + debugging: true, + ignoreDisplayInterval: true, + forcedGuideKey: null, + previewSessionId: null, + }, + }; + + const client = new KnockGuideClient(mockKnock, channelId); + const result = client["_selectGuide"](stateWithGuides); + + // Even though we are inside the configured throttle window, + // ignoreDisplayInterval bypasses it. + expect(result).toBeDefined(); + expect(result!.key).toBe("feature_tour"); + }); + + test("does not return a guide inside a throttle window when ignoreDisplayInterval is false", () => { + const stateWithGuides = { + guideGroups: [ + { + ...mockDefaultGroup, + display_interval: 5 * 60, // 5 minutes + }, + ], + guideGroupDisplayLogs: { + default: new Date().toISOString(), + }, + guides: mockGuides, + ineligibleGuides: {}, + previewGuides: {}, + queries: {}, + location: undefined, + counter: 0, + debug: { + debugging: true, + ignoreDisplayInterval: false, + forcedGuideKey: null, + previewSessionId: null, + }, + }; + + const client = new KnockGuideClient(mockKnock, channelId); + const result = client["_selectGuide"](stateWithGuides); + + expect(result).toBeUndefined(); + }); + test("skips ineligible guides during selection", () => { const stateWithGuides = { guideGroups: [mockDefaultGroup], @@ -4234,6 +4299,34 @@ describe("KnockGuideClient", () => { expect(client.store.state.debug!.skipEngagementTracking).toBe(false); }); + + test("defaults ignoreDisplayInterval to true", () => { + const client = new KnockGuideClient(mockKnock, channelId); + client.store.state.debug = undefined; + + vi.spyOn(client, "fetch").mockImplementation(() => + Promise.resolve({ status: "ok" }), + ); + vi.spyOn(client, "subscribe").mockImplementation(() => {}); + + client.setDebug(); + + expect(client.store.state.debug!.ignoreDisplayInterval).toBe(true); + }); + + test("allows overriding ignoreDisplayInterval to false", () => { + const client = new KnockGuideClient(mockKnock, channelId); + client.store.state.debug = undefined; + + vi.spyOn(client, "fetch").mockImplementation(() => + Promise.resolve({ status: "ok" }), + ); + vi.spyOn(client, "subscribe").mockImplementation(() => {}); + + client.setDebug({ ignoreDisplayInterval: false }); + + expect(client.store.state.debug!.ignoreDisplayInterval).toBe(false); + }); }); describe("unsetDebug", () => { diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx index a02e4001d..0adfd46fc 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx +++ b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx @@ -16,6 +16,7 @@ export const GuideContextDetails = () => { defaultGroup: state.guideGroups[0], debugSettings: { skipEngagementTracking: !!state.debug?.skipEngagementTracking, + ignoreDisplayInterval: !!state.debug?.ignoreDisplayInterval, }, }; }); @@ -70,6 +71,30 @@ export const GuideContextDetails = () => { + + + Ignore throttle + + + + Throttle From df3b5310da5c753689b4e5d5830dcf5d950821b5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 25 Feb 2026 14:53:28 -0500 Subject: [PATCH 2/5] update the layout a bit --- .../Toolbar/V2/GuideContextDetails.tsx | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx index 0adfd46fc..aa12c7be7 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx +++ b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx @@ -71,37 +71,32 @@ export const GuideContextDetails = () => { - - - Ignore throttle - - - - - - - Throttle - - - {displayInterval === null ? "-" : `Every ${displayInterval}s`} - + + + + Ignore throttle setting + + + + + + Throttle interval:{" "} + {displayInterval === null + ? "(none)" + : `Every ${displayInterval}s`} + + From eb46af4ad31f0054b2b36aeb1856e6704464be33 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 25 Feb 2026 15:09:14 -0500 Subject: [PATCH 3/5] add a tooltip --- .../components/Toolbar/V2/GuideContextDetails.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx index aa12c7be7..9bc631b66 100644 --- a/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx +++ b/packages/react/src/modules/guide/components/Toolbar/V2/GuideContextDetails.tsx @@ -73,9 +73,14 @@ export const GuideContextDetails = () => { - - Ignore throttle setting - + + + Suspend throttle application + + + + +