@orchestrator-ui/orchestrator-ui-components 5.9.0 → 6.0.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.
Files changed (57) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +10 -1
  3. package/.turbo/turbo-test.log +8 -8
  4. package/CHANGELOG.md +6 -0
  5. package/__mocks__/@copilotkit/react-core.js +9 -0
  6. package/__mocks__/@copilotkit/react-ui.js +11 -0
  7. package/dist/index.d.ts +1429 -2
  8. package/dist/index.js +2977 -19
  9. package/dist/index.js.map +1 -1
  10. package/package.json +5 -1
  11. package/src/components/WfoAgent/FilterDisplay/FilterDisplay.tsx +182 -0
  12. package/src/components/WfoAgent/FilterDisplay/index.ts +1 -0
  13. package/src/components/WfoAgent/FilterDisplay/styles.ts +62 -0
  14. package/src/components/WfoAgent/WfoAgent/WfoAgent.tsx +100 -0
  15. package/src/components/WfoAgent/WfoAgent/index.ts +1 -0
  16. package/src/components/WfoAgent/index.ts +2 -0
  17. package/src/components/WfoSearchPage/WfoConditionRow/WfoConditionRow.tsx +388 -0
  18. package/src/components/WfoSearchPage/WfoConditionRow/WfoFieldSelector.tsx +43 -0
  19. package/src/components/WfoSearchPage/WfoConditionRow/WfoOperatorSelector.tsx +100 -0
  20. package/src/components/WfoSearchPage/WfoConditionRow/WfoPathChips.tsx +193 -0
  21. package/src/components/WfoSearchPage/WfoConditionRow/WfoPathSelector.tsx +54 -0
  22. package/src/components/WfoSearchPage/WfoConditionRow/WfoRenderFunctions.tsx +107 -0
  23. package/src/components/WfoSearchPage/WfoConditionRow/WfoSelectedPathDisplay.tsx +75 -0
  24. package/src/components/WfoSearchPage/WfoConditionRow/index.ts +11 -0
  25. package/src/components/WfoSearchPage/WfoConditionRow/types.ts +84 -0
  26. package/src/components/WfoSearchPage/WfoConditionRow/utils.ts +63 -0
  27. package/src/components/WfoSearchPage/WfoFilterGroup/WfoFilterGroup.tsx +238 -0
  28. package/src/components/WfoSearchPage/WfoFilterGroup/index.ts +1 -0
  29. package/src/components/WfoSearchPage/WfoSearch/WfoSearch.tsx +453 -0
  30. package/src/components/WfoSearchPage/WfoSearch/index.ts +1 -0
  31. package/src/components/WfoSearchPage/WfoSearchResults/WfoHighlightedText.tsx +63 -0
  32. package/src/components/WfoSearchPage/WfoSearchResults/WfoPathBreadcrumb.tsx +80 -0
  33. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchEmptyState.tsx +24 -0
  34. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchLoadingState.tsx +24 -0
  35. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchMetadataHeader.tsx +24 -0
  36. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchPaginationInfo.tsx +107 -0
  37. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchResultItem.tsx +157 -0
  38. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchResults.tsx +65 -0
  39. package/src/components/WfoSearchPage/WfoSearchResults/WfoSubscriptionDetailModal.tsx +55 -0
  40. package/src/components/WfoSearchPage/WfoSearchResults/index.ts +10 -0
  41. package/src/components/WfoSearchPage/WfoValueControl/WfoValueControl.tsx +247 -0
  42. package/src/components/WfoSearchPage/WfoValueControl/index.ts +1 -0
  43. package/src/components/WfoSearchPage/constants.ts +17 -0
  44. package/src/components/WfoSearchPage/index.ts +6 -0
  45. package/src/components/WfoSearchPage/utils.ts +271 -0
  46. package/src/components/index.ts +2 -0
  47. package/src/configuration/version.ts +1 -1
  48. package/src/hooks/useDebounce.ts +21 -0
  49. package/src/hooks/usePathAutoComplete.ts +133 -0
  50. package/src/hooks/useSearch.ts +83 -0
  51. package/src/hooks/useSearchPagination.ts +148 -0
  52. package/src/hooks/useUrlParams.ts +120 -0
  53. package/src/messages/en-GB.json +77 -0
  54. package/src/rtk/endpoints/index.ts +1 -0
  55. package/src/rtk/endpoints/search.ts +90 -0
  56. package/src/types/index.ts +1 -0
  57. package/src/types/search.ts +215 -0
@@ -0,0 +1,238 @@
1
+ import React, { FC } from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import {
6
+ EuiButton,
7
+ EuiButtonIcon,
8
+ EuiCallOut,
9
+ EuiCode,
10
+ EuiFlexGroup,
11
+ EuiFlexItem,
12
+ EuiPanel,
13
+ EuiSpacer,
14
+ EuiText,
15
+ } from '@elastic/eui';
16
+
17
+ import { WfoToolTip } from '@/components';
18
+ import { isCondition } from '@/components/WfoSearchPage/utils';
19
+ import { useOrchestratorTheme } from '@/hooks';
20
+ import { Condition, EntityKind, Group } from '@/types';
21
+
22
+ import { ConditionRow } from '../WfoConditionRow';
23
+
24
+ interface FilterGroupProps {
25
+ group: Group;
26
+ entityType: EntityKind;
27
+ onChange: (group: Group) => void;
28
+ onRemove?: () => void;
29
+ depth?: number;
30
+ isRoot?: boolean;
31
+ }
32
+
33
+ export const FilterGroup: FC<FilterGroupProps> = ({
34
+ group,
35
+ entityType,
36
+ onChange,
37
+ onRemove,
38
+ depth = 0,
39
+ isRoot = false,
40
+ }) => {
41
+ const t = useTranslations('search.page');
42
+
43
+ const { theme } = useOrchestratorTheme();
44
+ const MAX_DEPTH = 5;
45
+ const canAddGroup = depth < MAX_DEPTH;
46
+
47
+ const addCondition = () => {
48
+ const newCondition: Condition = {
49
+ path: '',
50
+ condition: { op: '', value: undefined },
51
+ };
52
+ onChange({
53
+ ...group,
54
+ children: [...group.children, newCondition],
55
+ });
56
+ };
57
+
58
+ const addGroup = () => {
59
+ if (!canAddGroup) return;
60
+
61
+ const newGroup: Group = {
62
+ op: 'AND',
63
+ children: [],
64
+ };
65
+ onChange({
66
+ ...group,
67
+ children: [...group.children, newGroup],
68
+ });
69
+ };
70
+
71
+ const updateChild = (index: number, child: Group | Condition) => {
72
+ const newChildren = [...group.children];
73
+ newChildren[index] = child;
74
+ onChange({
75
+ ...group,
76
+ children: newChildren,
77
+ });
78
+ };
79
+
80
+ const removeChild = (index: number) => {
81
+ onChange({
82
+ ...group,
83
+ children: group.children.filter((_, i) => i !== index),
84
+ });
85
+ };
86
+
87
+ const toggleOperator = () => {
88
+ onChange({
89
+ ...group,
90
+ op: group.op === 'AND' ? 'OR' : 'AND',
91
+ });
92
+ };
93
+
94
+ return (
95
+ <EuiPanel
96
+ paddingSize="m"
97
+ color={depth % 2 === 0 ? 'primary' : 'plain'}
98
+ hasBorder
99
+ >
100
+ <EuiFlexGroup
101
+ gutterSize="s"
102
+ alignItems="center"
103
+ justifyContent="spaceBetween"
104
+ >
105
+ <EuiFlexItem grow={false}>
106
+ <EuiFlexGroup gutterSize="s" alignItems="center">
107
+ <EuiFlexItem grow={false}>
108
+ <EuiText size="s">
109
+ <strong>{t('groupLabel')}</strong>
110
+ </EuiText>
111
+ </EuiFlexItem>
112
+ <EuiFlexItem grow={false}>
113
+ <EuiButton
114
+ size="s"
115
+ fill={true}
116
+ color="primary"
117
+ onClick={toggleOperator}
118
+ >
119
+ {group.op}
120
+ </EuiButton>
121
+ </EuiFlexItem>
122
+ </EuiFlexGroup>
123
+ </EuiFlexItem>
124
+
125
+ <EuiFlexItem grow={false}>
126
+ <EuiFlexGroup gutterSize="s" alignItems="center">
127
+ <EuiFlexItem grow={false}>
128
+ <EuiButton
129
+ size="s"
130
+ iconType="plusInCircle"
131
+ onClick={addCondition}
132
+ >
133
+ {t('addCondition')}
134
+ </EuiButton>
135
+ </EuiFlexItem>
136
+ <EuiFlexItem grow={false}>
137
+ <WfoToolTip
138
+ tooltipContent={
139
+ !canAddGroup
140
+ ? t('maxNestingDepth')
141
+ : t('addNestedGroup')
142
+ }
143
+ >
144
+ <EuiButton
145
+ size="s"
146
+ iconType="nested"
147
+ onClick={addGroup}
148
+ disabled={!canAddGroup}
149
+ >
150
+ {t('addGroup')}
151
+ </EuiButton>
152
+ </WfoToolTip>
153
+ </EuiFlexItem>
154
+ {!isRoot && onRemove && (
155
+ <EuiFlexItem grow={false}>
156
+ <EuiButtonIcon
157
+ iconType="trash"
158
+ color="danger"
159
+ onClick={onRemove}
160
+ aria-label={t('removeGroup')}
161
+ />
162
+ </EuiFlexItem>
163
+ )}
164
+ </EuiFlexGroup>
165
+ </EuiFlexItem>
166
+ </EuiFlexGroup>
167
+
168
+ {group.children.length > 0 && (
169
+ <>
170
+ <EuiSpacer size="m" />
171
+ <EuiPanel
172
+ paddingSize={isRoot ? 'none' : 's'}
173
+ color="transparent"
174
+ hasShadow={false}
175
+ >
176
+ {group.children.map((child, index) => (
177
+ <div key={index}>
178
+ {index > 0 && (
179
+ <EuiFlexGroup
180
+ gutterSize="none"
181
+ alignItems="center"
182
+ justifyContent="center"
183
+ >
184
+ <EuiFlexItem grow={false}>
185
+ <EuiText
186
+ size="s"
187
+ color={theme.colors.textSubdued}
188
+ textAlign="center"
189
+ >
190
+ <EuiCode>{group.op}</EuiCode>
191
+ </EuiText>
192
+ </EuiFlexItem>
193
+ </EuiFlexGroup>
194
+ )}
195
+ <EuiSpacer size="s" />
196
+ {isCondition(child) ? (
197
+ <ConditionRow
198
+ condition={child}
199
+ entityType={entityType}
200
+ onChange={(newCondition) =>
201
+ updateChild(index, newCondition)
202
+ }
203
+ onRemove={() => removeChild(index)}
204
+ />
205
+ ) : (
206
+ <FilterGroup
207
+ group={child}
208
+ entityType={entityType}
209
+ onChange={(newGroup) =>
210
+ updateChild(index, newGroup)
211
+ }
212
+ onRemove={() => removeChild(index)}
213
+ depth={depth + 1}
214
+ />
215
+ )}
216
+ <EuiSpacer size="s" />
217
+ </div>
218
+ ))}
219
+ </EuiPanel>
220
+ </>
221
+ )}
222
+
223
+ {group.children.length === 0 && (
224
+ <>
225
+ <EuiSpacer size="s" />
226
+ <EuiCallOut
227
+ title={t('emptyGroupTitle')}
228
+ color="primary"
229
+ iconType="iInCircle"
230
+ size="s"
231
+ >
232
+ <p>{t('emptyGroupDescription')}</p>
233
+ </EuiCallOut>
234
+ </>
235
+ )}
236
+ </EuiPanel>
237
+ );
238
+ };
@@ -0,0 +1 @@
1
+ export { FilterGroup } from './WfoFilterGroup';
@@ -0,0 +1,453 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import {
6
+ EuiButton,
7
+ EuiCallOut,
8
+ EuiFieldSearch,
9
+ EuiFlexGroup,
10
+ EuiFlexItem,
11
+ EuiPanel,
12
+ EuiSpacer,
13
+ EuiTab,
14
+ EuiTabs,
15
+ EuiText,
16
+ } from '@elastic/eui';
17
+
18
+ import { WfoSubscription } from '@/components';
19
+ import { WfoBadge } from '@/components/WfoBadges';
20
+ import {
21
+ ENTITY_TABS,
22
+ findResultIndexById,
23
+ getRecordId,
24
+ isSubscriptionSearchResult,
25
+ } from '@/components/WfoSearchPage/utils';
26
+ import { TreeProvider } from '@/contexts';
27
+ import { useOrchestratorTheme } from '@/hooks';
28
+ import { useDebounce } from '@/hooks/useDebounce';
29
+ import { useSearch } from '@/hooks/useSearch';
30
+ import { useSearchPagination } from '@/hooks/useSearchPagination';
31
+ import { useUrlParams } from '@/hooks/useUrlParams';
32
+ import { EntityKind, Group } from '@/types';
33
+
34
+ import { FilterGroup } from '../WfoFilterGroup';
35
+ import { WfoSearchResults } from '../WfoSearchResults';
36
+ import { WfoSearchMetadataHeader } from '../WfoSearchResults/WfoSearchMetadataHeader';
37
+ import { WfoSearchPaginationInfo } from '../WfoSearchResults/WfoSearchPaginationInfo';
38
+ import {
39
+ DEFAULT_DEBOUNCE_DELAY,
40
+ DEFAULT_PAGE_SIZE,
41
+ LAYOUT_RATIOS,
42
+ SMALL_RESULT_THRESHOLD,
43
+ } from '../constants';
44
+
45
+ export const WfoSearch = () => {
46
+ const t = useTranslations('search.page');
47
+ const { theme } = useOrchestratorTheme();
48
+ const {
49
+ urlParams,
50
+ query,
51
+ selectedEntityTab,
52
+ showFilters,
53
+ selectedRecordIndex,
54
+ selectedRecordId,
55
+ setQuery,
56
+ setSelectedEntityTab,
57
+ setShowFilters,
58
+ setSelectedRecordIndex,
59
+ setSelectedRecordId,
60
+ } = useUrlParams();
61
+
62
+ const pageSize = DEFAULT_PAGE_SIZE;
63
+
64
+ const [filterGroup, setFilterGroup] = useState<Group>({
65
+ op: 'AND',
66
+ children: [],
67
+ });
68
+
69
+ const [showDetailPanel, setShowDetailPanel] = useState<boolean>(false);
70
+
71
+ const debouncedQuery = useDebounce(query, DEFAULT_DEBOUNCE_DELAY);
72
+ const { results, loading, setResults } = useSearch(
73
+ debouncedQuery,
74
+ selectedEntityTab,
75
+ filterGroup,
76
+ pageSize,
77
+ );
78
+
79
+ const [hasSearchBeenAttempted, setHasSearchBeenAttempted] = useState(false);
80
+
81
+ useEffect(() => {
82
+ const queryText =
83
+ typeof debouncedQuery === 'string'
84
+ ? debouncedQuery
85
+ : debouncedQuery?.text?.trim() || '';
86
+ const hasFilters = filterGroup && filterGroup.children.length > 0;
87
+
88
+ if (queryText.length >= 2 || hasFilters) {
89
+ setHasSearchBeenAttempted(true);
90
+ } else if (queryText === '' || queryText === '*') {
91
+ setHasSearchBeenAttempted(false);
92
+ }
93
+ }, [debouncedQuery, filterGroup]);
94
+
95
+ const {
96
+ currentPage,
97
+ error,
98
+ isLoadingMore,
99
+ handleNextPage,
100
+ handlePrevPage,
101
+ resetPagination,
102
+ setError,
103
+ } = useSearchPagination(
104
+ debouncedQuery,
105
+ selectedEntityTab,
106
+ filterGroup,
107
+ pageSize,
108
+ results,
109
+ setResults,
110
+ );
111
+
112
+ const [searchValue, setSearchValue] = useState(() => {
113
+ // For EuiSearchBar, we need to preserve the original query structure
114
+ if (typeof query === 'string') {
115
+ return query;
116
+ }
117
+ const queryText = query.text || '';
118
+ return queryText;
119
+ });
120
+
121
+ const handleTabChange = (tabId: EntityKind) => {
122
+ setSelectedEntityTab(tabId);
123
+ setQuery('');
124
+ setSearchValue('');
125
+ setFilterGroup({
126
+ op: 'AND',
127
+ children: [],
128
+ });
129
+ setResults({
130
+ data: [],
131
+ page_info: {
132
+ has_next_page: false,
133
+ next_page_cursor: null,
134
+ },
135
+ search_metadata: {
136
+ search_type: null,
137
+ description: null,
138
+ },
139
+ });
140
+ setSelectedRecordIndex(0);
141
+ setShowDetailPanel(false);
142
+ resetPagination();
143
+ };
144
+
145
+ const onSearchChange = (searchText: string) => {
146
+ const cleanedText = searchText.replace(/[=><[\]{}\\/#$%^&+]/g, '');
147
+
148
+ setSearchValue(cleanedText);
149
+ setQuery(cleanedText.trim() || '');
150
+ };
151
+
152
+ useEffect(() => {
153
+ if (typeof query === 'string') {
154
+ if (query !== searchValue) {
155
+ setSearchValue(query);
156
+ }
157
+ } else {
158
+ const queryText = query.text || '';
159
+ if (queryText !== searchValue) {
160
+ setSearchValue(queryText);
161
+ }
162
+ }
163
+ }, [query, searchValue]);
164
+
165
+ const currentTab = ENTITY_TABS.find((tab) => tab.id === selectedEntityTab);
166
+
167
+ const isSearchActive = results.data.length > 0 || loading;
168
+
169
+ const shouldShowNoResults = (() => {
170
+ // Only show no results banner if a search was actually attempted
171
+ return hasSearchBeenAttempted && !loading && results.data.length === 0;
172
+ })();
173
+
174
+ useEffect(() => {
175
+ if (results.data.length > 0) {
176
+ if (selectedRecordId) {
177
+ const foundIndex = findResultIndexById(
178
+ results.data,
179
+ selectedRecordId,
180
+ );
181
+
182
+ if (foundIndex !== -1) {
183
+ setSelectedRecordIndex(foundIndex);
184
+ } else if (results.data.length <= SMALL_RESULT_THRESHOLD) {
185
+ setSelectedRecordIndex(0);
186
+ setSelectedRecordId(null);
187
+ }
188
+ } else if (results.data.length <= SMALL_RESULT_THRESHOLD) {
189
+ const indexFromUrl = urlParams.get('selected');
190
+ if (!indexFromUrl) {
191
+ setSelectedRecordIndex(0);
192
+ }
193
+ }
194
+ }
195
+ }, [results.data, selectedRecordId, urlParams]);
196
+
197
+ useEffect(() => {
198
+ setShowDetailPanel(
199
+ results?.data?.length > 0 && selectedRecordIndex >= 0,
200
+ );
201
+ }, [results?.data?.length, selectedRecordIndex]);
202
+
203
+ useEffect(() => {
204
+ resetPagination();
205
+ }, [debouncedQuery, selectedEntityTab, filterGroup, resetPagination]);
206
+
207
+ const { RESULTS_GROW, DETAIL_GROW } = LAYOUT_RATIOS;
208
+
209
+ return (
210
+ <>
211
+ <EuiTabs>
212
+ {ENTITY_TABS.map((tab) => (
213
+ <EuiTab
214
+ key={tab.id}
215
+ onClick={() => handleTabChange(tab.id)}
216
+ isSelected={selectedEntityTab === tab.id}
217
+ >
218
+ {tab.label}
219
+ </EuiTab>
220
+ ))}
221
+ </EuiTabs>
222
+ <EuiSpacer size="m" />
223
+
224
+ <EuiFieldSearch
225
+ placeholder={t('searchPlaceholder', {
226
+ entityType: currentTab?.label.toLowerCase(),
227
+ })}
228
+ value={searchValue || ''}
229
+ onChange={(event) => {
230
+ onSearchChange(event.target.value);
231
+ }}
232
+ onSearch={(value) => {
233
+ onSearchChange(value);
234
+ }}
235
+ incremental={true}
236
+ fullWidth
237
+ />
238
+
239
+ <EuiSpacer size="s" />
240
+
241
+ <EuiFlexGroup gutterSize="s" alignItems="center">
242
+ <EuiFlexItem grow={false}>
243
+ <EuiButton
244
+ iconType={showFilters ? 'eyeClosed' : 'eye'}
245
+ size="s"
246
+ onClick={() => setShowFilters(!showFilters)}
247
+ >
248
+ {showFilters ? t('hideFilters') : t('showFilters')}
249
+ </EuiButton>
250
+ </EuiFlexItem>
251
+ </EuiFlexGroup>
252
+
253
+ {showFilters && (
254
+ <>
255
+ <EuiSpacer size="m" />
256
+ <EuiPanel hasBorder paddingSize="m">
257
+ <EuiText>
258
+ <h4>{t('structuredFilters')}</h4>
259
+ </EuiText>
260
+ <EuiSpacer size="s" />
261
+ <FilterGroup
262
+ group={filterGroup}
263
+ entityType={selectedEntityTab}
264
+ onChange={setFilterGroup}
265
+ isRoot
266
+ />
267
+ </EuiPanel>
268
+ </>
269
+ )}
270
+
271
+ <EuiSpacer size="m" />
272
+
273
+ {error && (
274
+ <>
275
+ <EuiCallOut
276
+ title={t('searchError')}
277
+ color="danger"
278
+ iconType="alert"
279
+ size="s"
280
+ >
281
+ <p>{error}</p>
282
+ <EuiButton
283
+ size="s"
284
+ color="danger"
285
+ onClick={() => setError(null)}
286
+ >
287
+ {t('dismiss')}
288
+ </EuiButton>
289
+ </EuiCallOut>
290
+ <EuiSpacer size="m" />
291
+ </>
292
+ )}
293
+
294
+ {shouldShowNoResults && (
295
+ <>
296
+ <EuiSpacer size="l" />
297
+ <EuiCallOut
298
+ title={t('noResults')}
299
+ color="primary"
300
+ iconType="search"
301
+ size="m"
302
+ >
303
+ <p>
304
+ {t('noResultsMessage', {
305
+ entityType: currentTab?.label.toLowerCase(),
306
+ })}
307
+ </p>
308
+ <EuiSpacer size="s" />
309
+ <EuiText size="s" color="subdued">
310
+ <p>{t('noResultsSuggestions')}</p>
311
+ </EuiText>
312
+ </EuiCallOut>
313
+ <EuiSpacer size="l" />
314
+ </>
315
+ )}
316
+
317
+ {isSearchActive && (
318
+ <>
319
+ <EuiSpacer size="m" />
320
+
321
+ <EuiFlexGroup gutterSize="s" alignItems="center">
322
+ <EuiFlexItem grow={showDetailPanel ? RESULTS_GROW : 1}>
323
+ <EuiFlexGroup
324
+ gutterSize="s"
325
+ alignItems="center"
326
+ justifyContent="spaceBetween"
327
+ responsive={false}
328
+ style={{ width: '100%' }}
329
+ >
330
+ <EuiFlexItem grow={false}>
331
+ <WfoSearchMetadataHeader
332
+ search_metadata={
333
+ results.search_metadata
334
+ }
335
+ />
336
+ </EuiFlexItem>
337
+
338
+ <EuiFlexItem grow={false}>
339
+ <WfoSearchPaginationInfo
340
+ has_next_page={
341
+ results.page_info.has_next_page
342
+ }
343
+ next_page_cursor={
344
+ results.page_info.next_page_cursor
345
+ }
346
+ onNextPage={handleNextPage}
347
+ onPrevPage={handlePrevPage}
348
+ isLoading={isLoadingMore}
349
+ currentPage={currentPage}
350
+ hasPrevPage={currentPage > 1}
351
+ resultCount={results?.data?.length || 0}
352
+ />
353
+ </EuiFlexItem>
354
+ </EuiFlexGroup>
355
+ </EuiFlexItem>
356
+
357
+ {showDetailPanel && <EuiFlexItem grow={DETAIL_GROW} />}
358
+ </EuiFlexGroup>
359
+
360
+ <EuiSpacer size="s" />
361
+
362
+ <EuiFlexGroup gutterSize="s" alignItems="flexStart">
363
+ <EuiFlexItem grow={showDetailPanel ? RESULTS_GROW : 1}>
364
+ <EuiPanel paddingSize="none" hasBorder={true}>
365
+ <WfoSearchResults
366
+ results={results.data}
367
+ loading={loading}
368
+ selectedRecordIndex={selectedRecordIndex}
369
+ onRecordSelect={(index: number) => {
370
+ setSelectedRecordIndex(index);
371
+ const record = results.data[index];
372
+ if (record) {
373
+ const recordId =
374
+ getRecordId(record);
375
+ setSelectedRecordId(recordId);
376
+ }
377
+ }}
378
+ />
379
+ </EuiPanel>
380
+ </EuiFlexItem>
381
+
382
+ {showDetailPanel && (
383
+ <EuiFlexItem grow={DETAIL_GROW}>
384
+ <EuiPanel
385
+ paddingSize="m"
386
+ hasBorder={true}
387
+ hasShadow={false}
388
+ color="transparent"
389
+ >
390
+ {selectedEntityTab === 'SUBSCRIPTION' &&
391
+ results.data[selectedRecordIndex] &&
392
+ isSubscriptionSearchResult(
393
+ results.data[selectedRecordIndex],
394
+ ) ? (
395
+ <TreeProvider>
396
+ <WfoSubscription
397
+ subscriptionId={
398
+ results.data[
399
+ selectedRecordIndex
400
+ ].subscription
401
+ .subscription_id
402
+ }
403
+ />
404
+ </TreeProvider>
405
+ ) : (
406
+ <>
407
+ <EuiText>
408
+ <h4>{t('details')}</h4>
409
+ </EuiText>
410
+ <EuiSpacer size="m" />
411
+ <EuiText
412
+ color={theme.colors.textSubdued}
413
+ >
414
+ <p>
415
+ {t(
416
+ 'showingDetailsForResult',
417
+ {
418
+ resultNumber:
419
+ selectedRecordIndex +
420
+ 1,
421
+ },
422
+ )}
423
+ </p>
424
+ <EuiSpacer size="s" />
425
+ <WfoBadge
426
+ color={theme.colors.primary}
427
+ textColor={
428
+ theme.colors.ghost
429
+ }
430
+ >
431
+ {selectedEntityTab} #
432
+ {selectedRecordIndex + 1}
433
+ </WfoBadge>
434
+ <EuiSpacer size="m" />
435
+ <p>
436
+ <em>
437
+ {t(
438
+ 'selectResultInstruction',
439
+ )}
440
+ </em>
441
+ </p>
442
+ </EuiText>
443
+ </>
444
+ )}
445
+ </EuiPanel>
446
+ </EuiFlexItem>
447
+ )}
448
+ </EuiFlexGroup>
449
+ </>
450
+ )}
451
+ </>
452
+ );
453
+ };
@@ -0,0 +1 @@
1
+ export { WfoSearch } from './WfoSearch';