Skip to content

Commit 22b623c

Browse files
committed
[SCAL-303326] support visual overrides for charts
1 parent 31d3584 commit 22b623c

6 files changed

Lines changed: 226 additions & 6 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';
@@ -798,6 +799,13 @@ export interface AppViewConfig extends AllEmbedViewConfig {
798799
* ```
799800
*/
800801
enableLiveboardDataCache?: boolean;
802+
803+
/**
804+
* Default visual overrides from `init()` sent on APP_INIT as `visualOverridesParams`
805+
* when the embed view config does not set {@link SearchLiveboardCommonViewConfig.visualOverrides}.
806+
* @version SDK: 1.47.0
807+
*/
808+
visualOverrides?: VisualOverridesPayload;
801809
}
802810

803811
/**
@@ -807,6 +815,7 @@ export interface AppViewConfig extends AllEmbedViewConfig {
807815
export interface AppEmbedAppInitData extends DefaultAppInitData {
808816
embedParams?: {
809817
spotterSidebarConfig?: SpotterSidebarViewConfig;
818+
visualOverridesParams?: VisualOverridesPayload | null;
810819
};
811820
}
812821

@@ -844,6 +853,8 @@ export class AppEmbed extends V1Embed {
844853
*
845854
* An invalid `spotterDocumentationUrl` triggers a validation error and is
846855
* excluded from the payload rather than forwarded to the app.
856+
*
857+
* Also sets `embedParams.visualOverridesParams` from {@link AppViewConfig.visualOverrides}.
847858
*/
848859
protected async getAppInitData(): Promise<AppEmbedAppInitData> {
849860
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';
@@ -360,6 +360,7 @@ export interface ConversationViewConfig extends SpotterEmbedViewConfig {}
360360
export interface SpotterAppInitData extends DefaultAppInitData {
361361
embedParams?: {
362362
spotterSidebarConfig?: SpotterSidebarViewConfig;
363+
visualOverridesParams?: VisualOverridesPayload | null;
363364
};
364365
}
365366

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,
@@ -332,6 +333,13 @@ export interface SearchViewConfig
332333
* ```
333334
*/
334335
newChartsLibrary?: boolean;
336+
337+
/**
338+
* Default visual overrides from `init()` sent on APP_INIT as `visualOverridesParams`
339+
* when the embed view config does not set {@link SearchLiveboardCommonViewConfig.visualOverrides}.
340+
* @version SDK: 1.47.0
341+
*/
342+
visualOverrides?: VisualOverridesPayload;
335343
}
336344

337345
export const HiddenActionItemByDefaultForSearchEmbed = [
@@ -344,6 +352,9 @@ export const HiddenActionItemByDefaultForSearchEmbed = [
344352

345353
export interface SearchAppInitData extends DefaultAppInitData {
346354
searchOptions?: SearchOptions;
355+
embedParams?: {
356+
visualOverridesParams?: VisualOverridesPayload | null;
357+
};
347358
}
348359

349360
/**
@@ -395,7 +406,21 @@ export class SearchEmbed extends TsEmbed {
395406

396407
protected async getAppInitData(): Promise<SearchAppInitData> {
397408
const defaultAppInitData = await super.getAppInitData();
398-
return { ...defaultAppInitData, ...this.getSearchInitData() };
409+
const result: SearchAppInitData = {
410+
...defaultAppInitData,
411+
...this.getSearchInitData(),
412+
};
413+
414+
if (this.viewConfig.visualOverrides) {
415+
result.embedParams = {
416+
...((defaultAppInitData as any).embedParams || {}),
417+
visualOverridesParams: this.viewConfig.visualOverrides,
418+
};
419+
} else if ((defaultAppInitData as any).embedParams) {
420+
result.embedParams = (defaultAppInitData as any).embedParams;
421+
}
422+
423+
return result;
399424
}
400425

401426
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,4 @@ export {
169169

170170
export { resetCachedAuthToken } from './authToken';
171171
export { startAutoMCPFrameRenderer } from './embed/auto-frame-renderer';
172+
export type { VisualOverridesPayload } from './types';

src/types.ts

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8214,3 +8214,170 @@ export interface ContextObject {
82148214
objectIds: ObjectIds;
82158215
};
82168216
}
8217+
8218+
8219+
// ─── Visual Overrides ────────────────────────────────────────────────────────
8220+
8221+
export interface FontProperties {
8222+
color?: string;
8223+
bold?: boolean;
8224+
italic?: boolean;
8225+
strikeThrough?: boolean;
8226+
underline?: boolean;
8227+
}
8228+
8229+
export interface SolidBackgroundAttrs {
8230+
color?: string;
8231+
}
8232+
8233+
export interface GradientBackgroundAttrs {
8234+
backgroundFormatMidpoint?: number;
8235+
colors?: string[];
8236+
backgroundFormatRange?: number[];
8237+
isAutoScaled?: boolean;
8238+
}
8239+
8240+
export interface ConditionalFormattingRow {
8241+
operator: string;
8242+
value?: string;
8243+
rangeValues?: { min: number; max: number };
8244+
plotAsBand?: boolean;
8245+
isHighlightRow?: boolean;
8246+
comparisonType?: 'VALUE_BASED' | 'COLUMN_BASED' | 'PARAMETER_BASED';
8247+
lhsColumnId?: string;
8248+
columnToCompare?: string;
8249+
comparisonParameterId?: string;
8250+
fontProperties?: FontProperties;
8251+
backgroundFormatType?: 'SOLID' | 'GRADIENT';
8252+
solidBackgroundAttrs?: SolidBackgroundAttrs;
8253+
gradientBackgroundAttrs?: GradientBackgroundAttrs;
8254+
}
8255+
8256+
export interface ConditionalFormatting {
8257+
rows?: ConditionalFormattingRow[];
8258+
}
8259+
8260+
export interface ColorPalette {
8261+
colors?: string[];
8262+
}
8263+
8264+
export interface ChartLegend {
8265+
show?: boolean;
8266+
position?: 'top' | 'bottom' | 'left' | 'right';
8267+
colorPalette?: ColorPalette;
8268+
}
8269+
8270+
export interface DataLabelFilter {
8271+
value?: number;
8272+
operator?: string;
8273+
}
8274+
8275+
export interface ColumnDataLabel {
8276+
name: string;
8277+
visible?: boolean;
8278+
filter?: DataLabelFilter | null;
8279+
}
8280+
8281+
export interface ChartDataLabel {
8282+
allLabels?: boolean;
8283+
stackLabels?: boolean;
8284+
columnDataLabel?: ColumnDataLabel[];
8285+
}
8286+
8287+
export interface ChartSummaries {
8288+
showRowTotals?: boolean;
8289+
showColumnTotals?: boolean;
8290+
showRowGrandTotals?: boolean;
8291+
showColumnGrandTotals?: boolean;
8292+
}
8293+
8294+
export interface GridLine {
8295+
x?: boolean;
8296+
y?: boolean;
8297+
}
8298+
8299+
export interface ChartDisplay {
8300+
summaries?: ChartSummaries;
8301+
regressionLine?: boolean;
8302+
gridLine?: GridLine;
8303+
}
8304+
8305+
export interface YAxisRange {
8306+
min?: number;
8307+
max?: number;
8308+
}
8309+
8310+
export interface ChartAxis {
8311+
linkedColumns?: string[];
8312+
showName?: boolean;
8313+
showLabelValue?: boolean;
8314+
yAxisRange?: YAxisRange;
8315+
}
8316+
8317+
export interface ChartColumn {
8318+
name: string;
8319+
color?: string;
8320+
conditionalFormatting?: ConditionalFormatting;
8321+
}
8322+
8323+
export interface ChartOverrides {
8324+
legend?: ChartLegend;
8325+
dataLabel?: ChartDataLabel;
8326+
display?: ChartDisplay;
8327+
axis?: ChartAxis[];
8328+
columns?: ChartColumn[];
8329+
updateMaskPaths?: string[];
8330+
}
8331+
8332+
export interface TableColumn {
8333+
name: string;
8334+
wrapText?: boolean;
8335+
show?: boolean;
8336+
conditionalFormatting?: ConditionalFormatting;
8337+
}
8338+
8339+
export interface TableDisplay {
8340+
tableTheme?: string;
8341+
tableContentDensity?: string;
8342+
}
8343+
8344+
export interface ColumnSummaryVisibility {
8345+
columnId: string;
8346+
visible: boolean;
8347+
}
8348+
8349+
export interface DisplaySummaryConfig {
8350+
showAllSummaries?: boolean;
8351+
columnVisibility?: ColumnSummaryVisibility[];
8352+
}
8353+
8354+
export interface TableOverrides {
8355+
columns?: TableColumn[];
8356+
display?: TableDisplay;
8357+
displaySummaryConfig?: DisplaySummaryConfig;
8358+
updateMaskPaths?: string[];
8359+
}
8360+
8361+
/**
8362+
* Visual overrides payload to customize chart and table rendering
8363+
* within embedded ThoughtSpot components.
8364+
*
8365+
* @example
8366+
* ```js
8367+
* const embed = new AppEmbed('#tsEmbed', {
8368+
* visualOverrides: {
8369+
* chart: {
8370+
* legend: { show: true, position: 'bottom' },
8371+
* columns: [{ name: 'Revenue', color: '#1f77b4' }],
8372+
* },
8373+
* table: {
8374+
* display: { tableTheme: 'ZEBRA', tableContentDensity: 'COMPACT' },
8375+
* },
8376+
* },
8377+
* });
8378+
* ```
8379+
*/
8380+
export interface VisualOverridesPayload {
8381+
chart?: ChartOverrides;
8382+
table?: TableOverrides;
8383+
}

0 commit comments

Comments
 (0)