@thoughtspot/visual-embed-sdk 1.52.1 → 1.52.2-beta
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 +11 -4
- package/cjs/src/contracts/host-event-contracts.d.ts +49 -11
- package/cjs/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +4 -3
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +1 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +10 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.js +1 -1
- package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.spec.js +24 -13
- package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.js +1 -1
- package/cjs/src/embed/bodyless-conversation.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +1 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +4 -4
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +35 -24
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/embedConfig.spec.js +2 -1
- package/cjs/src/embed/embedConfig.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.js +16 -10
- package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js +14 -8
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.d.ts +9 -0
- package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.js +49 -3
- package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.spec.js +151 -0
- package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +4 -3
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +18 -13
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +2 -1
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/search-bar.js +1 -1
- package/cjs/src/embed/search-bar.js.map +1 -1
- package/cjs/src/embed/search.js +1 -1
- package/cjs/src/embed/search.js.map +1 -1
- package/cjs/src/embed/search.spec.js +20 -0
- package/cjs/src/embed/search.spec.js.map +1 -1
- package/cjs/src/embed/spotter-utils.d.ts +8 -1
- package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-utils.js +14 -1
- package/cjs/src/embed/spotter-utils.js.map +1 -1
- package/cjs/src/embed/spotter-utils.spec.js +26 -0
- package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +3 -0
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +108 -29
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +163 -23
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/errors.js +1 -1
- package/cjs/src/errors.js.map +1 -1
- package/cjs/src/index.d.ts +2 -1
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +3 -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 +2 -1
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/types.d.ts +45 -22
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +44 -21
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js +2 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/cjs/src/utils/custom-actions.spec.js +4 -2
- package/cjs/src/utils/custom-actions.spec.js.map +1 -1
- package/cjs/src/utils/filterConverter.d.ts +106 -0
- package/cjs/src/utils/filterConverter.d.ts.map +1 -0
- package/cjs/src/utils/filterConverter.js +215 -0
- package/cjs/src/utils/filterConverter.js.map +1 -0
- package/cjs/src/utils/filterConverter.spec.d.ts +2 -0
- package/cjs/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/cjs/src/utils/filterConverter.spec.js +709 -0
- package/cjs/src/utils/filterConverter.spec.js.map +1 -0
- package/cjs/src/utils/processData.spec.js +2 -1
- package/cjs/src/utils/processData.spec.js.map +1 -1
- package/dist/{index-C1pmYb5H.js → index-CcBYlGo9.js} +1 -1
- package/dist/src/contracts/host-event-contracts.d.ts +49 -11
- package/dist/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +4 -3
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +1 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/utils.d.ts +9 -0
- package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +4 -3
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-utils.d.ts +8 -1
- package/dist/src/embed/spotter-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +3 -0
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -1
- 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 +45 -22
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/filterConverter.d.ts +106 -0
- package/dist/src/utils/filterConverter.d.ts.map +1 -0
- package/dist/src/utils/filterConverter.spec.d.ts +2 -0
- package/dist/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/dist/tsembed-react.es.js +257 -87
- package/dist/tsembed-react.js +256 -86
- package/dist/tsembed.es.js +466 -89
- package/dist/tsembed.js +465 -87
- package/dist/visual-embed-sdk-react-full.d.ts +202 -40
- package/dist/visual-embed-sdk-react.d.ts +108 -40
- package/dist/visual-embed-sdk.d.ts +202 -40
- package/lib/package.json +11 -4
- package/lib/src/contracts/host-event-contracts.d.ts +49 -11
- package/lib/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +4 -3
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +1 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +10 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.js +1 -1
- package/lib/src/embed/auto-frame-renderer.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.spec.js +24 -13
- package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.js +1 -1
- package/lib/src/embed/bodyless-conversation.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +1 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +5 -5
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +35 -24
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/embedConfig.spec.js +2 -1
- package/lib/src/embed/embedConfig.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.js +17 -11
- package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.spec.js +14 -8
- package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.d.ts +9 -0
- package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/utils.js +47 -2
- package/lib/src/embed/hostEventClient/utils.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.spec.js +152 -1
- package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +4 -3
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +18 -13
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +2 -1
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/search-bar.js +1 -1
- package/lib/src/embed/search-bar.js.map +1 -1
- package/lib/src/embed/search.js +1 -1
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/search.spec.js +20 -0
- package/lib/src/embed/search.spec.js.map +1 -1
- package/lib/src/embed/spotter-utils.d.ts +8 -1
- package/lib/src/embed/spotter-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-utils.js +12 -0
- package/lib/src/embed/spotter-utils.js.map +1 -1
- package/lib/src/embed/spotter-utils.spec.js +27 -1
- package/lib/src/embed/spotter-utils.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +3 -0
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +108 -29
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +164 -24
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.js +1 -1
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -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 +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/types.d.ts +45 -22
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +44 -21
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js +2 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/lib/src/utils/custom-actions.spec.js +4 -2
- package/lib/src/utils/custom-actions.spec.js.map +1 -1
- package/lib/src/utils/filterConverter.d.ts +106 -0
- package/lib/src/utils/filterConverter.d.ts.map +1 -0
- package/lib/src/utils/filterConverter.js +210 -0
- package/lib/src/utils/filterConverter.js.map +1 -0
- package/lib/src/utils/filterConverter.spec.d.ts +2 -0
- package/lib/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/lib/src/utils/filterConverter.spec.js +707 -0
- package/lib/src/utils/filterConverter.spec.js.map +1 -0
- package/lib/src/utils/processData.spec.js +2 -1
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +202 -40
- package/package.json +11 -4
- package/src/contracts/host-event-contracts.ts +55 -11
- package/src/embed/app.spec.ts +15 -0
- package/src/embed/app.ts +5 -4
- package/src/embed/auto-frame-renderer.spec.ts +24 -13
- package/src/embed/auto-frame-renderer.ts +1 -1
- package/src/embed/bodyless-conversation.ts +1 -1
- package/src/embed/conversation.spec.ts +38 -27
- package/src/embed/conversation.ts +5 -5
- package/src/embed/embedConfig.spec.ts +2 -1
- package/src/embed/hostEventClient/host-event-client.spec.ts +14 -8
- package/src/embed/hostEventClient/host-event-client.ts +18 -10
- package/src/embed/hostEventClient/utils.spec.ts +176 -1
- package/src/embed/hostEventClient/utils.ts +51 -2
- package/src/embed/liveboard.spec.ts +4 -3
- package/src/embed/liveboard.ts +22 -16
- package/src/embed/search-bar.tsx +1 -1
- package/src/embed/search.spec.ts +23 -0
- package/src/embed/search.ts +1 -1
- package/src/embed/spotter-utils.spec.ts +29 -0
- package/src/embed/spotter-utils.ts +16 -0
- package/src/embed/ts-embed.spec.ts +204 -23
- package/src/embed/ts-embed.ts +114 -28
- package/src/errors.ts +1 -1
- package/src/index.ts +10 -0
- package/src/react/all-types-export.ts +4 -0
- package/src/types.ts +44 -21
- package/src/utils/authService/tokenizedAuthService.spec.ts +2 -1
- package/src/utils/custom-actions.spec.ts +4 -2
- package/src/utils/filterConverter.spec.ts +801 -0
- package/src/utils/filterConverter.ts +304 -0
- package/src/utils/processData.spec.ts +2 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026
|
|
3
|
+
*
|
|
4
|
+
* Utility to convert the payload emitted by `EmbedEvent.FilterChanged`
|
|
5
|
+
* into the payload shape expected by `HostEvent.UpdateFilters`, so that
|
|
6
|
+
* the current filter state of a Liveboard can be captured and re-applied
|
|
7
|
+
* later without having to hand-parse the event payload.
|
|
8
|
+
* @summary Filter payload converter
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import isNil from 'lodash/isNil';
|
|
12
|
+
import { RuntimeFilter, RuntimeFilterOp } from '../types';
|
|
13
|
+
import { Applicability, ApplicabilityLevel } from '../contracts/ui-passthrough-contracts';
|
|
14
|
+
|
|
15
|
+
export interface FilterChangedFilterContentValue {
|
|
16
|
+
key?: string | number | boolean | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FilterChangedFilterContent {
|
|
20
|
+
filterType?: string;
|
|
21
|
+
negate?: boolean;
|
|
22
|
+
value?: FilterChangedFilterContentValue[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface FilterChangedDateFilterValue {
|
|
26
|
+
type?: string;
|
|
27
|
+
op?: string;
|
|
28
|
+
// The payload is JSON from the embedded app, so absent fields can arrive
|
|
29
|
+
// as `null` rather than being omitted.
|
|
30
|
+
epoch?: string | number | null;
|
|
31
|
+
dateRange?: {
|
|
32
|
+
lowEpoch?: string | number | null;
|
|
33
|
+
highEpoch?: string | number | null;
|
|
34
|
+
};
|
|
35
|
+
monthName?: string;
|
|
36
|
+
quarterName?: string;
|
|
37
|
+
yearName?: string;
|
|
38
|
+
number?: number | null;
|
|
39
|
+
datePeriod?: string;
|
|
40
|
+
includeCurrentPeriod?: boolean | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface FilterChangedDateFilterContent {
|
|
44
|
+
negate?: boolean;
|
|
45
|
+
dateFilter?: FilterChangedDateFilterValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface FilterChangedFilter {
|
|
49
|
+
filterContent?: FilterChangedFilterContent[];
|
|
50
|
+
dateFilterContent?: FilterChangedDateFilterContent[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface FilterChangedFilterGroup {
|
|
54
|
+
columnInfo?: {
|
|
55
|
+
name?: string;
|
|
56
|
+
};
|
|
57
|
+
filters?: FilterChangedFilter[];
|
|
58
|
+
/**
|
|
59
|
+
* Scope of the filter - `LIVEBOARD`, `TAB` or `GROUP`. Present from
|
|
60
|
+
* SDK 1.53.0 / ThoughtSpot 26.10.0.cl. Omitted means Liveboard level.
|
|
61
|
+
*/
|
|
62
|
+
applicability?: Applicability;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Shape of the payload received via `LiveboardEmbed.on(EmbedEvent.FilterChanged, ...)`.
|
|
67
|
+
*/
|
|
68
|
+
export interface FilterChangedPayload {
|
|
69
|
+
liveboardFilters?: FilterChangedFilterGroup[];
|
|
70
|
+
runtimeFilters?: RuntimeFilter[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface UpdateFiltersFilterParam {
|
|
74
|
+
columnName: string;
|
|
75
|
+
operator: string;
|
|
76
|
+
values: (string | number | boolean | bigint)[];
|
|
77
|
+
type?: string;
|
|
78
|
+
datePeriod?: string;
|
|
79
|
+
negate?: boolean;
|
|
80
|
+
includeCurrentPeriod?: boolean;
|
|
81
|
+
applicability?: Applicability;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Shape expected by `liveboardEmbed.trigger(HostEvent.UpdateFilters, ...)`.
|
|
86
|
+
*/
|
|
87
|
+
export interface UpdateFiltersPayload {
|
|
88
|
+
filters: UpdateFiltersFilterParam[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
type DateFilterValueExtractor = (dateFilter: FilterChangedDateFilterValue) => (string | number)[];
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Coerces an epoch/count field to a number, returning `null` when the value is
|
|
95
|
+
* absent or not a finite number. The payload arrives as JSON from the iframe,
|
|
96
|
+
* so a missing field can be `null` as well as `undefined`, and `Number(null)`
|
|
97
|
+
* or `Number('')` would otherwise silently become a valid-looking `0`
|
|
98
|
+
* (i.e. the Unix epoch, or a zero-length period).
|
|
99
|
+
* @param value Raw value from the date filter payload.
|
|
100
|
+
*/
|
|
101
|
+
function toFiniteNumber(value: string | number | undefined | null): number | null {
|
|
102
|
+
if (isNil(value) || value === '') return null;
|
|
103
|
+
const numericValue = Number(value);
|
|
104
|
+
return Number.isFinite(numericValue) ? numericValue : null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const DATE_FILTER_VALUE_EXTRACTORS: Record<string, DateFilterValueExtractor> = {
|
|
108
|
+
EXACT_DATE: (dateFilter) => {
|
|
109
|
+
const epoch = toFiniteNumber(dateFilter.epoch);
|
|
110
|
+
return epoch === null ? [] : [epoch];
|
|
111
|
+
},
|
|
112
|
+
EXACT_DATE_RANGE: (dateFilter) => {
|
|
113
|
+
const { lowEpoch, highEpoch } = dateFilter.dateRange ?? {};
|
|
114
|
+
const low = toFiniteNumber(lowEpoch);
|
|
115
|
+
const high = toFiniteNumber(highEpoch);
|
|
116
|
+
return low === null || high === null ? [] : [low, high];
|
|
117
|
+
},
|
|
118
|
+
MONTH_YEAR: (dateFilter) => (
|
|
119
|
+
dateFilter.monthName && dateFilter.yearName
|
|
120
|
+
? [dateFilter.monthName, dateFilter.yearName]
|
|
121
|
+
: []
|
|
122
|
+
),
|
|
123
|
+
QUARTER_YEAR: (dateFilter) => (
|
|
124
|
+
dateFilter.quarterName && dateFilter.yearName
|
|
125
|
+
? [dateFilter.quarterName, dateFilter.yearName]
|
|
126
|
+
: []
|
|
127
|
+
),
|
|
128
|
+
YEAR_ONLY: (dateFilter) => (dateFilter.yearName ? [dateFilter.yearName] : []),
|
|
129
|
+
LAST_N_PERIOD: (dateFilter) => {
|
|
130
|
+
const count = toFiniteNumber(dateFilter.number);
|
|
131
|
+
return count === null ? [] : [count];
|
|
132
|
+
},
|
|
133
|
+
NEXT_N_PERIOD: (dateFilter) => {
|
|
134
|
+
const count = toFiniteNumber(dateFilter.number);
|
|
135
|
+
return count === null ? [] : [count];
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Date filter types with no `values` (e.g. TODAY needs no operand).
|
|
140
|
+
const PERIOD_ONLY_DATE_FILTER_TYPES = new Set([
|
|
141
|
+
'THIS_PERIOD', 'PERIOD_TO_DATE', 'TODAY', 'YESTERDAY', 'TOMORROW',
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
function convertDateFilterToParam(
|
|
145
|
+
columnName: string,
|
|
146
|
+
dateFilterContent: FilterChangedDateFilterContent,
|
|
147
|
+
): UpdateFiltersFilterParam | null {
|
|
148
|
+
const dateFilter = dateFilterContent?.dateFilter;
|
|
149
|
+
if (!dateFilter?.type) return null;
|
|
150
|
+
|
|
151
|
+
let values: (string | number)[];
|
|
152
|
+
const getValues = DATE_FILTER_VALUE_EXTRACTORS[dateFilter.type];
|
|
153
|
+
if (getValues) {
|
|
154
|
+
values = getValues(dateFilter);
|
|
155
|
+
// Required fields (e.g. epoch, yearName) are missing - the source data
|
|
156
|
+
// can't be reconstructed faithfully, so skip rather than emit a filter
|
|
157
|
+
// that would clear/corrupt this column when re-applied.
|
|
158
|
+
if (values.length === 0) return null;
|
|
159
|
+
} else if (PERIOD_ONLY_DATE_FILTER_TYPES.has(dateFilter.type)) {
|
|
160
|
+
values = [];
|
|
161
|
+
} else {
|
|
162
|
+
// Unrecognized date filter type - skip rather than guess.
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const param: UpdateFiltersFilterParam = {
|
|
167
|
+
columnName,
|
|
168
|
+
operator: dateFilter.op ?? RuntimeFilterOp.EQ,
|
|
169
|
+
values,
|
|
170
|
+
type: dateFilter.type,
|
|
171
|
+
};
|
|
172
|
+
if (dateFilter.datePeriod) {
|
|
173
|
+
param.datePeriod = dateFilter.datePeriod;
|
|
174
|
+
}
|
|
175
|
+
if (!isNil(dateFilter.includeCurrentPeriod)) {
|
|
176
|
+
param.includeCurrentPeriod = dateFilter.includeCurrentPeriod;
|
|
177
|
+
}
|
|
178
|
+
if (dateFilterContent.negate) {
|
|
179
|
+
param.negate = true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return param;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function convertFilterContentToParam(
|
|
186
|
+
columnName: string,
|
|
187
|
+
filterContent: FilterChangedFilterContent,
|
|
188
|
+
): UpdateFiltersFilterParam | null {
|
|
189
|
+
if (!filterContent?.filterType) return null;
|
|
190
|
+
|
|
191
|
+
const values = (filterContent.value ?? [])
|
|
192
|
+
.map((value) => value?.key)
|
|
193
|
+
.filter((value): value is string | number | boolean => !isNil(value));
|
|
194
|
+
|
|
195
|
+
const param: UpdateFiltersFilterParam = {
|
|
196
|
+
columnName,
|
|
197
|
+
operator: filterContent.filterType,
|
|
198
|
+
values,
|
|
199
|
+
};
|
|
200
|
+
if (filterContent.negate) {
|
|
201
|
+
param.negate = true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return param;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function convertFilterToParams(columnName: string, filter: FilterChangedFilter): UpdateFiltersFilterParam[] {
|
|
208
|
+
const dateParams = (filter?.dateFilterContent ?? [])
|
|
209
|
+
.map((dateFilterContent) => convertDateFilterToParam(columnName, dateFilterContent));
|
|
210
|
+
const contentParams = (filter?.filterContent ?? [])
|
|
211
|
+
.map((filterContent) => convertFilterContentToParam(columnName, filterContent));
|
|
212
|
+
|
|
213
|
+
return [...dateParams, ...contentParams]
|
|
214
|
+
.filter((param): param is UpdateFiltersFilterParam => param !== null);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Runtime filters need no reshaping, but they still come off the wire as JSON,
|
|
219
|
+
* so a malformed entry is possible. Skip it rather than pass it through: an
|
|
220
|
+
* entry missing a column, operator or values array fails
|
|
221
|
+
* `isValidUpdateFiltersPayload`, and that rejects the *whole* `filters` array,
|
|
222
|
+
* so one bad runtime filter would drop every other converted filter with it.
|
|
223
|
+
* @param runtimeFilter A runtime filter from the `FilterChanged` payload.
|
|
224
|
+
*/
|
|
225
|
+
function convertRuntimeFilterToParam(runtimeFilter: RuntimeFilter): UpdateFiltersFilterParam | null {
|
|
226
|
+
const { columnName, operator, values } = runtimeFilter ?? {};
|
|
227
|
+
if (typeof columnName !== 'string' || !columnName) return null;
|
|
228
|
+
if (typeof operator !== 'string' || !operator) return null;
|
|
229
|
+
if (!Array.isArray(values)) return null;
|
|
230
|
+
|
|
231
|
+
return { columnName, operator, values };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Mirrors `isValidApplicability` in `hostEventClient/utils`: a `TAB` or `GROUP`
|
|
236
|
+
* scope is meaningless without a `targetId`, and `UpdateFilters` rejects the
|
|
237
|
+
* whole `filters` array when any entry carries a malformed `applicability`.
|
|
238
|
+
* @param applicability Scope taken from the `FilterChanged` payload.
|
|
239
|
+
*/
|
|
240
|
+
function isUsableApplicability(applicability: Applicability): boolean {
|
|
241
|
+
const levels: string[] = Object.values(ApplicabilityLevel);
|
|
242
|
+
if (!levels.includes(applicability.level)) return false;
|
|
243
|
+
if (applicability.level === ApplicabilityLevel.Liveboard) return true;
|
|
244
|
+
return typeof applicability.targetId === 'string' && applicability.targetId.trim().length > 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function convertFilterGroupToParams(filterGroup: FilterChangedFilterGroup): UpdateFiltersFilterParam[] {
|
|
248
|
+
const columnName = filterGroup?.columnInfo?.name;
|
|
249
|
+
if (!columnName) return [];
|
|
250
|
+
|
|
251
|
+
const { applicability } = filterGroup;
|
|
252
|
+
// A filter scoped to a tab or group has to keep that scope. Replaying it
|
|
253
|
+
// without `applicability` would silently widen it to the whole Liveboard,
|
|
254
|
+
// changing what every other tab shows. If a scope is present but unusable,
|
|
255
|
+
// skip the filter: widening is worse than dropping, and a malformed
|
|
256
|
+
// applicability would fail validation for every other filter alongside it.
|
|
257
|
+
if (!isNil(applicability) && !isUsableApplicability(applicability)) return [];
|
|
258
|
+
|
|
259
|
+
const params = (filterGroup.filters ?? [])
|
|
260
|
+
.flatMap((filter) => convertFilterToParams(columnName, filter));
|
|
261
|
+
|
|
262
|
+
return isNil(applicability) ? params : params.map((param) => ({ ...param, applicability }));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Converts the payload emitted by {@link EmbedEvent.FilterChanged} into the
|
|
267
|
+
* payload shape expected by {@link HostEvent.UpdateFilters}, so the same
|
|
268
|
+
* filter state can be captured and re-applied later, for example on a
|
|
269
|
+
* subsequent page load.
|
|
270
|
+
*
|
|
271
|
+
* Both the Liveboard filters and the runtime filters present in the
|
|
272
|
+
* `FilterChanged` payload are included in the returned `filters` array.
|
|
273
|
+
*
|
|
274
|
+
* Note: a column with multiple date-filter conditions (e.g. an OR of two
|
|
275
|
+
* date ranges) is not guaranteed to round-trip losslessly - `HostEvent.UpdateFilters`
|
|
276
|
+
* treats date filters as replace-not-merge per column, so only the last
|
|
277
|
+
* converted entry for such a column will apply.
|
|
278
|
+
* @param filterChangedPayload The filter state carried by the
|
|
279
|
+
* `EmbedEvent.FilterChanged` callback, which is `payload.data` - the
|
|
280
|
+
* callback argument is the event envelope, and the filters sit under its
|
|
281
|
+
* `data` key.
|
|
282
|
+
* @example
|
|
283
|
+
* ```js
|
|
284
|
+
* let savedFilters;
|
|
285
|
+
* liveboardEmbed.on(EmbedEvent.FilterChanged, (payload) => {
|
|
286
|
+
* savedFilters = convertFilterChangedToUpdateFiltersPayload(payload.data);
|
|
287
|
+
* });
|
|
288
|
+
*
|
|
289
|
+
* // later, e.g. after a fresh page load
|
|
290
|
+
* liveboardEmbed.trigger(HostEvent.UpdateFilters, savedFilters);
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export function convertFilterChangedToUpdateFiltersPayload(
|
|
294
|
+
filterChangedPayload: FilterChangedPayload,
|
|
295
|
+
): UpdateFiltersPayload {
|
|
296
|
+
const liveboardFilterParams = (filterChangedPayload?.liveboardFilters ?? [])
|
|
297
|
+
.flatMap(convertFilterGroupToParams);
|
|
298
|
+
|
|
299
|
+
const runtimeFilterParams = (filterChangedPayload?.runtimeFilters ?? [])
|
|
300
|
+
.map(convertRuntimeFilterToParam)
|
|
301
|
+
.filter((param): param is UpdateFiltersFilterParam => param !== null);
|
|
302
|
+
|
|
303
|
+
return { filters: [...liveboardFilterParams, ...runtimeFilterParams] };
|
|
304
|
+
}
|
|
@@ -311,7 +311,8 @@ describe('Unit test for process data', () => {
|
|
|
311
311
|
} as any);
|
|
312
312
|
const el: any = {};
|
|
313
313
|
processDataInstance.processEventData(e.type, e, '', el);
|
|
314
|
-
// isEmbeddedSSOInfoFailure=true so neither branch fires, innerHTML
|
|
314
|
+
// isEmbeddedSSOInfoFailure=true so neither branch fires, innerHTML
|
|
315
|
+
// stays unset
|
|
315
316
|
expect(el.innerHTML).toBeUndefined();
|
|
316
317
|
expect(base.notifyAuthFailure).not.toHaveBeenCalled();
|
|
317
318
|
});
|