@orchestrator-ui/orchestrator-ui-components 8.5.0 → 8.7.0
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/.turbo/turbo-build.log +10 -14
- package/.turbo/turbo-lint.log +2 -4
- package/.turbo/turbo-test.log +16 -15
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +188 -80
- package/dist/index.js +3509 -2731
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/components/WfoAutoExpandableTextArea/WfoAutoExpandableTextArea.tsx +54 -0
- package/src/components/WfoAutoExpandableTextArea/index.ts +1 -0
- package/src/components/WfoAutoExpandableTextArea/styles.ts +18 -0
- package/src/components/WfoPageTemplate/paths.ts +1 -0
- package/src/components/WfoPydanticForm/fields/WfoCron.spec.ts +88 -0
- package/src/components/WfoPydanticForm/fields/WfoCron.tsx +233 -0
- package/src/components/WfoPydanticForm/fields/index.ts +1 -0
- package/src/components/WfoPydanticForm/fields/styles.ts +92 -0
- package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchResultItem.tsx +2 -1
- package/src/components/WfoSearchPage/utils.ts +37 -1
- package/src/components/WfoSubscription/WfoInUseByRelations.tsx +6 -2
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionExpandableMenuItem.tsx +19 -14
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActions.tsx +13 -1
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionsMenuItem.tsx +3 -0
- package/src/components/WfoSubscription/WfoSubscriptionProductBlock/WfoSubscriptionProductBlock.tsx +1 -1
- package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +5 -0
- package/src/components/WfoSubscriptionsList/subscriptionResultMappers.ts +3 -1
- package/src/components/WfoTable/WfoAdvancedTable/WfoAdvancedTable.tsx +2 -12
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddGroupAction.tsx +1 -1
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector.tsx +3 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +21 -14
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +84 -4
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +119 -104
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoInlineCombinator.tsx +17 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoOperatorSelector.tsx +32 -7
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveRuleAction.tsx +3 -3
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRuleGroup.tsx +11 -7
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoSearchFieldWithActions.tsx +56 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +92 -87
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +41 -11
- package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +74 -21
- package/src/components/WfoTable/WfoStructuredSearchTable/utils.ts +45 -0
- package/src/components/WfoTable/WfoTable/WfoTable.tsx +1 -0
- package/src/components/WfoTable/WfoTable/WfoTableDataRows.tsx +16 -4
- package/src/components/WfoTable/WfoTable/styles.ts +8 -0
- package/src/components/WfoTable/WfoTable/utils.spec.ts +62 -1
- package/src/components/WfoTable/WfoTable/utils.ts +4 -1
- package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.spec.ts +45 -0
- package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.tsx +9 -0
- package/src/components/WfoTable/WfoTableSettingsModal/index.ts +1 -0
- package/src/components/WfoTable/WfoTableSettingsModal/utils.ts +17 -0
- package/src/components/index.ts +1 -0
- package/src/configuration/version.ts +1 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useGetPydanticFormsConfig.tsx +12 -0
- package/src/hooks/useLanguageCode.ts +11 -0
- package/src/messages/en-GB.json +20 -0
- package/src/messages/nl-NL.json +20 -0
- package/src/pages/WfoSearchPocPage.tsx +165 -30
- package/src/rtk/endpoints/subscriptionList.ts +1 -0
- package/src/theme/baseStyles/formFieldsBaseStyle.ts +0 -1
- package/src/types/search.ts +4 -1
- package/src/types/types.ts +1 -1
- package/src/utils/getDefaultTableConfig.ts +6 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/integer.spec.ts +20 -0
- package/src/utils/integer.ts +3 -0
|
@@ -3,31 +3,22 @@ import type { RuleGroupType } from 'react-querybuilder';
|
|
|
3
3
|
|
|
4
4
|
import { useTranslations } from 'next-intl';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
EuiButton,
|
|
8
|
-
EuiButtonIcon,
|
|
9
|
-
EuiFieldSearch,
|
|
10
|
-
EuiFlexGroup,
|
|
11
|
-
EuiFlexItem,
|
|
12
|
-
EuiFormRow,
|
|
13
|
-
EuiSelect,
|
|
14
|
-
EuiSpacer,
|
|
15
|
-
EuiText,
|
|
16
|
-
} from '@elastic/eui';
|
|
6
|
+
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect, EuiSpacer, EuiText } from '@elastic/eui';
|
|
17
7
|
|
|
18
8
|
import {
|
|
19
9
|
DEFAULT_PAGE_SIZE,
|
|
20
10
|
DEFAULT_PAGE_SIZES,
|
|
21
11
|
TableColumnKeys,
|
|
22
|
-
TableSettingsColumnConfig,
|
|
23
12
|
TableSettingsConfig,
|
|
24
13
|
TableSettingsModal,
|
|
14
|
+
WfoDataSearch,
|
|
25
15
|
WfoDataSorting,
|
|
26
16
|
WfoErrorWithMessage,
|
|
27
17
|
WfoInformationModal,
|
|
28
18
|
WfoKeyValueTable,
|
|
29
19
|
WfoKeyValueTableDataType,
|
|
30
20
|
clearTableConfigFromLocalStorage,
|
|
21
|
+
getTableSettingsColumns,
|
|
31
22
|
setTableConfigToLocalStorage,
|
|
32
23
|
} from '@/components';
|
|
33
24
|
import { getRowDetailData } from '@/components/WfoTable/WfoAdvancedTable/getRowDetailData';
|
|
@@ -39,12 +30,14 @@ import {
|
|
|
39
30
|
import { useOrchestratorTheme, useWithOrchestratorTheme } from '@/hooks';
|
|
40
31
|
import { WfoArrowsExpand } from '@/icons';
|
|
41
32
|
import { WfoGraphqlError } from '@/rtk';
|
|
42
|
-
import {
|
|
43
|
-
import { RetrieverType } from '@/types';
|
|
33
|
+
import { FieldToOperatorMap, RetrieverType } from '@/types';
|
|
44
34
|
import { getDefaultTableConfig } from '@/utils';
|
|
45
35
|
|
|
46
36
|
import { ColumnType, WfoTable, WfoTableProps } from '../WfoTable';
|
|
47
37
|
import { WfoFilterBuilder } from './WfoFilterBuilder';
|
|
38
|
+
import { WfoSearchFieldWithActions } from './WfoSearchFieldWithActions';
|
|
39
|
+
import { getWfoStructuredSearchTableStyles } from './styles';
|
|
40
|
+
import { buildColumnFilter } from './utils';
|
|
48
41
|
|
|
49
42
|
export type WfoStructuredSearchTableDataColumnConfigItem<
|
|
50
43
|
T extends object,
|
|
@@ -85,6 +78,9 @@ export type WfoStructuredSearchTableProps<T extends object> = Omit<
|
|
|
85
78
|
onSearchQueryText: (queryString: string) => void;
|
|
86
79
|
onShowMore: () => void;
|
|
87
80
|
onUpdateDataSorting: (updateSorting: WfoDataSorting<T>) => void;
|
|
81
|
+
// Resolves a column key to its search field path (e.g. "status" -> "subscription.status"), used
|
|
82
|
+
// when a column header search adds a condition to the filter query.
|
|
83
|
+
getColumnSearchFieldName?: (field: keyof T) => string;
|
|
88
84
|
onExportData?: () => void;
|
|
89
85
|
retrieverType: RetrieverType;
|
|
90
86
|
onUpdateRetrieverType: (newRetrieverType: RetrieverType) => void;
|
|
@@ -93,11 +89,12 @@ export type WfoStructuredSearchTableProps<T extends object> = Omit<
|
|
|
93
89
|
isValidFilterString?: boolean;
|
|
94
90
|
queryBuilderRuleGroup?: RuleGroupType;
|
|
95
91
|
onUpdateQueryBuilder: (ruleGroup: RuleGroupType | false) => void;
|
|
96
|
-
handleSearch: () => void;
|
|
92
|
+
handleSearch: (searchParams?: SearchParams) => void;
|
|
97
93
|
pageSize: number;
|
|
98
94
|
setPageSize: React.Dispatch<React.SetStateAction<number>>;
|
|
99
95
|
totalItems: number | false;
|
|
100
96
|
hasNextPage: boolean;
|
|
97
|
+
prefilledFieldOptions: FieldToOperatorMap;
|
|
101
98
|
};
|
|
102
99
|
|
|
103
100
|
export const WfoStructuredSearchTable = <T extends object>({
|
|
@@ -119,6 +116,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
119
116
|
queryBuilderRuleGroup,
|
|
120
117
|
onUpdateQueryBuilder,
|
|
121
118
|
onUpdateDataSorting,
|
|
119
|
+
getColumnSearchFieldName,
|
|
122
120
|
handleSearch,
|
|
123
121
|
pageSize,
|
|
124
122
|
setPageSize,
|
|
@@ -128,12 +126,13 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
128
126
|
hasNextPage,
|
|
129
127
|
data,
|
|
130
128
|
isLoading,
|
|
129
|
+
prefilledFieldOptions,
|
|
131
130
|
...tableProps
|
|
132
131
|
}: WfoStructuredSearchTableProps<T>) => {
|
|
133
132
|
const { theme } = useOrchestratorTheme();
|
|
134
|
-
const {
|
|
135
|
-
|
|
133
|
+
const { toggleButtonStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
|
|
136
134
|
const [hiddenColumns, setHiddenColumns] = useState<TableColumnKeys<T>>(defaultHiddenColumns);
|
|
135
|
+
const [isFilterBuilderVisible, setIsFilterBuilderVisible] = useState(false);
|
|
137
136
|
const [showTableSettingsModal, setShowTableSettingsModal] = useState(false);
|
|
138
137
|
const [rowDetailModalData, setRowDetailModalData] = useState<T | undefined>(undefined);
|
|
139
138
|
const [showInformationModal, setShowInformationModal] = useState(false);
|
|
@@ -145,6 +144,12 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
145
144
|
}
|
|
146
145
|
}, [defaultHiddenColumns]);
|
|
147
146
|
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (filterString) {
|
|
149
|
+
setIsFilterBuilderVisible(true);
|
|
150
|
+
}
|
|
151
|
+
}, [filterString]);
|
|
152
|
+
|
|
148
153
|
const detailsIconColumn: WfoStructuredSearchTableColumnConfig<T> = {
|
|
149
154
|
viewDetails: {
|
|
150
155
|
columnType: ColumnType.CONTROL,
|
|
@@ -162,17 +167,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
162
167
|
...tableColumnConfig,
|
|
163
168
|
};
|
|
164
169
|
|
|
165
|
-
const tableSettingsColumns
|
|
166
|
-
([key, { label }]): TableSettingsColumnConfig<T> => {
|
|
167
|
-
const field = key as keyof T;
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
field,
|
|
171
|
-
name: label,
|
|
172
|
-
isVisible: hiddenColumns.indexOf(field) === -1,
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
);
|
|
170
|
+
const tableSettingsColumns = getTableSettingsColumns(tableColumnConfig, hiddenColumns);
|
|
176
171
|
|
|
177
172
|
const rowDetailData: WfoKeyValueTableDataType[] | undefined =
|
|
178
173
|
rowDetailModalData && getRowDetailData(rowDetailModalData, tableColumnConfig);
|
|
@@ -198,10 +193,47 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
198
193
|
clearTableConfigFromLocalStorage(localStorageKey);
|
|
199
194
|
};
|
|
200
195
|
|
|
196
|
+
const handleColumnFilterSearch = ({ field, searchText }: WfoDataSearch<T>) => {
|
|
197
|
+
const columnFilter = buildColumnFilter(field, searchText, filterString, getColumnSearchFieldName);
|
|
198
|
+
if (!columnFilter) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
onUpdateFilterString(columnFilter.filterString);
|
|
202
|
+
handleSearch({ ruleGroup: columnFilter.ruleGroup });
|
|
203
|
+
};
|
|
204
|
+
|
|
201
205
|
return (
|
|
202
206
|
<>
|
|
203
|
-
<EuiFlexGroup alignItems="center">
|
|
204
|
-
|
|
207
|
+
<EuiFlexGroup alignItems="center" gutterSize="s">
|
|
208
|
+
{!isFilterBuilderVisible && (
|
|
209
|
+
<EuiFlexItem grow={false}>
|
|
210
|
+
<EuiButton
|
|
211
|
+
css={toggleButtonStyles}
|
|
212
|
+
onClick={() => setIsFilterBuilderVisible(true)}
|
|
213
|
+
id={'button-toggle-filter-builder'}
|
|
214
|
+
data-test-id={'button-toggle-filter-builder'}
|
|
215
|
+
fill
|
|
216
|
+
type="submit"
|
|
217
|
+
iconType="filter"
|
|
218
|
+
iconSide="left"
|
|
219
|
+
aria-label={t('createFilter')}
|
|
220
|
+
>
|
|
221
|
+
{t('createFilter')}
|
|
222
|
+
</EuiButton>
|
|
223
|
+
</EuiFlexItem>
|
|
224
|
+
)}
|
|
225
|
+
<WfoSearchFieldWithActions
|
|
226
|
+
queryText={queryText}
|
|
227
|
+
onChangeQueryText={onChangeQueryText}
|
|
228
|
+
onSearchQueryText={onSearchQueryText}
|
|
229
|
+
onShowInformation={() => setShowInformationModal(true)}
|
|
230
|
+
onShowTableSettings={() => setShowTableSettingsModal(true)}
|
|
231
|
+
/>
|
|
232
|
+
</EuiFlexGroup>
|
|
233
|
+
|
|
234
|
+
{isFilterBuilderVisible && (
|
|
235
|
+
<>
|
|
236
|
+
<EuiSpacer size="s" />
|
|
205
237
|
<WfoFilterBuilder
|
|
206
238
|
filterString={filterString}
|
|
207
239
|
onUpdateFilterString={onUpdateFilterString}
|
|
@@ -209,64 +241,11 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
209
241
|
queryBuilderRuleGroup={queryBuilderRuleGroup}
|
|
210
242
|
onUpdateQueryBuilder={onUpdateQueryBuilder}
|
|
211
243
|
handleSearch={handleSearch}
|
|
244
|
+
onToggleFilterBuilder={setIsFilterBuilderVisible}
|
|
245
|
+
prefilledFieldOptions={prefilledFieldOptions}
|
|
212
246
|
/>
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
<EuiFlexGroup alignItems="center">
|
|
217
|
-
<EuiFlexItem>
|
|
218
|
-
<EuiFormRow fullWidth>
|
|
219
|
-
<EuiFieldSearch
|
|
220
|
-
css={formFieldBaseStyle}
|
|
221
|
-
value={queryText}
|
|
222
|
-
placeholder={`${t('search')}...`}
|
|
223
|
-
onChange={(e) => onChangeQueryText(e.target.value)}
|
|
224
|
-
onSearch={(queryText) => onSearchQueryText(queryText)}
|
|
225
|
-
fullWidth
|
|
226
|
-
/>
|
|
227
|
-
</EuiFormRow>
|
|
228
|
-
</EuiFlexItem>
|
|
229
|
-
<EuiFlexItem grow={false}>
|
|
230
|
-
<EuiSelect
|
|
231
|
-
options={[
|
|
232
|
-
{
|
|
233
|
-
value: RetrieverType.Auto,
|
|
234
|
-
text: t('retrieverAuto'),
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
value: RetrieverType.Fuzzy,
|
|
238
|
-
text: t('retrieverFuzzy'),
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
value: RetrieverType.Semantic,
|
|
242
|
-
text: t('retrieverSemantic'),
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
value: RetrieverType.Hybrid,
|
|
246
|
-
text: t('retrieverHybrid'),
|
|
247
|
-
},
|
|
248
|
-
]}
|
|
249
|
-
value={retrieverType}
|
|
250
|
-
onChange={(e) => onUpdateRetrieverType(e.target.value as RetrieverType)}
|
|
251
|
-
compressed
|
|
252
|
-
prepend={t('retrieval')}
|
|
253
|
-
/>
|
|
254
|
-
</EuiFlexItem>
|
|
255
|
-
<EuiFlexItem grow={false}>
|
|
256
|
-
<EuiButtonIcon
|
|
257
|
-
onClick={() => setShowInformationModal(true)}
|
|
258
|
-
iconSize={'l'}
|
|
259
|
-
iconType={'info'}
|
|
260
|
-
aria-label={t('searchModalTitle')}
|
|
261
|
-
/>
|
|
262
|
-
</EuiFlexItem>
|
|
263
|
-
<EuiButton onClick={() => setShowTableSettingsModal(true)}>{t('editColumns')}</EuiButton>
|
|
264
|
-
{onExportData && (
|
|
265
|
-
<EuiButton isLoading={exportDataIsLoading} onClick={() => onExportData()}>
|
|
266
|
-
{t('export')}
|
|
267
|
-
</EuiButton>
|
|
268
|
-
)}
|
|
269
|
-
</EuiFlexGroup>
|
|
247
|
+
</>
|
|
248
|
+
)}
|
|
270
249
|
|
|
271
250
|
{error && <WfoErrorWithMessage error={error} />}
|
|
272
251
|
|
|
@@ -277,6 +256,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
277
256
|
hiddenColumns={hiddenColumns}
|
|
278
257
|
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
279
258
|
onUpdateDataSorting={onUpdateDataSorting}
|
|
259
|
+
onUpdateDataSearch={handleColumnFilterSearch}
|
|
280
260
|
dataSorting={dataSorting}
|
|
281
261
|
data={data}
|
|
282
262
|
isLoading={isLoading}
|
|
@@ -302,6 +282,31 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
302
282
|
onClose={() => setShowTableSettingsModal(false)}
|
|
303
283
|
onUpdateTableConfig={handleUpdateTableConfig}
|
|
304
284
|
onResetToDefaults={handleResetToDefaults}
|
|
285
|
+
extraSettings={
|
|
286
|
+
<>
|
|
287
|
+
<EuiFormRow label={t('retrieval')} display="columnCompressed">
|
|
288
|
+
<EuiSelect
|
|
289
|
+
options={[
|
|
290
|
+
{ value: RetrieverType.Auto, text: t('retrieverAuto') },
|
|
291
|
+
{ value: RetrieverType.Fuzzy, text: t('retrieverFuzzy') },
|
|
292
|
+
{ value: RetrieverType.Semantic, text: t('retrieverSemantic') },
|
|
293
|
+
{ value: RetrieverType.Hybrid, text: t('retrieverHybrid') },
|
|
294
|
+
]}
|
|
295
|
+
value={retrieverType}
|
|
296
|
+
onChange={(e) => onUpdateRetrieverType(e.target.value as RetrieverType)}
|
|
297
|
+
compressed
|
|
298
|
+
/>
|
|
299
|
+
</EuiFormRow>
|
|
300
|
+
{onExportData && (
|
|
301
|
+
<>
|
|
302
|
+
<EuiSpacer size="m" />
|
|
303
|
+
<EuiButton isLoading={exportDataIsLoading} onClick={() => onExportData()} fullWidth>
|
|
304
|
+
{t('export')}
|
|
305
|
+
</EuiButton>
|
|
306
|
+
</>
|
|
307
|
+
)}
|
|
308
|
+
</>
|
|
309
|
+
}
|
|
305
310
|
/>
|
|
306
311
|
)}
|
|
307
312
|
|
|
@@ -137,23 +137,53 @@ const DatePicker = ({ handleOnChange, rangeIndex, value: currentValue }: WfoRang
|
|
|
137
137
|
);
|
|
138
138
|
};
|
|
139
139
|
|
|
140
|
-
export const WfoValueEditor = ({
|
|
140
|
+
export const WfoValueEditor = ({
|
|
141
|
+
field: fieldName,
|
|
142
|
+
context,
|
|
143
|
+
handleOnChange,
|
|
144
|
+
operator,
|
|
145
|
+
value,
|
|
146
|
+
className,
|
|
147
|
+
}: ValueEditorProps) => {
|
|
141
148
|
const fieldPathInfoMap = context?.fieldPathInfoMap;
|
|
142
149
|
|
|
143
150
|
const fieldInfo = fieldPathInfoMap && fieldPathInfoMap.has(fieldName) ? fieldPathInfoMap.get(fieldName) : undefined;
|
|
144
151
|
const uiFieldType = fieldInfo?.ui_types[0] || UiFieldType.text;
|
|
145
152
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
const getEditor = () => {
|
|
154
|
+
if (uiFieldType === UiFieldType.boolean) {
|
|
155
|
+
return <BooleanEditor handleOnChange={handleOnChange} value={value} />;
|
|
156
|
+
}
|
|
149
157
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
158
|
+
if (uiFieldType === UiFieldType.datetime) {
|
|
159
|
+
return <WfoRangeEditor handleOnChange={handleOnChange} operator={operator} Element={DatePicker} value={value} />;
|
|
160
|
+
}
|
|
153
161
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
if (uiFieldType === UiFieldType.number) {
|
|
163
|
+
return (
|
|
164
|
+
<WfoRangeEditor handleOnChange={handleOnChange} operator={operator} Element={NumberEditor} value={value} />
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return <TextEditor handleOnChange={handleOnChange} value={value} />;
|
|
169
|
+
};
|
|
157
170
|
|
|
158
|
-
|
|
171
|
+
const handleWrapperKeyDown: KeyboardEventHandler<HTMLDivElement> = (event) => {
|
|
172
|
+
if (event.key !== 'Enter') return;
|
|
173
|
+
// Restrict to the editor inputs: the editors' own Enter handlers have already run
|
|
174
|
+
// (bubble phase) and committed the value via blur, so the search sees it. Enter on
|
|
175
|
+
// the boolean buttons means "select" — its click fires only after this keydown, so
|
|
176
|
+
// searching there would use the pre-toggle value.
|
|
177
|
+
if (!(event.target instanceof HTMLInputElement)) return;
|
|
178
|
+
context?.onValueEditorEnter?.();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// react-querybuilder delivers the standard `rule-value` class via this prop; the wrapper
|
|
182
|
+
// makes it queryable in the DOM (WfoFieldSelector relies on it to move focus here).
|
|
183
|
+
// `display: contents` keeps the children direct participants in the rule's flex row.
|
|
184
|
+
return (
|
|
185
|
+
<div className={className} style={{ display: 'contents' }} onKeyDown={handleWrapperKeyDown}>
|
|
186
|
+
{getEditor()}
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
159
189
|
};
|
|
@@ -2,7 +2,7 @@ import { css } from '@emotion/react';
|
|
|
2
2
|
|
|
3
3
|
import { WfoThemeHelpers } from '@/hooks';
|
|
4
4
|
|
|
5
|
-
export const getWfoStructuredSearchTableStyles = ({ theme
|
|
5
|
+
export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) => {
|
|
6
6
|
const queryBuilderContainerStyles = css({
|
|
7
7
|
backgroundColor: theme.colors.backgroundBaseSubdued,
|
|
8
8
|
padding: theme.base / 2,
|
|
@@ -13,20 +13,35 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
13
13
|
const toggleButtonStyles = css({
|
|
14
14
|
backgroundColor: 'primary',
|
|
15
15
|
padding: theme.base * 0.75,
|
|
16
|
-
marginLeft: theme.base,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const textAreaStyles = css({
|
|
20
|
-
width: '100%',
|
|
21
|
-
maxInlineSize: '100%',
|
|
22
|
-
height: '42px',
|
|
23
|
-
border: `this solid ${toSecondaryColor(theme.colors.borderBasePlain)}`,
|
|
24
16
|
});
|
|
25
17
|
|
|
26
18
|
const buttonGroupStyles = css({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
alignSelf: 'center',
|
|
20
|
+
backgroundColor: 'transparent',
|
|
21
|
+
height: theme.base * 2,
|
|
22
|
+
'.euiButtonGroup__buttons': {
|
|
23
|
+
backgroundColor: 'transparent',
|
|
24
|
+
height: theme.base * 2,
|
|
25
|
+
minHeight: theme.base * 2,
|
|
26
|
+
},
|
|
27
|
+
'button.euiButtonGroupButton': {
|
|
28
|
+
height: theme.base * 2,
|
|
29
|
+
minHeight: theme.base * 2,
|
|
30
|
+
blockSize: theme.base * 2,
|
|
31
|
+
borderRadius: 0,
|
|
32
|
+
transition: 'none',
|
|
33
|
+
},
|
|
34
|
+
'button.euiButtonGroupButton:not(.euiButtonGroupButton-isSelected)': {
|
|
35
|
+
backgroundColor: theme.colors.backgroundBasePlain,
|
|
36
|
+
},
|
|
37
|
+
'button.euiButtonGroupButton:first-of-type': {
|
|
38
|
+
borderTopLeftRadius: theme.base,
|
|
39
|
+
borderBottomLeftRadius: theme.base,
|
|
40
|
+
},
|
|
41
|
+
'button.euiButtonGroupButton:last-of-type': {
|
|
42
|
+
borderTopRightRadius: theme.base,
|
|
43
|
+
borderBottomRightRadius: theme.base,
|
|
44
|
+
},
|
|
30
45
|
});
|
|
31
46
|
|
|
32
47
|
const ruleContainerStyles = css({
|
|
@@ -42,7 +57,7 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
42
57
|
|
|
43
58
|
const ruleGroupContainerBase = {
|
|
44
59
|
padding: theme.base / 2,
|
|
45
|
-
|
|
60
|
+
border: `1px solid ${theme.colors.borderBaseSubdued}`,
|
|
46
61
|
};
|
|
47
62
|
|
|
48
63
|
const ruleGroupContainerBlueStyles = css({
|
|
@@ -74,12 +89,12 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
74
89
|
const removeGroupActionStyles = css({
|
|
75
90
|
backgroundColor: theme.colors.backgroundLightPrimary,
|
|
76
91
|
width: '40px',
|
|
77
|
-
marginTop: theme.base / 4,
|
|
78
92
|
height: 'stretch',
|
|
79
93
|
alignItems: 'center',
|
|
80
94
|
justifyContent: 'center',
|
|
81
95
|
borderBottomRightRadius: theme.border.radius.small,
|
|
82
96
|
borderTopRightRadius: theme.border.radius.small,
|
|
97
|
+
border: `thin solid ${theme.colors.borderBasePlain}`,
|
|
83
98
|
cursor: 'pointer',
|
|
84
99
|
});
|
|
85
100
|
|
|
@@ -92,11 +107,12 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
92
107
|
});
|
|
93
108
|
const expandingRowBodyStyles = css({
|
|
94
109
|
display: 'flex',
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
justifyContent: 'space-between',
|
|
111
|
+
// Size to the visible scroll viewport (minus the td padding) instead of
|
|
112
|
+
// the full table width, and keep it pinned there on horizontal scroll
|
|
113
|
+
position: 'sticky',
|
|
114
|
+
left: theme.base / 2,
|
|
115
|
+
width: `calc(100cqw - ${theme.base}px)`,
|
|
100
116
|
});
|
|
101
117
|
|
|
102
118
|
const addRulePlusStyles = css({
|
|
@@ -119,17 +135,49 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
119
135
|
border: `thin dashed ${theme.colors.backgroundFilledPrimary}`,
|
|
120
136
|
borderRadius: theme.border.radius.medium,
|
|
121
137
|
alignItems: 'center',
|
|
122
|
-
|
|
138
|
+
paddingBlock: theme.base / 3,
|
|
139
|
+
paddingInline: theme.base,
|
|
123
140
|
color: theme.colors.primary,
|
|
124
141
|
justifyContent: 'center',
|
|
125
142
|
flexDirection: 'row',
|
|
126
143
|
cursor: 'pointer',
|
|
127
144
|
});
|
|
128
145
|
|
|
146
|
+
const inlineCombinatorStyles = css({
|
|
147
|
+
alignSelf: 'start',
|
|
148
|
+
transform: `translateY(calc(-50% - ${theme.base / 8}px))`,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const ruleGroupBodyGridStyles = css({
|
|
152
|
+
display: 'grid',
|
|
153
|
+
gridTemplateColumns: 'auto 1fr',
|
|
154
|
+
columnGap: theme.base / 2,
|
|
155
|
+
rowGap: theme.base / 4,
|
|
156
|
+
alignItems: 'center',
|
|
157
|
+
'& > :first-child': {
|
|
158
|
+
gridColumn: '1 / -1',
|
|
159
|
+
},
|
|
160
|
+
'& > :first-child:not(:only-child)': {
|
|
161
|
+
gridColumn: '2 / -1',
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const hideExpandedRowStyle = css({
|
|
166
|
+
display: 'none',
|
|
167
|
+
});
|
|
168
|
+
const dotStyles = css({
|
|
169
|
+
padding: theme.base / 4,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const expandingRowFieldStyles = css({
|
|
173
|
+
display: 'flex',
|
|
174
|
+
padding: theme.base / 4,
|
|
175
|
+
alignItems: 'center',
|
|
176
|
+
});
|
|
177
|
+
|
|
129
178
|
return {
|
|
130
179
|
toggleButtonStyles,
|
|
131
180
|
queryBuilderContainerStyles,
|
|
132
|
-
textAreaStyles,
|
|
133
181
|
buttonGroupStyles,
|
|
134
182
|
ruleContainerStyles,
|
|
135
183
|
ruleGroupContainerBlueStyles,
|
|
@@ -142,5 +190,10 @@ export const getWfoStructuredSearchTableStyles = ({ theme, toSecondaryColor }: W
|
|
|
142
190
|
addRulePlusStyles,
|
|
143
191
|
addRuleContainerStyles,
|
|
144
192
|
addGroupStyles,
|
|
193
|
+
inlineCombinatorStyles,
|
|
194
|
+
ruleGroupBodyGridStyles,
|
|
195
|
+
hideExpandedRowStyle,
|
|
196
|
+
expandingRowFieldStyles,
|
|
197
|
+
dotStyles,
|
|
145
198
|
};
|
|
146
199
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { RuleGroupType } from 'react-querybuilder';
|
|
2
|
+
import { parseCEL } from 'react-querybuilder/parseCEL';
|
|
3
|
+
|
|
4
|
+
export const parseCelToRuleGroup = (celString: string): RuleGroupType | undefined => {
|
|
5
|
+
if (!celString) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const ruleGroup = parseCEL(celString);
|
|
10
|
+
return ruleGroup?.rules?.length > 0 ? ruleGroup : undefined;
|
|
11
|
+
} catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Builds a CEL filter that appends a single column condition (`field == "value"`) to the current
|
|
18
|
+
* filter and returns it together with its parsed rule group. The column name is resolved via
|
|
19
|
+
* getColumnSearchFieldName, falling back to the field key. Returns undefined when the input can't
|
|
20
|
+
* produce a valid filter (empty/quoted search text, or a filter that doesn't parse back to rules).
|
|
21
|
+
*/
|
|
22
|
+
export const buildColumnFilter = <T>(
|
|
23
|
+
field: keyof T,
|
|
24
|
+
searchText: string,
|
|
25
|
+
currentFilter?: string,
|
|
26
|
+
getColumnSearchFieldName?: (field: keyof T) => string,
|
|
27
|
+
): { filterString: string; ruleGroup: RuleGroupType } | undefined => {
|
|
28
|
+
// A double quote in the value would break the `== "..."` CEL literal and parseCEL has no escaping.
|
|
29
|
+
if (!searchText || searchText.includes('"')) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const searchFieldName = getColumnSearchFieldName?.(field) ?? String(field);
|
|
34
|
+
const columnFilterCondition = `${searchFieldName} == "${searchText}"`;
|
|
35
|
+
const trimmedCurrentFilter = currentFilter?.trim();
|
|
36
|
+
const filterString =
|
|
37
|
+
trimmedCurrentFilter ? `(${trimmedCurrentFilter}) && ${columnFilterCondition}` : columnFilterCondition;
|
|
38
|
+
|
|
39
|
+
const ruleGroup = parseCelToRuleGroup(filterString);
|
|
40
|
+
if (!ruleGroup) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { filterString, ruleGroup };
|
|
45
|
+
};
|
|
@@ -82,6 +82,7 @@ export type WfoTableProps<T extends object> = {
|
|
|
82
82
|
rowExpandingConfiguration?: {
|
|
83
83
|
uniqueRowId: keyof WfoTableColumnConfig<T>;
|
|
84
84
|
uniqueRowIdToExpandedRowMap: Record<string, ReactNode>;
|
|
85
|
+
shouldOnlyShowOnHover?: boolean;
|
|
85
86
|
};
|
|
86
87
|
pagination?: Pagination;
|
|
87
88
|
overrideHeader?: (
|
|
@@ -27,8 +27,15 @@ export const WfoTableDataRows = <T extends object>({
|
|
|
27
27
|
onRowClick,
|
|
28
28
|
className,
|
|
29
29
|
}: WfoTableDataRowsProps<T>) => {
|
|
30
|
-
const {
|
|
31
|
-
|
|
30
|
+
const {
|
|
31
|
+
cellStyle,
|
|
32
|
+
cellContentStyle,
|
|
33
|
+
rowStyle,
|
|
34
|
+
dataRowStyle,
|
|
35
|
+
clickableStyle,
|
|
36
|
+
setWidth,
|
|
37
|
+
toggleExpandedRowOnHoverStyle,
|
|
38
|
+
} = useWithOrchestratorTheme(getWfoTableStyles);
|
|
32
39
|
|
|
33
40
|
const sortedVisibleColumns = getSortedVisibleColumns(columnConfig, columnOrder, hiddenColumns);
|
|
34
41
|
|
|
@@ -37,8 +44,13 @@ export const WfoTableDataRows = <T extends object>({
|
|
|
37
44
|
{data.map((row, index) => (
|
|
38
45
|
<Fragment key={`table-data-row-${index}`}>
|
|
39
46
|
<tr
|
|
40
|
-
className={`${className} ${DATA_ROW_CLASS}`}
|
|
41
|
-
css={[
|
|
47
|
+
className={className ? `${className} ${DATA_ROW_CLASS}` : DATA_ROW_CLASS}
|
|
48
|
+
css={[
|
|
49
|
+
rowStyle,
|
|
50
|
+
dataRowStyle,
|
|
51
|
+
onRowClick && clickableStyle,
|
|
52
|
+
rowExpandingConfiguration?.shouldOnlyShowOnHover && toggleExpandedRowOnHoverStyle,
|
|
53
|
+
]}
|
|
42
54
|
onClick={() => onRowClick?.(row)}
|
|
43
55
|
>
|
|
44
56
|
{sortedVisibleColumns.map(([key, columnConfig]) => {
|
|
@@ -31,6 +31,9 @@ export const getWfoTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers)
|
|
|
31
31
|
|
|
32
32
|
const tableContainerStyle = css({
|
|
33
33
|
overflowX: 'auto',
|
|
34
|
+
// Query container so descendants (e.g. expanded rows) can size to the
|
|
35
|
+
// visible table width with cqw units instead of the full table width
|
|
36
|
+
containerType: 'inline-size',
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
const tableStyle = css({
|
|
@@ -157,6 +160,10 @@ export const getWfoTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers)
|
|
|
157
160
|
'.eui-xScroll': { display: 'flex', justifyContent: 'flex-start' },
|
|
158
161
|
});
|
|
159
162
|
|
|
163
|
+
const toggleExpandedRowOnHoverStyle = css({
|
|
164
|
+
'&:hover + tr, &:focus-within + tr': { display: 'table-row' },
|
|
165
|
+
});
|
|
166
|
+
|
|
160
167
|
return {
|
|
161
168
|
tableContainerStyle,
|
|
162
169
|
tableStyle,
|
|
@@ -174,5 +181,6 @@ export const getWfoTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers)
|
|
|
174
181
|
dragAndDropStyle,
|
|
175
182
|
paginationStyle,
|
|
176
183
|
setWidth,
|
|
184
|
+
toggleExpandedRowOnHoverStyle,
|
|
177
185
|
};
|
|
178
186
|
};
|