Skip to content

Commit 2b936a5

Browse files
committed
[SCAL-303326] support visual overrides for charts
1 parent 41e678e commit 2b936a5

6 files changed

Lines changed: 228 additions & 8 deletions

File tree

src/embed/app.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
MessagePayload,
1919
AllEmbedViewConfig,
2020
DefaultAppInitData,
21+
VisualOverridesPayload,
2122
} from '../types';
2223
import { V1Embed } from './ts-embed';
2324
import { SpotterChatViewConfig, SpotterSidebarViewConfig } from './conversation';
@@ -776,6 +777,13 @@ export interface AppViewConfig extends AllEmbedViewConfig {
776777
* @version SDK: 1.48.0 | ThoughtSpot: 26.5.0.cl
777778
*/
778779
enableHomepageAnnouncement?: boolean;
780+
781+
/**
782+
* Default visual overrides from `init()` sent on APP_INIT as `visualOverridesParams`
783+
* when the embed view config does not set {@link SearchLiveboardCommonViewConfig.visualOverrides}.
784+
* @version SDK: 1.47.0
785+
*/
786+
visualOverrides?: VisualOverridesPayload;
779787
}
780788

781789
/**
@@ -785,6 +793,7 @@ export interface AppViewConfig extends AllEmbedViewConfig {
785793
export interface AppEmbedAppInitData extends DefaultAppInitData {
786794
embedParams?: {
787795
spotterSidebarConfig?: SpotterSidebarViewConfig;
796+
visualOverridesParams?: VisualOverridesPayload | null;
788797
};
789798
}
790799

@@ -822,6 +831,8 @@ export class AppEmbed extends V1Embed {
822831
*
823832
* An invalid `spotterDocumentationUrl` triggers a validation error and is
824833
* excluded from the payload rather than forwarded to the app.
834+
*
835+
* Also sets `embedParams.visualOverridesParams` from {@link AppViewConfig.visualOverrides}.
825836
*/
826837
protected async getAppInitData(): Promise<AppEmbedAppInitData> {
827838
const defaultAppInitData = await super.getAppInitData();

src/embed/conversation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import isUndefined from 'lodash/isUndefined';
22
import { ERROR_MESSAGE } from '../errors';
3-
import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes, DefaultAppInitData } from '../types';
3+
import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes, DefaultAppInitData, VisualOverridesPayload } from '../types';
44
import { TsEmbed } from './ts-embed';
55
import { buildSpotterSidebarAppInitData } from './spotter-utils';
66
import { getQueryParamString, getFilterQuery, getRuntimeParameters, setParamIfDefined } from '../utils';
@@ -351,6 +351,7 @@ export interface ConversationViewConfig extends SpotterEmbedViewConfig {}
351351
export interface SpotterAppInitData extends DefaultAppInitData {
352352
embedParams?: {
353353
spotterSidebarConfig?: SpotterSidebarViewConfig;
354+
visualOverridesParams?: VisualOverridesPayload | null;
354355
};
355356
}
356357

src/embed/search.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
SearchLiveboardCommonViewConfig,
1616
DefaultAppInitData,
1717
BaseViewConfig,
18+
VisualOverridesPayload,
1819
} from '../types';
1920
import {
2021
getQueryParamString,
@@ -317,6 +318,13 @@ export interface SearchViewConfig
317318
* ```
318319
*/
319320
focusSearchBarOnRender?: boolean;
321+
322+
/**
323+
* Default visual overrides from `init()` sent on APP_INIT as `visualOverridesParams`
324+
* when the embed view config does not set {@link SearchLiveboardCommonViewConfig.visualOverrides}.
325+
* @version SDK: 1.47.0
326+
*/
327+
visualOverrides?: VisualOverridesPayload;
320328
}
321329

322330
export const HiddenActionItemByDefaultForSearchEmbed = [
@@ -329,6 +337,9 @@ export const HiddenActionItemByDefaultForSearchEmbed = [
329337

330338
export interface SearchAppInitData extends DefaultAppInitData {
331339
searchOptions?: SearchOptions;
340+
embedParams?: {
341+
visualOverridesParams?: VisualOverridesPayload | null;
342+
};
332343
}
333344

334345
/**
@@ -380,7 +391,21 @@ export class SearchEmbed extends TsEmbed {
380391

381392
protected async getAppInitData(): Promise<SearchAppInitData> {
382393
const defaultAppInitData = await super.getAppInitData();
383-
return { ...defaultAppInitData, ...this.getSearchInitData() };
394+
const result: SearchAppInitData = {
395+
...defaultAppInitData,
396+
...this.getSearchInitData(),
397+
};
398+
399+
if (this.viewConfig.visualOverrides) {
400+
result.embedParams = {
401+
...((defaultAppInitData as any).embedParams || {}),
402+
visualOverridesParams: this.viewConfig.visualOverrides,
403+
};
404+
} else if ((defaultAppInitData as any).embedParams) {
405+
result.embedParams = (defaultAppInitData as any).embedParams;
406+
}
407+
408+
return result;
384409
}
385410

386411
protected getEmbedParamsObject() {

src/embed/spotter-utils.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DefaultAppInitData, ErrorDetailsTypes, EmbedErrorCodes } from '../types
22
import { validateHttpUrl } from '../utils';
33
import { ERROR_MESSAGE } from '../errors';
44
import type { SpotterSidebarViewConfig } from './conversation';
5+
import type { VisualOverridesPayload } from '../types';
56

67
/**
78
* Resolves enablePastConversationsSidebar with
@@ -22,18 +23,32 @@ export function buildSpotterSidebarAppInitData<T extends DefaultAppInitData>(
2223
viewConfig: {
2324
spotterSidebarConfig?: SpotterSidebarViewConfig;
2425
enablePastConversationsSidebar?: boolean;
26+
visualOverrides?: VisualOverridesPayload;
2527
},
2628
handleError: (err: any) => void,
27-
): T & { embedParams?: { spotterSidebarConfig?: SpotterSidebarViewConfig } } {
28-
const { spotterSidebarConfig, enablePastConversationsSidebar } = viewConfig;
29+
): T & {
30+
embedParams?: {
31+
spotterSidebarConfig?: SpotterSidebarViewConfig;
32+
visualOverridesParams?: VisualOverridesPayload | null;
33+
};
34+
} {
35+
const { spotterSidebarConfig, enablePastConversationsSidebar, visualOverrides } = viewConfig;
2936

3037
const resolvedEnablePastConversations = resolveEnablePastConversationsSidebar({
3138
spotterSidebarConfigValue: spotterSidebarConfig?.enablePastConversationsSidebar,
3239
standaloneValue: enablePastConversationsSidebar,
3340
});
3441

3542
const hasConfig = spotterSidebarConfig || resolvedEnablePastConversations !== undefined;
36-
if (!hasConfig) return defaultAppInitData;
43+
if (!hasConfig) {
44+
if (visualOverrides === undefined) {
45+
return defaultAppInitData;
46+
}
47+
return {
48+
...defaultAppInitData,
49+
embedParams: { visualOverridesParams: visualOverrides },
50+
};
51+
}
3752

3853
const resolvedSidebarConfig: SpotterSidebarViewConfig = {
3954
...spotterSidebarConfig,
@@ -58,8 +73,8 @@ export function buildSpotterSidebarAppInitData<T extends DefaultAppInitData>(
5873
return {
5974
...defaultAppInitData,
6075
embedParams: {
61-
...((defaultAppInitData as any).embedParams || {}),
6276
spotterSidebarConfig: resolvedSidebarConfig,
77+
...(visualOverrides !== undefined ? { visualOverridesParams: visualOverrides } : {}),
6378
},
6479
};
6580
}

src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ import {
6767
CustomActionTarget,
6868
InterceptedApiType,
6969
EmbedErrorCodes,
70-
EmbedErrorDetailsEvent,
70+
EmbedErrorDetailsEvent,
7171
ErrorDetailsTypes,
7272
ContextType,
7373
AutoMCPFrameRendererViewConfig,
@@ -171,4 +171,5 @@ export {
171171
};
172172

173173
export { resetCachedAuthToken } from './authToken';
174-
export { startAutoMCPFrameRenderer } from './embed/auto-frame-renderer';
174+
export { startAutoMCPFrameRenderer } from './embed/auto-frame-renderer';
175+
export type { VisualOverridesPayload } from './types';

src/types.ts

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8126,3 +8126,170 @@ export interface ContextObject {
81268126
objectIds: ObjectIds;
81278127
}
81288128
}
8129+
8130+
8131+
// ─── Visual Overrides ────────────────────────────────────────────────────────
8132+
8133+
export interface FontProperties {
8134+
color?: string;
8135+
bold?: boolean;
8136+
italic?: boolean;
8137+
strikeThrough?: boolean;
8138+
underline?: boolean;
8139+
}
8140+
8141+
export interface SolidBackgroundAttrs {
8142+
color?: string;
8143+
}
8144+
8145+
export interface GradientBackgroundAttrs {
8146+
backgroundFormatMidpoint?: number;
8147+
colors?: string[];
8148+
backgroundFormatRange?: number[];
8149+
isAutoScaled?: boolean;
8150+
}
8151+
8152+
export interface ConditionalFormattingRow {
8153+
operator: string;
8154+
value?: string;
8155+
rangeValues?: { min: number; max: number };
8156+
plotAsBand?: boolean;
8157+
isHighlightRow?: boolean;
8158+
comparisonType?: 'VALUE_BASED' | 'COLUMN_BASED' | 'PARAMETER_BASED';
8159+
lhsColumnId?: string;
8160+
columnToCompare?: string;
8161+
comparisonParameterId?: string;
8162+
fontProperties?: FontProperties;
8163+
backgroundFormatType?: 'SOLID' | 'GRADIENT';
8164+
solidBackgroundAttrs?: SolidBackgroundAttrs;
8165+
gradientBackgroundAttrs?: GradientBackgroundAttrs;
8166+
}
8167+
8168+
export interface ConditionalFormatting {
8169+
rows?: ConditionalFormattingRow[];
8170+
}
8171+
8172+
export interface ColorPalette {
8173+
colors?: string[];
8174+
}
8175+
8176+
export interface ChartLegend {
8177+
show?: boolean;
8178+
position?: 'top' | 'bottom' | 'left' | 'right';
8179+
colorPalette?: ColorPalette;
8180+
}
8181+
8182+
export interface DataLabelFilter {
8183+
value?: number;
8184+
operator?: string;
8185+
}
8186+
8187+
export interface ColumnDataLabel {
8188+
name: string;
8189+
visible?: boolean;
8190+
filter?: DataLabelFilter | null;
8191+
}
8192+
8193+
export interface ChartDataLabel {
8194+
allLabels?: boolean;
8195+
stackLabels?: boolean;
8196+
columnDataLabel?: ColumnDataLabel[];
8197+
}
8198+
8199+
export interface ChartSummaries {
8200+
showRowTotals?: boolean;
8201+
showColumnTotals?: boolean;
8202+
showRowGrandTotals?: boolean;
8203+
showColumnGrandTotals?: boolean;
8204+
}
8205+
8206+
export interface GridLine {
8207+
x?: boolean;
8208+
y?: boolean;
8209+
}
8210+
8211+
export interface ChartDisplay {
8212+
summaries?: ChartSummaries;
8213+
regressionLine?: boolean;
8214+
gridLine?: GridLine;
8215+
}
8216+
8217+
export interface YAxisRange {
8218+
min?: number;
8219+
max?: number;
8220+
}
8221+
8222+
export interface ChartAxis {
8223+
linkedColumns?: string[];
8224+
showName?: boolean;
8225+
showLabelValue?: boolean;
8226+
yAxisRange?: YAxisRange;
8227+
}
8228+
8229+
export interface ChartColumn {
8230+
name: string;
8231+
color?: string;
8232+
conditionalFormatting?: ConditionalFormatting;
8233+
}
8234+
8235+
export interface ChartOverrides {
8236+
legend?: ChartLegend;
8237+
dataLabel?: ChartDataLabel;
8238+
display?: ChartDisplay;
8239+
axis?: ChartAxis[];
8240+
columns?: ChartColumn[];
8241+
updateMaskPaths?: string[];
8242+
}
8243+
8244+
export interface TableColumn {
8245+
name: string;
8246+
wrapText?: boolean;
8247+
show?: boolean;
8248+
conditionalFormatting?: ConditionalFormatting;
8249+
}
8250+
8251+
export interface TableDisplay {
8252+
tableTheme?: string;
8253+
tableContentDensity?: string;
8254+
}
8255+
8256+
export interface ColumnSummaryVisibility {
8257+
columnId: string;
8258+
visible: boolean;
8259+
}
8260+
8261+
export interface DisplaySummaryConfig {
8262+
showAllSummaries?: boolean;
8263+
columnVisibility?: ColumnSummaryVisibility[];
8264+
}
8265+
8266+
export interface TableOverrides {
8267+
columns?: TableColumn[];
8268+
display?: TableDisplay;
8269+
displaySummaryConfig?: DisplaySummaryConfig;
8270+
updateMaskPaths?: string[];
8271+
}
8272+
8273+
/**
8274+
* Visual overrides payload to customize chart and table rendering
8275+
* within embedded ThoughtSpot components.
8276+
*
8277+
* @example
8278+
* ```js
8279+
* const embed = new AppEmbed('#tsEmbed', {
8280+
* visualOverrides: {
8281+
* chart: {
8282+
* legend: { show: true, position: 'bottom' },
8283+
* columns: [{ name: 'Revenue', color: '#1f77b4' }],
8284+
* },
8285+
* table: {
8286+
* display: { tableTheme: 'ZEBRA', tableContentDensity: 'COMPACT' },
8287+
* },
8288+
* },
8289+
* });
8290+
* ```
8291+
*/
8292+
export interface VisualOverridesPayload {
8293+
chart?: ChartOverrides;
8294+
table?: TableOverrides;
8295+
}

0 commit comments

Comments
 (0)