@orchestrator-ui/orchestrator-ui-components 5.8.1 → 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 (58) hide show
  1. package/.turbo/turbo-build.log +9 -9
  2. package/.turbo/turbo-lint.log +10 -1
  3. package/.turbo/turbo-test.log +11 -11
  4. package/CHANGELOG.md +12 -1
  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 +3175 -169
  9. package/dist/index.js.map +1 -1
  10. package/package.json +13 -9
  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/WfoTree/treeUtils.spec.ts +3 -3
  47. package/src/components/index.ts +2 -0
  48. package/src/configuration/version.ts +1 -1
  49. package/src/hooks/useDebounce.ts +21 -0
  50. package/src/hooks/usePathAutoComplete.ts +133 -0
  51. package/src/hooks/useSearch.ts +83 -0
  52. package/src/hooks/useSearchPagination.ts +148 -0
  53. package/src/hooks/useUrlParams.ts +120 -0
  54. package/src/messages/en-GB.json +77 -0
  55. package/src/rtk/endpoints/index.ts +1 -0
  56. package/src/rtk/endpoints/search.ts +90 -0
  57. package/src/types/index.ts +1 -0
  58. package/src/types/search.ts +215 -0
@@ -0,0 +1,133 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import {
4
+ useSearchDefinitionsQuery,
5
+ useSearchPathsQuery,
6
+ } from '@/rtk/endpoints';
7
+ import { EntityKind, PathInfo, value_schema } from '@/types';
8
+
9
+ import { useDebounce } from './useDebounce';
10
+
11
+ const FALLBACK_DEFINITIONS: Record<
12
+ string,
13
+ {
14
+ operators: string[];
15
+ value_schema: Record<string, value_schema>;
16
+ }
17
+ > = {
18
+ string: {
19
+ operators: ['eq', 'neq'],
20
+ value_schema: {
21
+ eq: { kind: 'string' },
22
+ neq: { kind: 'string' },
23
+ },
24
+ },
25
+ number: {
26
+ operators: ['eq', 'neq', 'lt', 'lte', 'gt', 'gte'],
27
+ value_schema: {
28
+ eq: { kind: 'number' },
29
+ neq: { kind: 'number' },
30
+ lt: { kind: 'number' },
31
+ lte: { kind: 'number' },
32
+ gt: { kind: 'number' },
33
+ gte: { kind: 'number' },
34
+ },
35
+ },
36
+ boolean: {
37
+ operators: ['eq', 'neq'],
38
+ value_schema: {
39
+ eq: { kind: 'boolean' },
40
+ neq: { kind: 'boolean' },
41
+ },
42
+ },
43
+ datetime: {
44
+ operators: ['eq', 'neq', 'lt', 'lte', 'gt', 'gte'],
45
+ value_schema: {
46
+ eq: { kind: 'datetime' },
47
+ neq: { kind: 'datetime' },
48
+ lt: { kind: 'datetime' },
49
+ lte: { kind: 'datetime' },
50
+ gt: { kind: 'datetime' },
51
+ gte: { kind: 'datetime' },
52
+ },
53
+ },
54
+ };
55
+
56
+ export const usePathAutocomplete = (prefix: string, entityType: EntityKind) => {
57
+ const [paths, setPaths] = useState<PathInfo[]>([]);
58
+ const debouncedPrefix = useDebounce(prefix, 300);
59
+
60
+ const { data: definitions = FALLBACK_DEFINITIONS, isError: defError } =
61
+ useSearchDefinitionsQuery();
62
+
63
+ const {
64
+ data: pathData,
65
+ isLoading,
66
+ isError,
67
+ } = useSearchPathsQuery(
68
+ { q: debouncedPrefix, entity_type: entityType },
69
+ { skip: debouncedPrefix.length < 1 },
70
+ );
71
+
72
+ useEffect(() => {
73
+ if (debouncedPrefix.length < 1) {
74
+ setPaths([]);
75
+ return;
76
+ }
77
+
78
+ if (!pathData) {
79
+ return;
80
+ }
81
+
82
+ const enrichedPaths: PathInfo[] = [];
83
+
84
+ // Process leaves first
85
+ (pathData.leaves || []).forEach((leaf) => {
86
+ const primaryType = leaf.ui_types[0] || 'string';
87
+ const typeDefinition = definitions[primaryType];
88
+
89
+ enrichedPaths.push({
90
+ path: leaf.name,
91
+ type: primaryType as
92
+ | 'string'
93
+ | 'number'
94
+ | 'datetime'
95
+ | 'boolean',
96
+ operators: typeDefinition?.operators || [],
97
+ value_schema: typeDefinition?.value_schema || {},
98
+ group: 'leaf',
99
+ displayLabel: leaf.name,
100
+ ui_types: leaf.ui_types,
101
+ availablePaths: leaf.paths || [],
102
+ pathCount: leaf.paths ? leaf.paths.length : 0,
103
+ });
104
+ });
105
+
106
+ (pathData.components || []).forEach((component) => {
107
+ const primaryType = component.ui_types[0] || 'string';
108
+ const typeDefinition = definitions[primaryType];
109
+
110
+ enrichedPaths.push({
111
+ path: component.name,
112
+ type: 'component',
113
+ operators: typeDefinition?.operators || [],
114
+ value_schema: typeDefinition?.value_schema || {},
115
+ group: 'component',
116
+ displayLabel: component.name,
117
+ ui_types: component.ui_types,
118
+ availablePaths: component.paths || [],
119
+ pathCount: component.paths ? component.paths.length : 0,
120
+ });
121
+ });
122
+
123
+ setPaths(enrichedPaths);
124
+ }, [pathData, definitions]);
125
+
126
+ const errorMessage = isError
127
+ ? 'Failed to load paths'
128
+ : defError
129
+ ? 'Failed to load definitions'
130
+ : null;
131
+
132
+ return { paths, loading: isLoading, error: errorMessage };
133
+ };
@@ -0,0 +1,83 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { Query } from '@elastic/eui';
4
+
5
+ import { useSearchMutation } from '@/rtk/endpoints';
6
+ import { EntityKind, Group, PaginatedSearchResults } from '@/types';
7
+
8
+ export const useSearch = (
9
+ query: Query | string,
10
+ entityType: EntityKind,
11
+ filterGroup?: Group,
12
+ limit?: number,
13
+ ) => {
14
+ const [results, setResults] = useState<PaginatedSearchResults>({
15
+ data: [],
16
+ page_info: { has_next_page: false, next_page_cursor: null },
17
+ search_metadata: { search_type: null, description: null },
18
+ });
19
+
20
+ const [triggerSearch, { isLoading, isError }] = useSearchMutation();
21
+
22
+ useEffect(() => {
23
+ const queryText =
24
+ typeof query === 'string' ? query : query.text?.trim() || '';
25
+
26
+ const hasFilters = filterGroup && filterGroup.children.length > 0;
27
+
28
+ if (queryText.length < 2 && !hasFilters) {
29
+ setResults({
30
+ data: [],
31
+ page_info: { has_next_page: false, next_page_cursor: null },
32
+ search_metadata: { search_type: null, description: null },
33
+ });
34
+ return;
35
+ }
36
+
37
+ const performSearch = async () => {
38
+ try {
39
+ const result = await triggerSearch({
40
+ action: 'select',
41
+ entity_type: entityType,
42
+ query: queryText,
43
+ filters:
44
+ filterGroup && filterGroup.children.length > 0
45
+ ? filterGroup
46
+ : undefined,
47
+ limit: limit,
48
+ }).unwrap();
49
+
50
+ setResults({
51
+ data: result.data || [],
52
+ page_info: {
53
+ has_next_page: result.page_info?.has_next_page || false,
54
+ next_page_cursor:
55
+ result.page_info?.next_page_cursor || null,
56
+ },
57
+ search_metadata: {
58
+ search_type:
59
+ result.search_metadata?.search_type || null,
60
+ description:
61
+ result.search_metadata?.description || null,
62
+ },
63
+ });
64
+ } catch (error) {
65
+ console.error('Search error:', error);
66
+ setResults({
67
+ data: [],
68
+ page_info: { has_next_page: false, next_page_cursor: null },
69
+ search_metadata: { search_type: null, description: null },
70
+ });
71
+ }
72
+ };
73
+
74
+ performSearch();
75
+ }, [query, entityType, filterGroup, limit, triggerSearch]);
76
+
77
+ return {
78
+ results,
79
+ loading: isLoading,
80
+ error: isError ? 'Search failed' : null,
81
+ setResults,
82
+ };
83
+ };
@@ -0,0 +1,148 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ import { Query } from '@elastic/eui';
4
+
5
+ import { buildSearchParams } from '@/components/WfoSearchPage/utils';
6
+ import { useSearchWithPaginationMutation } from '@/rtk/endpoints';
7
+ import {
8
+ AnySearchResult,
9
+ EntityKind,
10
+ Group,
11
+ PaginatedSearchResults,
12
+ } from '@/types';
13
+
14
+ interface PageHistoryItem {
15
+ page: number;
16
+ results: AnySearchResult[];
17
+ cursor: number | null;
18
+ }
19
+
20
+ interface UseSearchPaginationReturn {
21
+ currentPage: number;
22
+ pageHistory: PageHistoryItem[];
23
+ error: string | null;
24
+ isLoadingMore: boolean;
25
+ handleNextPage: (nextPageCursor: number) => Promise<void>;
26
+ handlePrevPage: () => void;
27
+ resetPagination: () => void;
28
+ setError: (error: string | null) => void;
29
+ }
30
+
31
+ export const useSearchPagination = (
32
+ debouncedQuery: Query | string,
33
+ selectedEntityTab: EntityKind,
34
+ filterGroup: Group,
35
+ pageSize: number,
36
+ results: PaginatedSearchResults,
37
+ setResults: (results: PaginatedSearchResults) => void,
38
+ ): UseSearchPaginationReturn => {
39
+ const [currentPage, setCurrentPage] = useState<number>(1);
40
+ const [pageHistory, setPageHistory] = useState<PageHistoryItem[]>([]);
41
+ const [error, setError] = useState<string | null>(null);
42
+ const [isLoadingMore, setIsLoadingMore] = useState<boolean>(false);
43
+
44
+ const [triggerSearchPagination] = useSearchWithPaginationMutation();
45
+
46
+ const handleNextPage = useCallback(
47
+ async (nextPageCursor: number) => {
48
+ if (!nextPageCursor || isLoadingMore) return;
49
+
50
+ setIsLoadingMore(true);
51
+
52
+ setPageHistory((prev) => [
53
+ ...prev.filter((p) => p.page !== currentPage),
54
+ {
55
+ page: currentPage,
56
+ results: results.data,
57
+ cursor: results.page_info.next_page_cursor,
58
+ },
59
+ ]);
60
+
61
+ try {
62
+ setError(null);
63
+ const searchParams = buildSearchParams(
64
+ debouncedQuery,
65
+ selectedEntityTab,
66
+ filterGroup,
67
+ pageSize,
68
+ );
69
+
70
+ const res = await triggerSearchPagination({
71
+ ...searchParams,
72
+ cursor: nextPageCursor,
73
+ }).unwrap();
74
+
75
+ setResults({
76
+ data: res.data || [],
77
+ page_info: {
78
+ has_next_page: res.page_info.has_next_page,
79
+ next_page_cursor: res.page_info.next_page_cursor,
80
+ },
81
+ search_metadata: {
82
+ search_type: res.search_metadata.search_type,
83
+ description: res.search_metadata.description,
84
+ },
85
+ });
86
+
87
+ setCurrentPage((prev) => prev + 1);
88
+ } catch (error) {
89
+ const errorMessage =
90
+ error instanceof Error
91
+ ? error.message
92
+ : 'An unexpected error occurred while loading the next page';
93
+ setError(errorMessage);
94
+ console.error('Load next page error:', error);
95
+ } finally {
96
+ setIsLoadingMore(false);
97
+ }
98
+ },
99
+ [
100
+ currentPage,
101
+ results.data,
102
+ results.page_info.next_page_cursor,
103
+ isLoadingMore,
104
+ debouncedQuery,
105
+ selectedEntityTab,
106
+ filterGroup,
107
+ pageSize,
108
+ setResults,
109
+ triggerSearchPagination,
110
+ ],
111
+ );
112
+
113
+ const handlePrevPage = useCallback(() => {
114
+ const previousPage = pageHistory.find(
115
+ (p) => p.page === currentPage - 1,
116
+ );
117
+ if (previousPage) {
118
+ setResults({
119
+ data: previousPage.results,
120
+ page_info: {
121
+ has_next_page: true,
122
+ next_page_cursor: previousPage.cursor,
123
+ },
124
+ search_metadata: results.search_metadata,
125
+ });
126
+
127
+ setCurrentPage((prev) => prev - 1);
128
+
129
+ setPageHistory((prev) => prev.filter((p) => p.page < currentPage));
130
+ }
131
+ }, [currentPage, pageHistory, results.search_metadata, setResults]);
132
+
133
+ const resetPagination = useCallback(() => {
134
+ setCurrentPage(1);
135
+ setPageHistory([]);
136
+ }, []);
137
+
138
+ return {
139
+ currentPage,
140
+ pageHistory,
141
+ error,
142
+ isLoadingMore,
143
+ handleNextPage,
144
+ handlePrevPage,
145
+ resetPagination,
146
+ setError,
147
+ };
148
+ };
@@ -0,0 +1,120 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+
3
+ import { Query } from '@elastic/eui';
4
+
5
+ import { EntityKind } from '@/types';
6
+
7
+ import {
8
+ DEFAULT_ENTITY_TAB,
9
+ VALID_ENTITY_TYPES,
10
+ } from '../components/WfoSearchPage/constants';
11
+
12
+ interface UseUrlParamsReturn {
13
+ urlParams: URLSearchParams;
14
+ query: Query | string;
15
+ selectedEntityTab: EntityKind;
16
+ showFilters: boolean;
17
+ selectedRecordIndex: number;
18
+ selectedRecordId: string | null;
19
+ setQuery: (query: Query | string) => void;
20
+ setSelectedEntityTab: (tab: EntityKind) => void;
21
+ setShowFilters: (show: boolean) => void;
22
+ setSelectedRecordIndex: (index: number) => void;
23
+ setSelectedRecordId: (id: string | null) => void;
24
+ }
25
+
26
+ export const useUrlParams = (): UseUrlParamsReturn => {
27
+ const [urlParams, setUrlParams] = useState(() => {
28
+ if (typeof window !== 'undefined') {
29
+ return new URLSearchParams(window.location.search);
30
+ }
31
+ return new URLSearchParams();
32
+ });
33
+
34
+ const [query, setQuery] = useState<Query | string>(() => {
35
+ const queryParam = urlParams.get('q');
36
+ return queryParam || '';
37
+ });
38
+
39
+ const [selectedEntityTab, setSelectedEntityTab] = useState<EntityKind>(
40
+ () => {
41
+ const tabParam = urlParams.get('tab') as EntityKind;
42
+ return tabParam && VALID_ENTITY_TYPES.includes(tabParam)
43
+ ? tabParam
44
+ : DEFAULT_ENTITY_TAB;
45
+ },
46
+ );
47
+
48
+ const [showFilters, setShowFilters] = useState<boolean>(() => {
49
+ return urlParams.get('filters') === 'true';
50
+ });
51
+
52
+ const [selectedRecordIndex, setSelectedRecordIndex] = useState<number>(
53
+ () => {
54
+ const indexParam = urlParams.get('selected');
55
+ return indexParam ? parseInt(indexParam, 10) || 0 : 0;
56
+ },
57
+ );
58
+
59
+ const [selectedRecordId, setSelectedRecordId] = useState<string | null>(
60
+ () => {
61
+ return urlParams.get('id') || null;
62
+ },
63
+ );
64
+
65
+ const updateUrl = useCallback(() => {
66
+ const newParams = new URLSearchParams();
67
+
68
+ const queryText = typeof query === 'string' ? query : query.text || '';
69
+ if (queryText && queryText !== '*') {
70
+ newParams.set('q', queryText);
71
+ }
72
+
73
+ if (selectedEntityTab !== DEFAULT_ENTITY_TAB) {
74
+ newParams.set('tab', selectedEntityTab);
75
+ }
76
+
77
+ if (showFilters) {
78
+ newParams.set('filters', 'true');
79
+ }
80
+
81
+ if (selectedRecordIndex > 0) {
82
+ newParams.set('selected', selectedRecordIndex.toString());
83
+ }
84
+
85
+ if (selectedRecordId) {
86
+ newParams.set('id', selectedRecordId);
87
+ }
88
+
89
+ const newUrl = newParams.toString()
90
+ ? `${window.location.pathname}?${newParams.toString()}`
91
+ : window.location.pathname;
92
+
93
+ window.history.replaceState({}, '', newUrl);
94
+ setUrlParams(newParams);
95
+ }, [
96
+ query,
97
+ selectedEntityTab,
98
+ showFilters,
99
+ selectedRecordIndex,
100
+ selectedRecordId,
101
+ ]);
102
+
103
+ useEffect(() => {
104
+ updateUrl();
105
+ }, [updateUrl]);
106
+
107
+ return {
108
+ urlParams,
109
+ query,
110
+ selectedEntityTab,
111
+ showFilters,
112
+ selectedRecordIndex,
113
+ selectedRecordId,
114
+ setQuery,
115
+ setSelectedEntityTab,
116
+ setShowFilters,
117
+ setSelectedRecordIndex,
118
+ setSelectedRecordId,
119
+ };
120
+ };
@@ -465,5 +465,82 @@
465
465
  "softwareVersions": "Software Versions",
466
466
  "logout": "Logout",
467
467
  "aoStatusPage": "A&O application status page"
468
+ },
469
+ "agent": {
470
+ "title": "Search results",
471
+ "page": {
472
+ "filledParameters": "Filled parameters",
473
+ "results": "Results",
474
+ "emptyGroup": "Empty group",
475
+ "searchQuery": "Search query",
476
+ "activeFilters": "Active filters",
477
+ "noFiltersApplied": "No filters applied",
478
+ "entityType": "Entity type",
479
+ "action": "Action",
480
+ "copilot": {
481
+ "title": "Database assistant",
482
+ "initial": "Ask me things such as:\n• *Find active subscriptions for Surf*\n• *Show terminated workflows”*\n\nThe filled template and results will appear on the left."
483
+ }
484
+ }
485
+ },
486
+ "search": {
487
+ "page": {
488
+ "selectFieldFirst": "Select a field first",
489
+ "maxNestingDepth": "Maximum nesting depth reached",
490
+ "addNestedGroup": "Add nested group",
491
+ "addCondition": "Add condition",
492
+ "addGroup": "Add group",
493
+ "removeGroup": "Remove group",
494
+ "emptyGroupDescription": "Add conditions or nested groups to build your filter.",
495
+ "emptyGroupTitle": "Empty group",
496
+ "fieldSearchPlaceholder": "Type to search fields...",
497
+ "removeConditionAriaLabel": "Remove condition",
498
+ "groupLabel": "Group",
499
+ "hideFilters": "Hide filters",
500
+ "showFilters": "Show filters",
501
+ "structuredFilters": "Structured filters",
502
+ "searchError": "Error",
503
+ "selectResultInstruction": "Detail content will be implemented here...",
504
+ "showingDetailsForResult": "Showing details for result #{resultNumber}",
505
+ "details": "Details",
506
+ "dismiss": "Dismiss",
507
+ "searchPlaceholder": "Search for {entityType}…",
508
+ "noResults": "No Results",
509
+ "noResultsMessage": "No {entityType} found matching your search criteria.",
510
+ "noResultsSuggestions": "Try adjusting your search terms, removing filters, or searching for different keywords.",
511
+ "noResultsFound": "No results found for your search.",
512
+ "loadingSearchResults": "Loading search results...",
513
+ "previousPage": "Previous page",
514
+ "page": "Page",
515
+ "nextPage": "Next page",
516
+ "resultsOnPage": "{resultCount} result(s) on this page",
517
+ "searchResultsPagination": "Search results pagination",
518
+ "viewDetails": "View details",
519
+ "closeButton": "Close",
520
+ "selectOrEnterValue": "Select or type value",
521
+ "enterValue": "Enter value",
522
+ "fromNumber": "From",
523
+ "toNumber": "To",
524
+ "fromDate": "From date",
525
+ "toDate": "To date",
526
+ "enterNumber": "Enter number",
527
+ "selectDateAndTime": "Select date",
528
+ "valueControlTo": "to",
529
+ "searchFieldsPlaceholder": "Search fields...",
530
+ "selectSpecificPathPlaceholder": "Select a specific path...",
531
+ "anyPathOption": "Any path",
532
+ "operatorLabel": "Operator",
533
+ "fieldLabel": "Field",
534
+ "valueLabel": "Value",
535
+ "fieldsGroupLabel": "Fields",
536
+ "componentsGroupLabel": "Components",
537
+ "pathsCount": "{count} paths"
538
+ },
539
+ "tabs": {
540
+ "subscriptions": "Subscriptions",
541
+ "products": "Products",
542
+ "workflows": "Workflows",
543
+ "processes": "Processes"
544
+ }
468
545
  }
469
546
  }
@@ -20,3 +20,4 @@ export * from './forms';
20
20
  export * from './deprecated';
21
21
  export * from './formFields';
22
22
  export * from './fileUpload';
23
+ export * from './search';
@@ -0,0 +1,90 @@
1
+ import { getEndpointPath } from '@/components/WfoSearchPage/utils';
2
+ import { BaseQueryTypes, orchestratorApi } from '@/rtk';
3
+ import {
4
+ EntityKind,
5
+ Group,
6
+ PaginatedSearchResults,
7
+ PathAutocompleteResponse,
8
+ value_schema,
9
+ } from '@/types';
10
+
11
+ export interface SearchPayload {
12
+ action: 'select';
13
+ entity_type: EntityKind;
14
+ query: string;
15
+ filters?: Group;
16
+ limit?: number;
17
+ }
18
+
19
+ export interface SearchPaginationPayload extends SearchPayload {
20
+ cursor: number;
21
+ }
22
+
23
+ export interface SearchDefinitionsResponse {
24
+ [key: string]: {
25
+ operators: string[];
26
+ value_schema: Record<string, value_schema>;
27
+ };
28
+ }
29
+
30
+ const searchApi = orchestratorApi.injectEndpoints({
31
+ endpoints: (build) => ({
32
+ search: build.mutation<PaginatedSearchResults, SearchPayload>({
33
+ query: (payload) => ({
34
+ url: `search/${getEndpointPath(payload.entity_type)}`,
35
+ method: 'POST',
36
+ body: payload,
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ },
40
+ }),
41
+ extraOptions: {
42
+ baseQueryType: BaseQueryTypes.fetch,
43
+ },
44
+ }),
45
+ searchWithPagination: build.mutation<
46
+ PaginatedSearchResults,
47
+ SearchPaginationPayload
48
+ >({
49
+ query: ({ cursor, ...payload }) => ({
50
+ url: `search/${getEndpointPath(payload.entity_type)}?cursor=${cursor}`,
51
+ method: 'POST',
52
+ body: payload,
53
+ headers: {
54
+ 'Content-Type': 'application/json',
55
+ },
56
+ }),
57
+ extraOptions: {
58
+ baseQueryType: BaseQueryTypes.fetch,
59
+ },
60
+ }),
61
+ searchPaths: build.query<
62
+ PathAutocompleteResponse,
63
+ { q: string; entity_type: EntityKind }
64
+ >({
65
+ query: ({ q, entity_type }) => ({
66
+ url: `search/paths?q=${encodeURIComponent(q)}&entity_type=${entity_type}`,
67
+ method: 'GET',
68
+ }),
69
+ extraOptions: {
70
+ baseQueryType: BaseQueryTypes.fetch,
71
+ },
72
+ }),
73
+ searchDefinitions: build.query<SearchDefinitionsResponse, void>({
74
+ query: () => ({
75
+ url: 'search/definitions',
76
+ method: 'GET',
77
+ }),
78
+ extraOptions: {
79
+ baseQueryType: BaseQueryTypes.fetch,
80
+ },
81
+ }),
82
+ }),
83
+ });
84
+
85
+ export const {
86
+ useSearchMutation,
87
+ useSearchWithPaginationMutation,
88
+ useSearchPathsQuery,
89
+ useSearchDefinitionsQuery,
90
+ } = searchApi;
@@ -1,3 +1,4 @@
1
1
  export * from './types';
2
2
  export * from './deprecated';
3
3
  export * from './forms';
4
+ export * from './search';