@thoughtspot/visual-embed-sdk 1.53.0 → 1.53.1
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/cjs/package.json +1 -1
- package/cjs/src/contracts/contracts.spec.js +4 -0
- package/cjs/src/contracts/contracts.spec.js.map +1 -1
- package/cjs/src/contracts/host-event-contracts.d.ts +10 -0
- package/cjs/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +1 -0
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +14 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +22 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/host-events.spec.js +32 -0
- package/cjs/src/embed/host-events.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +2 -16
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +29 -10
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +97 -0
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/spotter-utils.d.ts +1 -0
- package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-utils.js +7 -1
- package/cjs/src/embed/spotter-utils.js.map +1 -1
- package/cjs/src/embed/spotter-utils.spec.js +19 -0
- package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +21 -16
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +77 -63
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +240 -7
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +2 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/react/all-types-export.d.ts +1 -1
- package/cjs/src/react/all-types-export.d.ts.map +1 -1
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/types.d.ts +69 -2
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +67 -0
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/runtimeTelemetry.d.ts +11 -0
- package/cjs/src/utils/runtimeTelemetry.d.ts.map +1 -0
- package/cjs/src/utils/runtimeTelemetry.js +34 -0
- package/cjs/src/utils/runtimeTelemetry.js.map +1 -0
- package/cjs/src/utils/runtimeTelemetry.spec.d.ts +2 -0
- package/cjs/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
- package/cjs/src/utils/runtimeTelemetry.spec.js +124 -0
- package/cjs/src/utils/runtimeTelemetry.spec.js.map +1 -0
- package/dist/{index-CyDR8j_0.js → index-CrBnZBZv.js} +1 -1
- package/dist/src/contracts/host-event-contracts.d.ts +10 -0
- package/dist/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +1 -0
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +14 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +2 -16
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-utils.d.ts +1 -0
- package/dist/src/embed/spotter-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +21 -16
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/all-types-export.d.ts +1 -1
- package/dist/src/react/all-types-export.d.ts.map +1 -1
- package/dist/src/types.d.ts +69 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/runtimeTelemetry.d.ts +11 -0
- package/dist/src/utils/runtimeTelemetry.d.ts.map +1 -0
- package/dist/src/utils/runtimeTelemetry.spec.d.ts +2 -0
- package/dist/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
- package/dist/tsembed-react.es.js +247 -78
- package/dist/tsembed-react.js +246 -77
- package/dist/tsembed.es.js +247 -78
- package/dist/tsembed.js +246 -77
- package/dist/visual-embed-sdk-react-full.d.ts +116 -18
- package/dist/visual-embed-sdk-react.d.ts +116 -18
- package/dist/visual-embed-sdk.d.ts +116 -33
- package/lib/package.json +1 -1
- package/lib/src/contracts/contracts.spec.js +4 -0
- package/lib/src/contracts/contracts.spec.js.map +1 -1
- package/lib/src/contracts/host-event-contracts.d.ts +10 -0
- package/lib/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +1 -0
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +14 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +22 -0
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/host-events.spec.js +32 -0
- package/lib/src/embed/host-events.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +2 -16
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +28 -10
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +97 -0
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/spotter-utils.d.ts +1 -0
- package/lib/src/embed/spotter-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-utils.js +7 -1
- package/lib/src/embed/spotter-utils.js.map +1 -1
- package/lib/src/embed/spotter-utils.spec.js +19 -0
- package/lib/src/embed/spotter-utils.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +21 -16
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +78 -64
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +240 -7
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/all-types-export.d.ts +1 -1
- package/lib/src/react/all-types-export.d.ts.map +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/types.d.ts +69 -2
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +67 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/runtimeTelemetry.d.ts +11 -0
- package/lib/src/utils/runtimeTelemetry.d.ts.map +1 -0
- package/lib/src/utils/runtimeTelemetry.js +28 -0
- package/lib/src/utils/runtimeTelemetry.js.map +1 -0
- package/lib/src/utils/runtimeTelemetry.spec.d.ts +2 -0
- package/lib/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
- package/lib/src/utils/runtimeTelemetry.spec.js +122 -0
- package/lib/src/utils/runtimeTelemetry.spec.js.map +1 -0
- package/lib/src/visual-embed-sdk.d.ts +116 -33
- package/package.json +1 -1
- package/src/contracts/contracts.spec.ts +4 -0
- package/src/contracts/host-event-contracts.ts +13 -0
- package/src/embed/app.ts +1 -0
- package/src/embed/conversation.spec.ts +24 -0
- package/src/embed/conversation.ts +14 -0
- package/src/embed/host-events.spec.ts +44 -0
- package/src/embed/liveboard.spec.ts +111 -0
- package/src/embed/liveboard.ts +34 -10
- package/src/embed/spotter-utils.spec.ts +20 -0
- package/src/embed/spotter-utils.ts +12 -1
- package/src/embed/ts-embed.spec.ts +297 -8
- package/src/embed/ts-embed.ts +79 -64
- package/src/index.ts +2 -0
- package/src/react/all-types-export.ts +1 -0
- package/src/types.ts +68 -0
- package/src/utils/runtimeTelemetry.spec.ts +148 -0
- package/src/utils/runtimeTelemetry.ts +50 -0
|
@@ -795,6 +795,30 @@ describe('SpotterEmbed APP_INIT embedParams', () => {
|
|
|
795
795
|
).toEqual(spotterChatPinConfig);
|
|
796
796
|
});
|
|
797
797
|
|
|
798
|
+
it('should send enableConnectorMarketplace in embedParams.spotterSidebarConfig, not the URL', async () => {
|
|
799
|
+
const response = await getAppInitResponse({
|
|
800
|
+
worksheetId: 'ws1',
|
|
801
|
+
spotterSidebarConfig: {
|
|
802
|
+
enableConnectorMarketplace: true,
|
|
803
|
+
},
|
|
804
|
+
});
|
|
805
|
+
expect(response.data.embedParams.spotterSidebarConfig.enableConnectorMarketplace).toBe(true);
|
|
806
|
+
expect(getIFrameSrc()).not.toContain('enableConnectorMarketplace');
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('should send enableSpotterInstructionAndMoreSettings at the top level of embedParams', async () => {
|
|
810
|
+
const response = await getAppInitResponse({
|
|
811
|
+
worksheetId: 'ws1',
|
|
812
|
+
spotterSidebarConfig: {
|
|
813
|
+
enablePastConversationsSidebar: true,
|
|
814
|
+
enableSpotterInstructionAndMoreSettings: true,
|
|
815
|
+
},
|
|
816
|
+
});
|
|
817
|
+
expect(response.data.embedParams.enableSpotterInstructionAndMoreSettings).toBe(true);
|
|
818
|
+
expect(response.data.embedParams.spotterSidebarConfig)
|
|
819
|
+
.not.toHaveProperty('enableSpotterInstructionAndMoreSettings');
|
|
820
|
+
});
|
|
821
|
+
|
|
798
822
|
it('should populate enablePastConversationsSidebar from deprecated standalone flag', async () => {
|
|
799
823
|
const response = await getAppInitResponse({
|
|
800
824
|
worksheetId: 'ws1',
|
|
@@ -152,6 +152,19 @@ export interface SpotterSidebarViewConfig {
|
|
|
152
152
|
* @default Analysts
|
|
153
153
|
*/
|
|
154
154
|
spotterAnalystsLabel?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Shows the connector marketplace option in the settings menu of the
|
|
157
|
+
* Spotter sidebar footer. When not set, the cluster setting applies.
|
|
158
|
+
* @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
|
|
159
|
+
*/
|
|
160
|
+
enableConnectorMarketplace?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Shows the Spotter instructions and more settings options in the
|
|
163
|
+
* settings menu of the Spotter sidebar footer.
|
|
164
|
+
* @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
|
|
165
|
+
* @default false
|
|
166
|
+
*/
|
|
167
|
+
enableSpotterInstructionAndMoreSettings?: boolean;
|
|
155
168
|
}
|
|
156
169
|
|
|
157
170
|
/**
|
|
@@ -822,6 +835,7 @@ export interface SpotterAppInitData extends DefaultAppInitData {
|
|
|
822
835
|
visualOverridesParams?: VisualizationOverrides | null;
|
|
823
836
|
starterPrompts?: StarterPromptsConfig;
|
|
824
837
|
spotterAnalystConfig?: SpotterAnalystConfig;
|
|
838
|
+
enableSpotterInstructionAndMoreSettings?: boolean;
|
|
825
839
|
};
|
|
826
840
|
}
|
|
827
841
|
|
|
@@ -636,6 +636,50 @@ describe('HostEvent.Edit', () => {
|
|
|
636
636
|
});
|
|
637
637
|
});
|
|
638
638
|
|
|
639
|
+
// ---------------------------------------------------------------------------
|
|
640
|
+
// ExitEditMode
|
|
641
|
+
// ---------------------------------------------------------------------------
|
|
642
|
+
describe('HostEvent.ExitEditMode', () => {
|
|
643
|
+
test("enum value is 'exitEditMode' (wire contract with the host app)", () => {
|
|
644
|
+
expect(HostEvent.ExitEditMode).toBe('exitEditMode');
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("postMessage type is 'exitEditMode' (camelCase)", async () => {
|
|
648
|
+
mockMessageChannel();
|
|
649
|
+
const { lb, iframe } = await renderLiveboard();
|
|
650
|
+
await executeAfterWait(() => {
|
|
651
|
+
lb.trigger(HostEvent.ExitEditMode);
|
|
652
|
+
expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(
|
|
653
|
+
expect.objectContaining({ type: 'exitEditMode' }),
|
|
654
|
+
thoughtSpotHost,
|
|
655
|
+
expect.anything(),
|
|
656
|
+
);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
test('viewConfig.vizId is injected into the payload as data.vizId', async () => {
|
|
661
|
+
mockMessageChannel();
|
|
662
|
+
const { lb, iframe } = await renderLiveboard({ vizId });
|
|
663
|
+
await executeAfterWait(() => {
|
|
664
|
+
lb.trigger(HostEvent.ExitEditMode, {} as any);
|
|
665
|
+
expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(
|
|
666
|
+
expect.objectContaining({
|
|
667
|
+
type: 'exitEditMode',
|
|
668
|
+
data: expect.objectContaining({ vizId }),
|
|
669
|
+
}),
|
|
670
|
+
thoughtSpotHost,
|
|
671
|
+
expect.anything(),
|
|
672
|
+
);
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
test('returns null when !isRendered', async () => {
|
|
677
|
+
const lb = unrenderedLiveboard();
|
|
678
|
+
const result = await lb.trigger(HostEvent.ExitEditMode);
|
|
679
|
+
expect(result).toBeNull();
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
|
|
639
683
|
// ---------------------------------------------------------------------------
|
|
640
684
|
// 30 – CopyLink (maps to 'embedDocument')
|
|
641
685
|
// ---------------------------------------------------------------------------
|
|
@@ -158,6 +158,25 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
158
158
|
});
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
+
test('should hide and disable the Cancel button in the Liveboard edit header', async () => {
|
|
162
|
+
expect(Action.Cancel).toBe('cancel');
|
|
163
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
164
|
+
hiddenActions: [Action.Cancel],
|
|
165
|
+
disabledActions: [Action.Cancel],
|
|
166
|
+
disabledActionReason: 'Save your changes to leave edit mode',
|
|
167
|
+
...defaultViewConfig,
|
|
168
|
+
liveboardId,
|
|
169
|
+
} as LiveboardViewConfig);
|
|
170
|
+
liveboardEmbed.render();
|
|
171
|
+
await executeAfterWait(() => {
|
|
172
|
+
expectUrlToHaveParamsWithValues(getIFrameSrc(), {
|
|
173
|
+
hideAction: JSON.stringify([Action.ReportError, Action.Cancel]),
|
|
174
|
+
disableAction: JSON.stringify([Action.Cancel]),
|
|
175
|
+
disableHint: 'Save your changes to leave edit mode',
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
161
180
|
test('should hide and disable the Spotter button on the Liveboard header', async () => {
|
|
162
181
|
expect(Action.SpotterOnLiveboard).toBe('spotterOnLiveboard');
|
|
163
182
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
@@ -2832,6 +2851,98 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
2832
2851
|
expect(navigateToLiveboardSpy).toHaveBeenCalled();
|
|
2833
2852
|
});
|
|
2834
2853
|
|
|
2854
|
+
test('should not route via home when a new instance shows an equal config', async () => {
|
|
2855
|
+
const viewConfig = {
|
|
2856
|
+
liveboardId,
|
|
2857
|
+
vizId,
|
|
2858
|
+
activeTabId,
|
|
2859
|
+
...defaultViewConfig,
|
|
2860
|
+
};
|
|
2861
|
+
const previous = new LiveboardEmbed(getRootEl(), { ...viewConfig, beforeRender: () => {} } as any);
|
|
2862
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...viewConfig, beforeRender: () => {} } as any);
|
|
2863
|
+
|
|
2864
|
+
// React constructs a new embed on every mount.
|
|
2865
|
+
jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
|
|
2866
|
+
const triggerSpy = jest
|
|
2867
|
+
.spyOn(liveboardEmbed, 'trigger')
|
|
2868
|
+
.mockImplementation(() => Promise.resolve(undefined as any));
|
|
2869
|
+
const navigateToLiveboardSpy = jest
|
|
2870
|
+
.spyOn(liveboardEmbed, 'navigateToLiveboard')
|
|
2871
|
+
.mockImplementation(() => Promise.resolve(undefined));
|
|
2872
|
+
|
|
2873
|
+
liveboardEmbed.isEmbedContainerLoaded = false;
|
|
2874
|
+
liveboardEmbed['beforePrerenderVisible']();
|
|
2875
|
+
liveboardEmbed.isEmbedContainerLoaded = true;
|
|
2876
|
+
liveboardEmbed['executeEmbedContainerReadyCallbacks']();
|
|
2877
|
+
await waitForPreRenderNavigate();
|
|
2878
|
+
|
|
2879
|
+
expect(triggerSpy).not.toHaveBeenCalledWith(HostEvent.Navigate, 'home');
|
|
2880
|
+
expect(navigateToLiveboardSpy).toHaveBeenCalled();
|
|
2881
|
+
});
|
|
2882
|
+
|
|
2883
|
+
test('should not route via home when the previous instance has been shown once', async () => {
|
|
2884
|
+
// navigateToLiveboard assigns vizId/activeTabId/personalizedViewId
|
|
2885
|
+
// unconditionally, so a shown instance carries them as undefined
|
|
2886
|
+
// while a fresh one lacks the keys entirely. Comparing raw objects
|
|
2887
|
+
// counts own keys, so it never matches again.
|
|
2888
|
+
const viewConfig = { liveboardId, ...defaultViewConfig };
|
|
2889
|
+
const previous = new LiveboardEmbed(getRootEl(), { ...viewConfig } as any);
|
|
2890
|
+
(previous as any).viewConfig.vizId = undefined;
|
|
2891
|
+
(previous as any).viewConfig.activeTabId = undefined;
|
|
2892
|
+
(previous as any).viewConfig.personalizedViewId = undefined;
|
|
2893
|
+
|
|
2894
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...viewConfig } as any);
|
|
2895
|
+
|
|
2896
|
+
jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
|
|
2897
|
+
const triggerSpy = jest
|
|
2898
|
+
.spyOn(liveboardEmbed, 'trigger')
|
|
2899
|
+
.mockImplementation(() => Promise.resolve(undefined as any));
|
|
2900
|
+
jest
|
|
2901
|
+
.spyOn(liveboardEmbed, 'navigateToLiveboard')
|
|
2902
|
+
.mockImplementation(() => Promise.resolve(undefined));
|
|
2903
|
+
|
|
2904
|
+
liveboardEmbed.isEmbedContainerLoaded = false;
|
|
2905
|
+
liveboardEmbed['beforePrerenderVisible']();
|
|
2906
|
+
liveboardEmbed.isEmbedContainerLoaded = true;
|
|
2907
|
+
liveboardEmbed['executeEmbedContainerReadyCallbacks']();
|
|
2908
|
+
await waitForPreRenderNavigate();
|
|
2909
|
+
|
|
2910
|
+
expect(triggerSpy).not.toHaveBeenCalledWith(HostEvent.Navigate, 'home');
|
|
2911
|
+
});
|
|
2912
|
+
|
|
2913
|
+
test('should route via home when a new instance shows the same route with other filters', async () => {
|
|
2914
|
+
const viewConfig = {
|
|
2915
|
+
liveboardId,
|
|
2916
|
+
vizId,
|
|
2917
|
+
activeTabId,
|
|
2918
|
+
...defaultViewConfig,
|
|
2919
|
+
};
|
|
2920
|
+
const previous = new LiveboardEmbed(getRootEl(), {
|
|
2921
|
+
...viewConfig,
|
|
2922
|
+
runtimeFilters: [{ columnName: 'region', operator: RuntimeFilterOp.EQ, values: ['east'] }],
|
|
2923
|
+
});
|
|
2924
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2925
|
+
...viewConfig,
|
|
2926
|
+
runtimeFilters: [{ columnName: 'region', operator: RuntimeFilterOp.EQ, values: ['west'] }],
|
|
2927
|
+
});
|
|
2928
|
+
|
|
2929
|
+
jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
|
|
2930
|
+
const triggerSpy = jest
|
|
2931
|
+
.spyOn(liveboardEmbed, 'trigger')
|
|
2932
|
+
.mockImplementation(() => Promise.resolve(undefined as any));
|
|
2933
|
+
jest
|
|
2934
|
+
.spyOn(liveboardEmbed, 'navigateToLiveboard')
|
|
2935
|
+
.mockImplementation(() => Promise.resolve(undefined));
|
|
2936
|
+
|
|
2937
|
+
liveboardEmbed.isEmbedContainerLoaded = false;
|
|
2938
|
+
liveboardEmbed['beforePrerenderVisible']();
|
|
2939
|
+
liveboardEmbed.isEmbedContainerLoaded = true;
|
|
2940
|
+
liveboardEmbed['executeEmbedContainerReadyCallbacks']();
|
|
2941
|
+
await waitForHomeHopNavigate();
|
|
2942
|
+
|
|
2943
|
+
expect(triggerSpy).toHaveBeenCalledWith(HostEvent.Navigate, 'home');
|
|
2944
|
+
});
|
|
2945
|
+
|
|
2835
2946
|
test('should not route via home when the pre-render is on another liveboard', async () => {
|
|
2836
2947
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2837
2948
|
liveboardId,
|
package/src/embed/liveboard.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import isEqualWith from 'lodash/isEqualWith';
|
|
11
12
|
import { getPreview } from '../utils/graphql/preview-service';
|
|
12
13
|
import { ERROR_MESSAGE } from '../errors';
|
|
13
14
|
import {
|
|
@@ -605,6 +606,14 @@ export interface LiveboardViewConfig
|
|
|
605
606
|
* })
|
|
606
607
|
* ```
|
|
607
608
|
*/
|
|
609
|
+
/**
|
|
610
|
+
* A shallow copy without the keys whose value is `undefined`, so a key that was
|
|
611
|
+
* assigned `undefined` compares equal to one that was never set.
|
|
612
|
+
*/
|
|
613
|
+
const definedEntries = (config: Record<string, any> = {}): Record<string, any> => Object.fromEntries(
|
|
614
|
+
Object.entries(config).filter(([, value]) => value !== undefined),
|
|
615
|
+
);
|
|
616
|
+
|
|
608
617
|
export class LiveboardEmbed extends V1Embed {
|
|
609
618
|
protected viewConfig: LiveboardViewConfig;
|
|
610
619
|
|
|
@@ -1004,17 +1013,19 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
1004
1013
|
super.beforePrerenderVisible();
|
|
1005
1014
|
|
|
1006
1015
|
// Captured before showPreRender() hands the wrapper over to this
|
|
1007
|
-
// instance.
|
|
1008
|
-
// nothing stale to clear.
|
|
1016
|
+
// instance. React builds a new instance per mount, so an equal config
|
|
1017
|
+
// is a hide/show, not a hand-over: there is nothing stale to clear.
|
|
1009
1018
|
const previous = this.getPreRenderObj<LiveboardEmbed>();
|
|
1010
|
-
const
|
|
1019
|
+
const previousRoute = this.isSameEmbedConfig(previous)
|
|
1020
|
+
? undefined
|
|
1021
|
+
: previous?.currentLiveboardState;
|
|
1011
1022
|
|
|
1012
1023
|
this.executeAfterEmbedContainerLoaded(async () => {
|
|
1013
1024
|
// Without this the params callback suspends on its await and
|
|
1014
1025
|
// Navigate goes out first, so the container loads with the previous
|
|
1015
1026
|
// config's filters.
|
|
1016
1027
|
await this.preRenderParamsApplied;
|
|
1017
|
-
if (this.
|
|
1028
|
+
if (this.isAlreadyOnSameRoute(previousRoute)) {
|
|
1018
1029
|
// Navigate to the route we are already on is a no-op, so the
|
|
1019
1030
|
// liveboard keeps its state. Home unmounts the container, which
|
|
1020
1031
|
// clears it.
|
|
@@ -1041,18 +1052,31 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
1041
1052
|
});
|
|
1042
1053
|
}
|
|
1043
1054
|
|
|
1055
|
+
// definedEntries drops undefined-valued keys: a shown instance carries
|
|
1056
|
+
// vizId/activeTabId/etc as undefined, so a raw isEqual never matches again.
|
|
1057
|
+
// Functions compare equal, since React passes a fresh closure per render.
|
|
1058
|
+
private isSameEmbedConfig(previous?: LiveboardEmbed): boolean {
|
|
1059
|
+
if (!previous) return false;
|
|
1060
|
+
if (previous === this) return true;
|
|
1061
|
+
return isEqualWith(
|
|
1062
|
+
definedEntries(previous.viewConfig),
|
|
1063
|
+
definedEntries(this.viewConfig),
|
|
1064
|
+
(a, b) => (typeof a === 'function' && typeof b === 'function' ? true : undefined),
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1044
1068
|
// The whole route, not just the liveboard id: the path is built from the
|
|
1045
1069
|
// viz, tab and view too, so a same-liveboard show onto another tab is a
|
|
1046
1070
|
// real navigation.
|
|
1047
|
-
private
|
|
1048
|
-
if (!
|
|
1071
|
+
private isAlreadyOnSameRoute(previousRoute?: LiveboardEmbed['currentLiveboardState']): boolean {
|
|
1072
|
+
if (!previousRoute?.liveboardId) return false;
|
|
1049
1073
|
const {
|
|
1050
1074
|
liveboardId, vizId, activeTabId, personalizedViewId,
|
|
1051
1075
|
} = this.viewConfig;
|
|
1052
|
-
return
|
|
1053
|
-
&&
|
|
1054
|
-
&&
|
|
1055
|
-
&&
|
|
1076
|
+
return previousRoute.liveboardId === liveboardId
|
|
1077
|
+
&& previousRoute.vizId === vizId
|
|
1078
|
+
&& previousRoute.activeTabId === activeTabId
|
|
1079
|
+
&& previousRoute.personalizedViewId === personalizedViewId;
|
|
1056
1080
|
}
|
|
1057
1081
|
|
|
1058
1082
|
protected async handleRenderForPrerender(): Promise<TsEmbed> {
|
|
@@ -58,6 +58,26 @@ describe('buildSpotterSidebarAppInitData', () => {
|
|
|
58
58
|
.toEqual(spotterChatPinConfig);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
it('lifts enableSpotterInstructionAndMoreSettings to the top level of embedParams', () => {
|
|
62
|
+
const result = buildSpotterSidebarAppInitData(base, {
|
|
63
|
+
spotterSidebarConfig: {
|
|
64
|
+
enablePastConversationsSidebar: true,
|
|
65
|
+
enableSpotterInstructionAndMoreSettings: false,
|
|
66
|
+
},
|
|
67
|
+
}, noopError);
|
|
68
|
+
expect(result.embedParams?.enableSpotterInstructionAndMoreSettings).toBe(false);
|
|
69
|
+
expect(result.embedParams?.spotterSidebarConfig).toEqual({
|
|
70
|
+
enablePastConversationsSidebar: true,
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('omits enableSpotterInstructionAndMoreSettings when it is not set', () => {
|
|
75
|
+
const result = buildSpotterSidebarAppInitData(base, {
|
|
76
|
+
spotterSidebarConfig: { enablePastConversationsSidebar: true },
|
|
77
|
+
}, noopError);
|
|
78
|
+
expect(result.embedParams).not.toHaveProperty('enableSpotterInstructionAndMoreSettings');
|
|
79
|
+
});
|
|
80
|
+
|
|
61
81
|
it('promotes standalone flag into spotterSidebarConfig.enablePastConversationsSidebar', () => {
|
|
62
82
|
const result = buildSpotterSidebarAppInitData(base, { enablePastConversationsSidebar: true }, noopError);
|
|
63
83
|
expect(result.embedParams?.spotterSidebarConfig?.enablePastConversationsSidebar).toBe(true);
|
|
@@ -36,6 +36,7 @@ export function buildSpotterSidebarAppInitData<T extends DefaultAppInitData>(
|
|
|
36
36
|
embedParams?: {
|
|
37
37
|
spotterSidebarConfig?: SpotterSidebarViewConfig;
|
|
38
38
|
visualOverridesParams?: VisualizationOverrides | null;
|
|
39
|
+
enableSpotterInstructionAndMoreSettings?: boolean;
|
|
39
40
|
};
|
|
40
41
|
} {
|
|
41
42
|
const { spotterSidebarConfig, enablePastConversationsSidebar, visualOverrides } = viewConfig;
|
|
@@ -56,8 +57,15 @@ export function buildSpotterSidebarAppInitData<T extends DefaultAppInitData>(
|
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
// The app reads enableSpotterInstructionAndMoreSettings from the top level
|
|
61
|
+
// of embedParams, so lift it out of the sidebar config.
|
|
62
|
+
const {
|
|
63
|
+
enableSpotterInstructionAndMoreSettings,
|
|
64
|
+
...sidebarConfigRest
|
|
65
|
+
} = spotterSidebarConfig || {};
|
|
66
|
+
|
|
59
67
|
const resolvedSidebarConfig: SpotterSidebarViewConfig = {
|
|
60
|
-
...
|
|
68
|
+
...sidebarConfigRest,
|
|
61
69
|
...(resolvedEnablePastConversations !== undefined && {
|
|
62
70
|
enablePastConversationsSidebar: resolvedEnablePastConversations,
|
|
63
71
|
}),
|
|
@@ -81,6 +89,9 @@ export function buildSpotterSidebarAppInitData<T extends DefaultAppInitData>(
|
|
|
81
89
|
embedParams: {
|
|
82
90
|
...((defaultAppInitData as any).embedParams || {}),
|
|
83
91
|
spotterSidebarConfig: resolvedSidebarConfig,
|
|
92
|
+
...(enableSpotterInstructionAndMoreSettings !== undefined
|
|
93
|
+
? { enableSpotterInstructionAndMoreSettings }
|
|
94
|
+
: {}),
|
|
84
95
|
...(visualOverrides !== undefined ? { visualOverridesParams: visualOverrides } : {}),
|
|
85
96
|
},
|
|
86
97
|
};
|