@orchestrator-ui/orchestrator-ui-components 0.2.6 → 0.3.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 +6 -6
- package/.turbo/turbo-lint.log +0 -6
- package/.turbo/turbo-test.log +9 -8
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +1005 -123
- package/dist/index.js +33996 -6348
- package/package.json +14 -12
- package/src/api/index.ts +55 -3
- package/src/components/WfoDiff/WfoDiff.tsx +119 -0
- package/src/components/WfoDiff/index.ts +1 -0
- package/src/components/WfoDiff/unidiff.d.ts +1 -0
- package/src/components/WfoForms/AutoFieldLoader.tsx +5 -1
- package/src/components/WfoForms/CreateForm.tsx +1 -1
- package/src/components/WfoForms/UserInputForm.tsx +75 -43
- package/src/components/WfoForms/UserInputFormWizard.tsx +11 -4
- package/src/components/WfoForms/formFields/AcceptField.tsx +8 -5
- package/src/components/WfoForms/formFields/BoolField.tsx +1 -1
- package/src/components/WfoForms/formFields/ImsNodeIdField.tsx +2 -2
- package/src/components/WfoForms/formFields/ImsPortIdField.tsx +238 -0
- package/src/components/WfoForms/formFields/ImsPortIdFieldStyling.ts +17 -0
- package/src/components/WfoForms/formFields/IpPrefixTableField.tsx +1 -1
- package/src/components/WfoForms/formFields/ListAddField.tsx +1 -1
- package/src/components/WfoForms/formFields/ListDelField.tsx +1 -1
- package/src/components/WfoForms/formFields/OptGroupField.tsx +1 -1
- package/src/components/WfoForms/formFields/SubscriptionField.tsx +2 -1
- package/src/components/WfoForms/formFields/SummaryField.tsx +103 -0
- package/src/components/WfoForms/formFields/SummaryFieldStyling.ts +46 -0
- package/src/components/WfoForms/formFields/VlanField.tsx +10 -10
- package/src/components/WfoForms/formFields/index.ts +2 -0
- package/src/components/WfoForms/formFields/surf/types.ts +26 -0
- package/src/components/WfoForms/formFields/utils.spec.ts +1 -0
- package/src/components/WfoJsonCodeBlock/index.ts +1 -0
- package/src/components/WfoPageTemplate/WfoPageHeader/WfoPageHeader.tsx +4 -3
- package/src/components/WfoPageTemplate/WfoSidebar/WfoSidebar.tsx +14 -14
- package/src/components/WfoPageTemplate/WfoSidebar/WfoStartCreateWorkflowButtonComboBox.tsx +15 -9
- package/src/components/WfoPageTemplate/paths.ts +3 -2
- package/src/components/{WfoProcessesList → WfoProcessList}/WfoProcessList.tsx +18 -14
- package/src/components/WfoProcessList/index.ts +1 -0
- package/src/components/{WfoProcessesList → WfoProcessList}/processListObjectMappers.ts +4 -2
- package/src/components/WfoSearchBar/WfoSearchField.tsx +27 -37
- package/src/components/{WfoSettingsPage → WfoSettings}/WfoEngineStatusButton.tsx +7 -4
- package/src/components/{WfoSettingsPage → WfoSettings}/WfoFlushSettings.tsx +13 -12
- package/src/components/WfoSettings/WfoModifySettings.tsx +38 -0
- package/src/components/WfoSettings/WfoSettings.tsx +40 -0
- package/src/components/{WfoSettingsPage → WfoSettings}/WfoStatus.tsx +21 -14
- package/src/components/WfoStartPage/WfoListStartPage.tsx +3 -3
- package/src/components/WfoStartTaskButtonComboBox/WfoStartTaskButtonComboBox.tsx +14 -8
- package/src/components/WfoSubscription/WfoProcessesTimeline.tsx +11 -18
- package/src/components/WfoSubscription/WfoSubscription.tsx +1 -1
- package/src/components/WfoSubscription/WfoSubscriptionActions.tsx +41 -33
- package/src/components/WfoSubscription/WfoSubscriptionDetailTree.tsx +32 -22
- package/src/components/WfoSubscription/WfoSubscriptionProductBlock.tsx +94 -90
- package/src/components/WfoSubscription/WfoTargetTypeIcon.tsx +26 -0
- package/src/components/WfoSubscription/utils/utils.spec.ts +24 -0
- package/src/components/WfoSubscription/utils/utils.ts +16 -0
- package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +17 -37
- package/src/components/WfoTable/WfoTableWithFilter/WfoTableWithFilter.tsx +20 -19
- package/src/components/WfoTable/WfoTableWithFilter/updateQueryString.spec.ts +95 -0
- package/src/components/WfoTable/WfoTableWithFilter/updateQueryString.ts +60 -0
- package/src/components/WfoTable/utils/tableUtils.ts +3 -3
- package/src/components/WfoTextAnchor/WfoTextAnchor.stories.tsx +18 -0
- package/src/components/WfoTextAnchor/WfoTextAnchor.tsx +22 -0
- package/src/components/WfoTextAnchor/index.ts +1 -0
- package/src/components/WfoTextAnchor/styles.ts +17 -0
- package/src/components/WfoTimeline/styles.ts +10 -4
- package/src/components/WfoWorkflowSteps/WfoStep/WfoStep.tsx +39 -24
- package/src/components/WfoWorkflowSteps/WfoStep/WfoStepForm.tsx +48 -0
- package/src/components/WfoWorkflowSteps/WfoStepList/WfoStepList.tsx +14 -11
- package/src/components/WfoWorkflowSteps/WfoWorkflowStepList/WfoStepListHeader.tsx +22 -23
- package/src/components/WfoWorkflowSteps/WfoWorkflowStepList/WfoWorkflowStepList.tsx +97 -17
- package/src/components/WfoWorkflowSteps/stepListUtils.ts +1 -28
- package/src/components/confirmationDialog/WfoConfirmationDialog.tsx +3 -3
- package/src/components/index.ts +6 -1
- package/src/contexts/ConfirmationDialogProvider.tsx +2 -2
- package/src/contexts/TreeContext.tsx +5 -0
- package/src/graphqlQueries/index.ts +1 -0
- package/src/graphqlQueries/processDetailQuery.ts +8 -0
- package/src/graphqlQueries/processListQuery.ts +7 -6
- package/src/graphqlQueries/processStepsQuery.ts +22 -0
- package/src/graphqlQueries/productBlocksQuery.ts +9 -5
- package/src/graphqlQueries/productsQuery.ts +7 -3
- package/src/graphqlQueries/relatedSubscriptionsQuery.ts +2 -2
- package/src/graphqlQueries/resourceTypesQuery.ts +8 -4
- package/src/graphqlQueries/subscriptionDetailQuery.ts +1 -0
- package/src/graphqlQueries/subscriptionsListQuery.ts +5 -3
- package/src/graphqlQueries/workflows/workflowsQuery.ts +8 -4
- package/src/graphqlQueries/workflows/workflowsQueryForDropdownList.ts +2 -2
- package/src/hooks/DataFetchHooks.ts +9 -4
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useCheckEngineStatus.ts +30 -0
- package/src/hooks/useDataDisplayParams.ts +3 -3
- package/src/hooks/useEngineStatusQuery.ts +9 -7
- package/src/hooks/useMutateProcess.ts +96 -0
- package/src/messages/{en-US.json → en-GB.json} +85 -37
- package/src/messages/getTranslationMessages.spec.ts +25 -40
- package/src/messages/index.ts +1 -1
- package/src/messages/nl-NL.json +95 -48
- package/src/messages/useGetTranslationMessages.ts +51 -0
- package/src/pages/metadata/WfoProductBlocksPage.tsx +12 -10
- package/src/pages/metadata/WfoProductsPage.tsx +24 -25
- package/src/pages/metadata/WfoResourceTypesPage.tsx +12 -10
- package/src/pages/metadata/WfoWorkflowsPage.tsx +12 -10
- package/src/pages/processes/WfoProcessDetail.tsx +96 -79
- package/src/pages/processes/WfoProcessDetailPage.tsx +5 -3
- package/src/pages/{workflow/WfoStartWorkflowPage.tsx → processes/WfoStartProcessPage.tsx} +102 -51
- package/src/pages/processes/index.ts +1 -3
- package/src/pages/settings/WfoSettingsPage.tsx +30 -0
- package/src/pages/settings/index.ts +1 -0
- package/src/pages/tasks/WfoTaskListPage.tsx +35 -9
- package/src/pages/{processes/WfoProcessListPage.tsx → workflow/WfoWorkflowListPage.tsx} +22 -23
- package/src/pages/workflow/getWorkflowListTabTypeFromString.ts +19 -0
- package/src/pages/workflow/index.ts +1 -1
- package/src/pages/{processes → workflow}/tabConfig.ts +6 -6
- package/src/types/types.ts +33 -3
- package/src/utils/getDefaultTableConfig.ts +1 -1
- package/src/components/WfoSettingsPage/WfoModifySettings.tsx +0 -33
- package/src/components/WfoSettingsPage/WfoSettings.tsx +0 -40
- package/src/hooks/ProcessesHooks/useDeleteProcess.ts +0 -37
- package/src/messages/getTranslationMessages.ts +0 -26
- package/src/pages/processes/getProcessListTabTypeFromString.ts +0 -19
- /package/src/components/{WfoSettingsPage → WfoSettings}/index.ts +0 -0
|
@@ -74,3 +74,19 @@ export const getWorkflowTargetColor = (
|
|
|
74
74
|
|
|
75
75
|
return theme.colors.body;
|
|
76
76
|
};
|
|
77
|
+
|
|
78
|
+
export const getWorkflowTargetIconContent = (
|
|
79
|
+
workflowTarget: WorkflowTarget,
|
|
80
|
+
) => {
|
|
81
|
+
// Data returned from graphql can't always be depended on to be lowercase
|
|
82
|
+
switch (workflowTarget.toLocaleLowerCase()) {
|
|
83
|
+
case WorkflowTarget.CREATE:
|
|
84
|
+
return 'C';
|
|
85
|
+
case WorkflowTarget.SYSTEM:
|
|
86
|
+
return 'T';
|
|
87
|
+
case WorkflowTarget.TERMINATE:
|
|
88
|
+
return 'X';
|
|
89
|
+
default:
|
|
90
|
+
return 'M';
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -4,32 +4,29 @@ import { useTranslations } from 'next-intl';
|
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { useRouter } from 'next/router';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Pagination } from '@elastic/eui';
|
|
8
|
+
|
|
9
|
+
import { WfoSubscriptionStatusBadge } from '@/components';
|
|
10
|
+
import { FilterQuery, WfoDateTime, WfoLoading } from '@/components';
|
|
11
|
+
import { WfoInsyncIcon } from '@/components/WfoInsyncIcon';
|
|
12
|
+
import { getSubscriptionsListGraphQlQuery } from '@/graphqlQueries';
|
|
13
|
+
import { DataDisplayParams, useQueryWithGraphql } from '@/hooks';
|
|
14
|
+
import { SortOrder } from '@/types';
|
|
15
|
+
import {
|
|
16
|
+
getTypedFieldFromObject,
|
|
17
|
+
parseDateToLocaleDateTimeString,
|
|
18
|
+
} from '@/utils';
|
|
8
19
|
|
|
9
|
-
import { getSubscriptionsListGraphQlQuery } from '../../graphqlQueries/subscriptionsListQuery';
|
|
10
|
-
import { DataDisplayParams } from '../../hooks/useDataDisplayParams';
|
|
11
|
-
import { useOrchestratorTheme } from '../../hooks/useOrchestratorTheme';
|
|
12
|
-
import { useQueryWithGraphql } from '../../hooks/useQueryWithGraphql';
|
|
13
|
-
import { WfoPlusCircleFill } from '../../icons';
|
|
14
|
-
import { SortOrder } from '../../types';
|
|
15
|
-
import { parseDateToLocaleDateTimeString } from '../../utils';
|
|
16
|
-
import { getTypedFieldFromObject } from '../../utils/getTypedFieldFromObject';
|
|
17
|
-
import { WfoSubscriptionStatusBadge } from '../WfoBadges/WfoSubscriptionStatusBadge';
|
|
18
|
-
import { WfoDateTime } from '../WfoDateTime/WfoDateTime';
|
|
19
|
-
import { FilterQuery } from '../WfoFilterTabs';
|
|
20
|
-
import { WfoInsyncIcon } from '../WfoInsyncIcon/WfoInsyncIcon';
|
|
21
|
-
import { WfoLoading } from '../WfoLoading';
|
|
22
20
|
import {
|
|
23
21
|
DEFAULT_PAGE_SIZES,
|
|
24
22
|
SUBSCRIPTIONS_TABLE_LOCAL_STORAGE_KEY,
|
|
25
23
|
TableColumnKeys,
|
|
26
24
|
WfoDataSorting,
|
|
27
25
|
WfoTableColumns,
|
|
28
|
-
WfoTableControlColumnConfig,
|
|
29
26
|
WfoTableWithFilter,
|
|
30
27
|
getDataSortHandler,
|
|
31
|
-
getEsQueryStringHandler,
|
|
32
28
|
getPageChangeHandler,
|
|
29
|
+
getQueryStringHandler,
|
|
33
30
|
} from '../WfoTable';
|
|
34
31
|
import { WfoFirstPartUUID } from '../WfoTable/WfoFirstPartUUID';
|
|
35
32
|
import { mapSortableAndFilterableValuesToTableColumnConfig } from '../WfoTable/utils/mapSortableAndFilterableValuesToTableColumnConfig';
|
|
@@ -38,8 +35,6 @@ import {
|
|
|
38
35
|
mapGrapghQlSubscriptionsResultToSubscriptionListItems,
|
|
39
36
|
} from './mapGrapghQlSubscriptionsResultToSubscriptionListItems';
|
|
40
37
|
|
|
41
|
-
const FIELD_NAME_INLINE_SUBSCRIPTION_DETAILS = 'inlineSubscriptionDetails';
|
|
42
|
-
|
|
43
38
|
export type WfoSubscriptionsListProps = {
|
|
44
39
|
alwaysOnFilters?: FilterQuery<SubscriptionListItem>[];
|
|
45
40
|
dataDisplayParams: DataDisplayParams<SubscriptionListItem>;
|
|
@@ -64,8 +59,6 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
64
59
|
const router = useRouter();
|
|
65
60
|
const t = useTranslations('subscriptions.index');
|
|
66
61
|
|
|
67
|
-
const { theme } = useOrchestratorTheme();
|
|
68
|
-
|
|
69
62
|
const tableColumns: WfoTableColumns<SubscriptionListItem> = {
|
|
70
63
|
subscriptionId: {
|
|
71
64
|
field: 'subscriptionId',
|
|
@@ -127,20 +120,7 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
127
120
|
},
|
|
128
121
|
};
|
|
129
122
|
|
|
130
|
-
const
|
|
131
|
-
{
|
|
132
|
-
inlineSubscriptionDetails: {
|
|
133
|
-
field: FIELD_NAME_INLINE_SUBSCRIPTION_DETAILS,
|
|
134
|
-
width: '40',
|
|
135
|
-
render: () => (
|
|
136
|
-
<EuiFlexItem>
|
|
137
|
-
<WfoPlusCircleFill color={theme.colors.mediumShade} />
|
|
138
|
-
</EuiFlexItem>
|
|
139
|
-
),
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const { sortBy } = dataDisplayParams;
|
|
123
|
+
const { sortBy, queryString } = dataDisplayParams;
|
|
144
124
|
const { data, isFetching } = useQueryWithGraphql(
|
|
145
125
|
getSubscriptionsListGraphQlQuery<SubscriptionListItem>(),
|
|
146
126
|
{
|
|
@@ -148,6 +128,7 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
148
128
|
after: dataDisplayParams.pageIndex * dataDisplayParams.pageSize,
|
|
149
129
|
sortBy,
|
|
150
130
|
filterBy: alwaysOnFilters,
|
|
131
|
+
query: queryString || undefined,
|
|
151
132
|
},
|
|
152
133
|
'subscriptions',
|
|
153
134
|
);
|
|
@@ -177,8 +158,8 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
177
158
|
|
|
178
159
|
return (
|
|
179
160
|
<WfoTableWithFilter<SubscriptionListItem>
|
|
180
|
-
|
|
181
|
-
|
|
161
|
+
queryString={dataDisplayParams.queryString}
|
|
162
|
+
onUpdateQueryString={getQueryStringHandler<SubscriptionListItem>(
|
|
182
163
|
setDataDisplayParam,
|
|
183
164
|
)}
|
|
184
165
|
data={mapGrapghQlSubscriptionsResultToSubscriptionListItems(data)}
|
|
@@ -187,7 +168,6 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
187
168
|
sortFields,
|
|
188
169
|
filterFields,
|
|
189
170
|
)}
|
|
190
|
-
leadingControlColumns={leadingControlColumns}
|
|
191
171
|
defaultHiddenColumns={hiddenColumns}
|
|
192
172
|
dataSorting={dataSorting}
|
|
193
173
|
pagination={pagination}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from 'next-intl';
|
|
4
|
+
|
|
3
5
|
import {
|
|
4
6
|
Criteria,
|
|
5
7
|
EuiButton,
|
|
@@ -39,6 +41,7 @@ import {
|
|
|
39
41
|
clearTableConfigFromLocalStorage,
|
|
40
42
|
setTableConfigToLocalStorage,
|
|
41
43
|
} from '../utils/tableConfigPersistence';
|
|
44
|
+
import { updateQueryString } from './updateQueryString';
|
|
42
45
|
|
|
43
46
|
export type WfoTableWithFilterProps<T> = {
|
|
44
47
|
data: T[];
|
|
@@ -48,12 +51,12 @@ export type WfoTableWithFilterProps<T> = {
|
|
|
48
51
|
defaultHiddenColumns?: TableColumnKeys<T>;
|
|
49
52
|
dataSorting: WfoDataSorting<T>;
|
|
50
53
|
pagination: Pagination;
|
|
51
|
-
|
|
54
|
+
queryString?: string;
|
|
52
55
|
isLoading: boolean;
|
|
53
56
|
localStorageKey: string;
|
|
54
57
|
detailModal?: boolean;
|
|
55
58
|
detailModalTitle?: string;
|
|
56
|
-
|
|
59
|
+
onUpdateQueryString: (queryString: string) => void;
|
|
57
60
|
onUpdatePage: (criterion: Criteria<T>['page']) => void;
|
|
58
61
|
onUpdateDataSort: (dataSorting: WfoDataSorting<T>) => void;
|
|
59
62
|
};
|
|
@@ -66,12 +69,12 @@ export const WfoTableWithFilter = <T,>({
|
|
|
66
69
|
defaultHiddenColumns = [],
|
|
67
70
|
dataSorting,
|
|
68
71
|
pagination,
|
|
69
|
-
|
|
72
|
+
queryString,
|
|
70
73
|
isLoading,
|
|
71
74
|
localStorageKey,
|
|
72
75
|
detailModal = true,
|
|
73
76
|
detailModalTitle = 'Details',
|
|
74
|
-
|
|
77
|
+
onUpdateQueryString,
|
|
75
78
|
onUpdatePage,
|
|
76
79
|
onUpdateDataSort,
|
|
77
80
|
}: WfoTableWithFilterProps<T>) => {
|
|
@@ -83,6 +86,7 @@ export const WfoTableWithFilter = <T,>({
|
|
|
83
86
|
const [showSettingsModal, setShowSettingsModal] = useState(false);
|
|
84
87
|
const [selectedDataForDetailModal, setSelectedDataForDetailModal] =
|
|
85
88
|
useState<T | undefined>(undefined);
|
|
89
|
+
const t = useTranslations('common');
|
|
86
90
|
|
|
87
91
|
useEffect(() => {
|
|
88
92
|
if (defaultHiddenColumns) {
|
|
@@ -189,12 +193,12 @@ export const WfoTableWithFilter = <T,>({
|
|
|
189
193
|
<EuiFlexGroup>
|
|
190
194
|
<EuiFlexItem>
|
|
191
195
|
<WfoSearchField
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
queryString={queryString}
|
|
197
|
+
onUpdateQueryString={onUpdateQueryString}
|
|
194
198
|
/>
|
|
195
199
|
</EuiFlexItem>
|
|
196
200
|
<EuiButton onClick={() => setShowSettingsModal(true)}>
|
|
197
|
-
|
|
201
|
+
{t('editColumns')}
|
|
198
202
|
</EuiButton>
|
|
199
203
|
</EuiFlexGroup>
|
|
200
204
|
<EuiSpacer size="m" />
|
|
@@ -207,18 +211,15 @@ export const WfoTableWithFilter = <T,>({
|
|
|
207
211
|
pagination={pagination}
|
|
208
212
|
isLoading={isLoading}
|
|
209
213
|
onCriteriaChange={onCriteriaChange}
|
|
210
|
-
onDataSearch={({ field, searchText }) =>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
: `${field.toString()}:"${searchText}"`,
|
|
220
|
-
);
|
|
221
|
-
}}
|
|
214
|
+
onDataSearch={({ field, searchText }) =>
|
|
215
|
+
onUpdateQueryString(
|
|
216
|
+
updateQueryString(
|
|
217
|
+
queryString ?? '',
|
|
218
|
+
field.toString(),
|
|
219
|
+
searchText,
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
}
|
|
222
223
|
/>
|
|
223
224
|
|
|
224
225
|
{showSettingsModal && (
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { updateQueryString } from './updateQueryString';
|
|
2
|
+
|
|
3
|
+
describe('updateQueryString', () => {
|
|
4
|
+
it('adds a new field when the query string is empty', () => {
|
|
5
|
+
const queryString = '';
|
|
6
|
+
const fieldName = 'field1';
|
|
7
|
+
const value = 'value1';
|
|
8
|
+
|
|
9
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
10
|
+
|
|
11
|
+
expect(result).toBe('field1:value1');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('adds a new field when the query string does not contain the field yet', () => {
|
|
15
|
+
const queryString = 'field1:value1';
|
|
16
|
+
const fieldName = 'field2';
|
|
17
|
+
const value = 'value2';
|
|
18
|
+
|
|
19
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
20
|
+
|
|
21
|
+
expect(result).toBe('field1:value1 field2:value2');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('updates an existing field with a single value in the query string', () => {
|
|
25
|
+
const queryString = 'field1:value1 field2:value2';
|
|
26
|
+
const fieldName = 'field1';
|
|
27
|
+
const value = 'value3';
|
|
28
|
+
|
|
29
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
30
|
+
|
|
31
|
+
expect(result).toBe('field1:(value1|value3) field2:value2');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('updates an existing field with with already 2 values in the query string', () => {
|
|
35
|
+
const queryString = 'field1:(value1|value3) field2:value2';
|
|
36
|
+
const fieldName = 'field1';
|
|
37
|
+
const value = 'value4';
|
|
38
|
+
|
|
39
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
40
|
+
|
|
41
|
+
expect(result).toBe('field1:(value1|value3|value4) field2:value2');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('uses quotes when the added value contains spaces', () => {
|
|
45
|
+
const queryString = 'field1:(value1|value3) field2:value2';
|
|
46
|
+
const fieldName = 'field1';
|
|
47
|
+
const value = 'value 4';
|
|
48
|
+
|
|
49
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
50
|
+
|
|
51
|
+
expect(result).toBe('field1:(value1|value3|"value 4") field2:value2');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('adds a new value to an exising field where one existing value contains spaces', () => {
|
|
55
|
+
const queryString = 'field1:("value 1"|value3) field2:value2';
|
|
56
|
+
const fieldName = 'field1';
|
|
57
|
+
const value = 'value 4';
|
|
58
|
+
|
|
59
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
60
|
+
|
|
61
|
+
expect(result).toBe(
|
|
62
|
+
'field1:("value 1"|value3|"value 4") field2:value2',
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('returns the same query string when the given field name is an empty string', () => {
|
|
67
|
+
const queryString = 'field1:value1 field2:value2';
|
|
68
|
+
const fieldName = 'field1';
|
|
69
|
+
const value = '';
|
|
70
|
+
|
|
71
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
72
|
+
|
|
73
|
+
expect(result).toBe('field1:value1 field2:value2');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('returns the same query string when the given value is an empty string', () => {
|
|
77
|
+
const queryString = 'field1:value1 field2:value2';
|
|
78
|
+
const fieldName = '';
|
|
79
|
+
const value = 'value 3';
|
|
80
|
+
|
|
81
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
82
|
+
|
|
83
|
+
expect(result).toBe('field1:value1 field2:value2');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('updates an existing field ignoring case in the field name', () => {
|
|
87
|
+
const queryString = 'field1:value1 field2:value2';
|
|
88
|
+
const fieldName = 'Field1';
|
|
89
|
+
const value = 'value3';
|
|
90
|
+
|
|
91
|
+
const result = updateQueryString(queryString, fieldName, value);
|
|
92
|
+
|
|
93
|
+
expect(result).toBe('field1:(value1|value3) field2:value2');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Four cases to consider when this function is called
|
|
2
|
+
// 1 - fieldName or value is empty
|
|
3
|
+
// 2 - queryString is empty
|
|
4
|
+
// 3 - fieldName does not exist in query string
|
|
5
|
+
// 4 - fieldName already exists in query string
|
|
6
|
+
export const updateQueryString = (
|
|
7
|
+
queryString: string,
|
|
8
|
+
fieldName: string,
|
|
9
|
+
value: string,
|
|
10
|
+
) => {
|
|
11
|
+
// 1 - Returning the exising query string when either fieldName or value is empty
|
|
12
|
+
if (fieldName === '' || value === '') {
|
|
13
|
+
return queryString;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 2 - Empty query string returning directly fieldName:value
|
|
17
|
+
if (queryString === '') {
|
|
18
|
+
return `${fieldName}:${toQueryValue(value)}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Finding fieldName with values in queryString in this order:
|
|
22
|
+
// - Value surrounded with double quotes
|
|
23
|
+
// field:"value"
|
|
24
|
+
// - Value is surrounded with brackets
|
|
25
|
+
// field:(value1|value2)
|
|
26
|
+
// field:("value1 with spaces"|value2|value3)
|
|
27
|
+
// - Value is a single word (no quotes and no brackets)
|
|
28
|
+
// field:value
|
|
29
|
+
const fieldRegex = new RegExp(
|
|
30
|
+
String.raw`(${fieldName}):(".*?"|\(.*?\)|[^()|!:<>*"\s]+\*?)`,
|
|
31
|
+
'i',
|
|
32
|
+
);
|
|
33
|
+
const match = queryString.match(fieldRegex);
|
|
34
|
+
|
|
35
|
+
// 3 - Field name does not exist in query string yet, appending fieldName:value
|
|
36
|
+
if (!match) {
|
|
37
|
+
return `${queryString} ${fieldName}:${toQueryValue(value)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 4 - Field name already exists in query string as:
|
|
41
|
+
const existingFieldName = match[1];
|
|
42
|
+
const existingValue = getValueWithoutBrackets(match[2]);
|
|
43
|
+
const updatedValue = `${existingValue}|${toQueryValue(value)}`;
|
|
44
|
+
return queryString.replace(
|
|
45
|
+
fieldRegex,
|
|
46
|
+
`${existingFieldName}:(${updatedValue})`,
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const getValueWithoutBrackets = (value: string) => {
|
|
51
|
+
if (value.startsWith('(') && value.endsWith(')')) {
|
|
52
|
+
return value.slice(1, -1);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const hasSpaces = (value: string) => value.indexOf(' ') !== -1;
|
|
58
|
+
|
|
59
|
+
const toQueryValue = (value: string) =>
|
|
60
|
+
hasSpaces(value) ? `"${value}"` : value;
|
|
@@ -44,10 +44,10 @@ export const getPageChangeHandler =
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
export const
|
|
47
|
+
export const getQueryStringHandler =
|
|
48
48
|
<Type>(
|
|
49
49
|
setDataDisplayParam: DataDisplayReturnValues<Type>['setDataDisplayParam'],
|
|
50
50
|
) =>
|
|
51
|
-
(
|
|
52
|
-
setDataDisplayParam('
|
|
51
|
+
(queryString: string) => {
|
|
52
|
+
setDataDisplayParam('queryString', queryString);
|
|
53
53
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Meta } from '@storybook/react';
|
|
4
|
+
|
|
5
|
+
import { WfoTextAnchor } from './WfoTextAnchor';
|
|
6
|
+
|
|
7
|
+
const Story: Meta<typeof WfoTextAnchor> = {
|
|
8
|
+
component: ({ text, url }) => <WfoTextAnchor text={text} url={url} />,
|
|
9
|
+
title: 'Text/WfoTextAnchor',
|
|
10
|
+
};
|
|
11
|
+
export default Story;
|
|
12
|
+
|
|
13
|
+
export const Primary = {
|
|
14
|
+
args: {
|
|
15
|
+
text: 'Text',
|
|
16
|
+
url: 'Url',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { EuiText } from '@elastic/eui';
|
|
4
|
+
|
|
5
|
+
import { useWithOrchestratorTheme } from '@/hooks';
|
|
6
|
+
|
|
7
|
+
import { getStyles } from './styles';
|
|
8
|
+
|
|
9
|
+
interface WfoTextAnchorProps {
|
|
10
|
+
text: string;
|
|
11
|
+
onClick: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const WfoTextAnchor = ({ text, onClick }: WfoTextAnchorProps) => {
|
|
15
|
+
const { textAnchorStyle } = useWithOrchestratorTheme(getStyles);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<EuiText onClick={onClick} css={textAnchorStyle}>
|
|
19
|
+
{text}
|
|
20
|
+
</EuiText>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { WfoTextAnchor } from './WfoTextAnchor';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types';
|
|
2
|
+
import { css } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
export const getStyles = (theme: EuiThemeComputed) => {
|
|
5
|
+
const textAnchorStyle = css({
|
|
6
|
+
marginTop: theme.size.xxs,
|
|
7
|
+
marginLeft: 0,
|
|
8
|
+
fontSize: theme.size.m,
|
|
9
|
+
fontWeight: theme.font.weight.bold,
|
|
10
|
+
color: theme.colors.link,
|
|
11
|
+
cursor: 'pointer',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
textAnchorStyle,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { makeHighContrastColor } from '@elastic/eui';
|
|
2
1
|
import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types';
|
|
3
2
|
import { css } from '@emotion/react';
|
|
4
3
|
|
|
@@ -29,6 +28,15 @@ export const getStyles = (theme: EuiThemeComputed) => {
|
|
|
29
28
|
}
|
|
30
29
|
};
|
|
31
30
|
|
|
31
|
+
const getTextColorForStepStatusIcon = (processStepStatus: StepStatus) => {
|
|
32
|
+
switch (processStepStatus) {
|
|
33
|
+
case StepStatus.SUSPEND:
|
|
34
|
+
return theme.colors.ink;
|
|
35
|
+
default:
|
|
36
|
+
return theme.colors.ghost;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
32
40
|
const timelinePanelStyle = css({
|
|
33
41
|
backgroundColor: theme.colors.body,
|
|
34
42
|
borderRadius: theme.border.radius.medium,
|
|
@@ -133,9 +141,7 @@ export const getStyles = (theme: EuiThemeComputed) => {
|
|
|
133
141
|
display: 'flex',
|
|
134
142
|
alignItems: 'center',
|
|
135
143
|
justifyContent: 'center',
|
|
136
|
-
color:
|
|
137
|
-
getColorForStepStatus(stepStatus),
|
|
138
|
-
),
|
|
144
|
+
color: getTextColorForStepStatusIcon(stepStatus),
|
|
139
145
|
});
|
|
140
146
|
};
|
|
141
147
|
|
|
@@ -4,40 +4,44 @@ import { useTranslations } from 'next-intl';
|
|
|
4
4
|
|
|
5
5
|
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
7
|
+
import { WfoJsonCodeBlock } from '@/components';
|
|
8
|
+
import { useOrchestratorTheme } from '@/hooks';
|
|
9
|
+
import { WfoChevronDown, WfoChevronUp } from '@/icons';
|
|
10
|
+
import type { EmailState } from '@/types';
|
|
11
|
+
import { StepStatus } from '@/types';
|
|
12
|
+
import { calculateTimeDifference, formatDate } from '@/utils';
|
|
13
|
+
|
|
13
14
|
import { WfoStepStatusIcon } from '../WfoStepStatusIcon';
|
|
15
|
+
import type { StepListItem } from '../WfoWorkflowStepList';
|
|
14
16
|
import { getStepContent } from '../stepListUtils';
|
|
15
17
|
import { getStyles } from '../styles';
|
|
18
|
+
import { WfoStepForm } from './WfoStepForm';
|
|
16
19
|
|
|
17
20
|
export interface WfoStepProps {
|
|
18
|
-
|
|
19
|
-
stepDelta: StepState;
|
|
20
|
-
stepDetailIsOpen: boolean;
|
|
21
|
+
stepListItem: StepListItem;
|
|
21
22
|
startedAt: string;
|
|
22
23
|
showHiddenKeys: boolean;
|
|
23
24
|
onToggleStepDetail: () => void;
|
|
25
|
+
isTask: boolean;
|
|
24
26
|
isStartStep?: boolean;
|
|
27
|
+
processId?: string;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export const WfoStep = React.forwardRef(
|
|
28
31
|
(
|
|
29
32
|
{
|
|
30
|
-
|
|
31
|
-
stepDelta,
|
|
32
|
-
stepDetailIsOpen,
|
|
33
|
+
stepListItem,
|
|
33
34
|
onToggleStepDetail,
|
|
34
35
|
startedAt,
|
|
35
36
|
showHiddenKeys,
|
|
36
37
|
isStartStep = false,
|
|
38
|
+
isTask,
|
|
39
|
+
processId,
|
|
37
40
|
}: WfoStepProps,
|
|
38
41
|
ref: LegacyRef<HTMLDivElement>,
|
|
39
42
|
) => {
|
|
40
|
-
const {
|
|
43
|
+
const { isExpanded, step, userInputForm } = stepListItem;
|
|
44
|
+
|
|
41
45
|
const { theme } = useOrchestratorTheme();
|
|
42
46
|
const {
|
|
43
47
|
stepEmailContainerStyle,
|
|
@@ -49,9 +53,12 @@ export const WfoStep = React.forwardRef(
|
|
|
49
53
|
getStepToggleExpandStyle,
|
|
50
54
|
} = getStyles(theme);
|
|
51
55
|
const t = useTranslations('processes.steps');
|
|
52
|
-
const hasHtmlMail =
|
|
56
|
+
const hasHtmlMail =
|
|
57
|
+
step.stateDelta?.hasOwnProperty('confirmation_mail');
|
|
53
58
|
|
|
54
|
-
const stepContent =
|
|
59
|
+
const stepContent = step.stateDelta
|
|
60
|
+
? getStepContent(step.stateDelta, showHiddenKeys)
|
|
61
|
+
: {};
|
|
55
62
|
const hasStepContent = Object.keys(stepContent).length > 0;
|
|
56
63
|
|
|
57
64
|
const displayMailConfirmation = (value: EmailState) => {
|
|
@@ -103,17 +110,18 @@ export const WfoStep = React.forwardRef(
|
|
|
103
110
|
onClick={() => hasStepContent && onToggleStepDetail()}
|
|
104
111
|
>
|
|
105
112
|
<WfoStepStatusIcon
|
|
106
|
-
stepStatus={status}
|
|
113
|
+
stepStatus={step.status}
|
|
107
114
|
isStartStep={isStartStep}
|
|
108
115
|
/>
|
|
109
116
|
|
|
110
117
|
<EuiFlexItem grow={0}>
|
|
111
118
|
<EuiText css={stepListContentBoldTextStyle}>
|
|
112
|
-
{name}
|
|
119
|
+
{step.name}
|
|
113
120
|
</EuiText>
|
|
114
121
|
<EuiText>
|
|
115
|
-
{status}{' '}
|
|
116
|
-
{executed &&
|
|
122
|
+
{step.status}{' '}
|
|
123
|
+
{step.executed &&
|
|
124
|
+
`- ${formatDate(step.executed)}`}
|
|
117
125
|
</EuiText>
|
|
118
126
|
</EuiFlexItem>
|
|
119
127
|
|
|
@@ -140,24 +148,31 @@ export const WfoStep = React.forwardRef(
|
|
|
140
148
|
hasStepContent,
|
|
141
149
|
)}
|
|
142
150
|
>
|
|
143
|
-
{(
|
|
144
|
-
<
|
|
145
|
-
)
|
|
151
|
+
{(isExpanded && <WfoChevronUp />) || (
|
|
152
|
+
<WfoChevronDown />
|
|
153
|
+
)}
|
|
146
154
|
</EuiFlexItem>
|
|
147
155
|
</>
|
|
148
156
|
)}
|
|
149
157
|
</EuiFlexGroup>
|
|
150
158
|
</EuiFlexGroup>
|
|
151
|
-
{hasStepContent &&
|
|
159
|
+
{hasStepContent && isExpanded && (
|
|
152
160
|
<WfoJsonCodeBlock data={stepContent} />
|
|
153
161
|
)}
|
|
154
|
-
{
|
|
162
|
+
{isExpanded && hasHtmlMail && (
|
|
155
163
|
<div css={stepEmailContainerStyle}>
|
|
156
164
|
{displayMailConfirmation(
|
|
157
165
|
step.state.confirmation_mail as EmailState,
|
|
158
166
|
)}
|
|
159
167
|
</div>
|
|
160
168
|
)}
|
|
169
|
+
{step.status === StepStatus.SUSPEND && userInputForm && (
|
|
170
|
+
<WfoStepForm
|
|
171
|
+
userInputForm={userInputForm}
|
|
172
|
+
isTask={isTask}
|
|
173
|
+
processId={processId}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
161
176
|
</EuiPanel>
|
|
162
177
|
</div>
|
|
163
178
|
);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { EuiFlexItem } from '@elastic/eui';
|
|
4
|
+
|
|
5
|
+
import { UserInputFormWizard, WfoLoading } from '@/components';
|
|
6
|
+
import { useAxiosApiClient } from '@/components/WfoForms/useAxiosApiClient';
|
|
7
|
+
import { useOrchestratorTheme } from '@/hooks';
|
|
8
|
+
import { InputForm } from '@/types/forms';
|
|
9
|
+
|
|
10
|
+
interface WfoStepFormProps {
|
|
11
|
+
userInputForm: InputForm;
|
|
12
|
+
isTask: boolean;
|
|
13
|
+
processId?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const WfoStepForm = ({
|
|
17
|
+
userInputForm,
|
|
18
|
+
isTask,
|
|
19
|
+
processId,
|
|
20
|
+
}: WfoStepFormProps) => {
|
|
21
|
+
const [isProcessing, setIsProcessing] = useState<boolean>(false);
|
|
22
|
+
const { theme } = useOrchestratorTheme();
|
|
23
|
+
const apiClient = useAxiosApiClient();
|
|
24
|
+
|
|
25
|
+
const submitForm = (processInput: object[]) => {
|
|
26
|
+
if (!processId) {
|
|
27
|
+
return Promise.reject();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return apiClient.resumeProcess(processId, processInput).then(() => {
|
|
31
|
+
setIsProcessing(true);
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<EuiFlexItem css={{ margin: theme.size.m }}>
|
|
37
|
+
{(isProcessing && <WfoLoading />) || (
|
|
38
|
+
<UserInputFormWizard
|
|
39
|
+
stepUserInput={userInputForm}
|
|
40
|
+
validSubmit={submitForm}
|
|
41
|
+
hasNext={false}
|
|
42
|
+
isTask={isTask}
|
|
43
|
+
isResuming={true}
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
46
|
+
</EuiFlexItem>
|
|
47
|
+
);
|
|
48
|
+
};
|