@orchestrator-ui/orchestrator-ui-components 5.7.1 → 5.8.1
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 +7 -7
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +12 -12
- package/CHANGELOG.md +13 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.js +463 -401
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/WfoBadges/WfoWorkflowTargetBadge/WfoWorkflowTargetBadge.tsx +7 -0
- package/src/components/WfoPydanticForm/WfoPydanticForm.tsx +3 -1
- package/src/components/WfoPydanticForm/fields/WfoDropdown.tsx +2 -2
- package/src/components/WfoPydanticForm/fields/WfoInteger.tsx +11 -1
- package/src/components/WfoPydanticForm/fields/WfoMultiCheckboxField.tsx +2 -2
- package/src/components/WfoPydanticForm/fields/WfoRadio.tsx +2 -2
- package/src/components/WfoPydanticForm/fields/WfoReactSelect/WfoReactSelect.tsx +16 -14
- package/src/components/WfoPydanticForm/fields/WfoText.tsx +10 -2
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActions.tsx +109 -110
- package/src/components/WfoSubscription/utils/utils.ts +4 -0
- package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +12 -0
- package/src/configuration/policy-resources.ts +1 -0
- package/src/configuration/version.ts +1 -1
- package/src/messages/en-GB.json +5 -0
- package/src/messages/nl-NL.json +5 -0
- package/src/rtk/endpoints/metadata/workflows.ts +1 -1
- package/src/types/types.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchestrator-ui/orchestrator-ui-components",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Library of UI Components used to display the workflow orchestrator frontend",
|
|
6
6
|
"author": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"next-query-params": "^5.0.0",
|
|
49
49
|
"object-hash": "^3.0.0",
|
|
50
50
|
"prism-themes": "^1.9.0",
|
|
51
|
-
"pydantic-forms": "^0.9.
|
|
51
|
+
"pydantic-forms": "^0.9.2",
|
|
52
52
|
"react-diff-view": "^3.2.0",
|
|
53
53
|
"react-draggable": "^4.4.6",
|
|
54
54
|
"react-redux": "^9.1.2",
|
|
@@ -24,6 +24,8 @@ export const WfoWorkflowTargetBadge: FC<WfoWorkflowTargetBadgeProps> = ({
|
|
|
24
24
|
successText,
|
|
25
25
|
warning,
|
|
26
26
|
warningText,
|
|
27
|
+
accent,
|
|
28
|
+
accentText,
|
|
27
29
|
} = theme.colors;
|
|
28
30
|
|
|
29
31
|
switch (_target?.toLowerCase()) {
|
|
@@ -48,6 +50,11 @@ export const WfoWorkflowTargetBadge: FC<WfoWorkflowTargetBadgeProps> = ({
|
|
|
48
50
|
badgeColor: toSecondaryColor(danger),
|
|
49
51
|
textColor: dangerText,
|
|
50
52
|
};
|
|
53
|
+
case WorkflowTarget.RECONCILE:
|
|
54
|
+
return {
|
|
55
|
+
badgeColor: toSecondaryColor(accent),
|
|
56
|
+
textColor: accentText,
|
|
57
|
+
};
|
|
51
58
|
default:
|
|
52
59
|
return {
|
|
53
60
|
badgeColor: toSecondaryColor(primary),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
+
import _ from 'lodash';
|
|
3
4
|
import { AbstractIntlMessages, useMessages, useTranslations } from 'next-intl';
|
|
4
5
|
import { useRouter } from 'next/router';
|
|
5
6
|
import type {
|
|
@@ -168,7 +169,7 @@ export const useWfoPydanticFormConfig = () => {
|
|
|
168
169
|
// We are not using a radio button component to maintain being able to deselect options
|
|
169
170
|
return (
|
|
170
171
|
field.type === PydanticFormFieldType.STRING &&
|
|
171
|
-
|
|
172
|
+
_.isArray(field.options) &&
|
|
172
173
|
field.options.length > 0
|
|
173
174
|
);
|
|
174
175
|
},
|
|
@@ -193,6 +194,7 @@ export const useWfoPydanticFormConfig = () => {
|
|
|
193
194
|
matcher(field) {
|
|
194
195
|
return (
|
|
195
196
|
field.type === PydanticFormFieldType.ARRAY &&
|
|
197
|
+
_.isArray(field.options) &&
|
|
196
198
|
field.options?.length > 0 &&
|
|
197
199
|
field.options?.length <= 5
|
|
198
200
|
);
|
|
@@ -9,14 +9,14 @@ export const WfoDropdown: PydanticFormControlledElement = ({
|
|
|
9
9
|
pydanticFormField,
|
|
10
10
|
value,
|
|
11
11
|
}) => {
|
|
12
|
-
const dropDownOptions = pydanticFormField.options
|
|
12
|
+
const dropDownOptions = pydanticFormField.options?.map((option) => ({
|
|
13
13
|
value: option.value,
|
|
14
14
|
label: option.label,
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<WfoReactSelect
|
|
19
|
-
options={dropDownOptions}
|
|
19
|
+
options={dropDownOptions || []}
|
|
20
20
|
onChange={onChange}
|
|
21
21
|
id={pydanticFormField.id}
|
|
22
22
|
value={value}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
+
import _ from 'lodash';
|
|
3
4
|
import type { PydanticFormControlledElement } from 'pydantic-forms';
|
|
5
|
+
import { getFormFieldIdWithPath } from 'pydantic-forms';
|
|
4
6
|
|
|
5
7
|
import { EuiFieldNumber } from '@elastic/eui';
|
|
6
8
|
import { css } from '@emotion/react';
|
|
@@ -32,13 +34,21 @@ export const WfoInteger: PydanticFormControlledElement = ({
|
|
|
32
34
|
getFormFieldsBaseStyle,
|
|
33
35
|
);
|
|
34
36
|
|
|
37
|
+
// If the field is part of an array the value is passed in as an object with the field name as key
|
|
38
|
+
// this is imposed by react-hook-form. We try to detect this and extract the actual value
|
|
39
|
+
const fieldName = getFormFieldIdWithPath(pydanticFormField.id);
|
|
40
|
+
const fieldValue =
|
|
41
|
+
_.isObject(value) && _.has(value, fieldName)
|
|
42
|
+
? _.get(value, fieldName)
|
|
43
|
+
: value;
|
|
44
|
+
|
|
35
45
|
return (
|
|
36
46
|
<EuiFieldNumber
|
|
37
47
|
data-testid={pydanticFormField.id}
|
|
38
48
|
css={formFieldBaseStyle}
|
|
39
49
|
name={pydanticFormField.id}
|
|
40
50
|
onChange={(event) => onChange(parseInt(event.target.value))}
|
|
41
|
-
value={
|
|
51
|
+
value={fieldValue}
|
|
42
52
|
disabled={disabled}
|
|
43
53
|
/>
|
|
44
54
|
);
|
|
@@ -35,7 +35,7 @@ export const WfoMultiCheckboxField: PydanticFormControlledElement = ({
|
|
|
35
35
|
|
|
36
36
|
const { options, id } = pydanticFormField;
|
|
37
37
|
|
|
38
|
-
const checkboxes = options
|
|
38
|
+
const checkboxes = options?.map((option, index) => ({
|
|
39
39
|
label: option.label,
|
|
40
40
|
id: option.value,
|
|
41
41
|
'data-test-id': `${id}-${index}`,
|
|
@@ -59,7 +59,7 @@ export const WfoMultiCheckboxField: PydanticFormControlledElement = ({
|
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
61
|
<EuiCheckboxGroup
|
|
62
|
-
options={checkboxes}
|
|
62
|
+
options={checkboxes || []}
|
|
63
63
|
idToSelectedMap={checkboxIdToSelectedMap}
|
|
64
64
|
onChange={(id) => handleCheckboxChange(id)}
|
|
65
65
|
data-testid={id}
|
|
@@ -10,7 +10,7 @@ export const WfoRadio: PydanticFormControlledElement = ({
|
|
|
10
10
|
value,
|
|
11
11
|
disabled,
|
|
12
12
|
}) => {
|
|
13
|
-
const radioOptions = pydanticFormField.options
|
|
13
|
+
const radioOptions = pydanticFormField.options?.map((option) => ({
|
|
14
14
|
id: option.value,
|
|
15
15
|
label: option.label,
|
|
16
16
|
}));
|
|
@@ -18,7 +18,7 @@ export const WfoRadio: PydanticFormControlledElement = ({
|
|
|
18
18
|
return (
|
|
19
19
|
<EuiRadioGroup
|
|
20
20
|
data-testid={pydanticFormField.id}
|
|
21
|
-
options={radioOptions}
|
|
21
|
+
options={radioOptions || []}
|
|
22
22
|
idSelected={value}
|
|
23
23
|
onChange={(id) => onChange(id)}
|
|
24
24
|
name={pydanticFormField.id}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import ReactSelect, { components } from 'react-select';
|
|
3
3
|
import type { GroupBase, InputProps } from 'react-select';
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ import { getWfoReactSelectStyles } from './styles';
|
|
|
13
13
|
interface WfoReactSelectProps<ValueType> {
|
|
14
14
|
options: Option<ValueType>[];
|
|
15
15
|
id: string;
|
|
16
|
-
onChange: (value: ValueType | undefined) => void;
|
|
16
|
+
onChange: (value: ValueType | undefined | null) => void;
|
|
17
17
|
value: ValueType;
|
|
18
18
|
disabled?: boolean;
|
|
19
19
|
isLoading?: boolean;
|
|
@@ -33,19 +33,21 @@ export const WfoReactSelect = <ValueType,>({
|
|
|
33
33
|
hasError = false,
|
|
34
34
|
refetch,
|
|
35
35
|
}: WfoReactSelectProps<ValueType>) => {
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
const selectedValue = options.find(
|
|
38
|
-
(option: Option<ValueType>) => option.value === value,
|
|
39
|
-
);
|
|
40
|
-
setSelectedValue(selectedValue || null);
|
|
41
|
-
}, [options, value]);
|
|
42
|
-
|
|
43
36
|
const initialValue = options.find(
|
|
44
37
|
(option: Option<ValueType>) => option.value === value,
|
|
45
38
|
);
|
|
46
39
|
|
|
47
40
|
const [selectedValue, setSelectedValue] =
|
|
48
|
-
|
|
41
|
+
useState<Option<ValueType> | null>(initialValue || null);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const preSelectedValue = options.find(
|
|
45
|
+
(option: Option<ValueType>) => option.value === value,
|
|
46
|
+
);
|
|
47
|
+
if (preSelectedValue !== selectedValue) {
|
|
48
|
+
setSelectedValue(preSelectedValue || null);
|
|
49
|
+
}
|
|
50
|
+
}, [options, selectedValue, value]);
|
|
49
51
|
|
|
50
52
|
// React select allows callbacks to supply style for innercomponents: https://react-select.com/styles#inner-components
|
|
51
53
|
const {
|
|
@@ -89,12 +91,12 @@ export const WfoReactSelect = <ValueType,>({
|
|
|
89
91
|
id={id}
|
|
90
92
|
inputId={`${id}.search`}
|
|
91
93
|
onChange={(option) => {
|
|
94
|
+
// By default reactSelect reverts to the initial option when cleared.
|
|
95
|
+
// This is to make sure we can also deselect the value after it is
|
|
96
|
+
// initialized from error state that sets it to the latest value.
|
|
92
97
|
if (option === null) {
|
|
93
|
-
// By default reactSelect reverts to the initial option when cleared
|
|
94
|
-
// this is to make sure we can also deselect the value after it is
|
|
95
|
-
// initialized from error state for example.
|
|
96
98
|
setSelectedValue(null);
|
|
97
|
-
onChange(
|
|
99
|
+
onChange(null);
|
|
98
100
|
} else {
|
|
99
101
|
const selectedValue = option?.value;
|
|
100
102
|
setSelectedValue(option);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
+
import _ from 'lodash';
|
|
3
4
|
import type { PydanticFormControlledElement } from 'pydantic-forms';
|
|
5
|
+
import { getFormFieldIdWithPath } from 'pydantic-forms';
|
|
4
6
|
|
|
5
7
|
import { EuiFieldText } from '@elastic/eui';
|
|
6
8
|
|
|
@@ -16,14 +18,20 @@ export const WfoText: PydanticFormControlledElement = ({
|
|
|
16
18
|
const { formFieldBaseStyle } = useWithOrchestratorTheme(
|
|
17
19
|
getFormFieldsBaseStyle,
|
|
18
20
|
);
|
|
19
|
-
|
|
21
|
+
// If the field is part of an array the value is passed in as an object with the field name as key
|
|
22
|
+
// this is imposed by react-hook-form. We try to detect this and extract the actual value
|
|
23
|
+
const fieldName = getFormFieldIdWithPath(pydanticFormField.id);
|
|
24
|
+
const fieldValue =
|
|
25
|
+
_.isObject(value) && _.has(value, fieldName)
|
|
26
|
+
? _.get(value, fieldName)
|
|
27
|
+
: value;
|
|
20
28
|
return (
|
|
21
29
|
<EuiFieldText
|
|
22
30
|
data-testid={pydanticFormField.id}
|
|
23
31
|
css={formFieldBaseStyle}
|
|
24
32
|
disabled={disabled}
|
|
25
33
|
onChange={(event) => onChange(event.target.value)}
|
|
26
|
-
value={
|
|
34
|
+
value={fieldValue}
|
|
27
35
|
fullWidth
|
|
28
36
|
/>
|
|
29
37
|
);
|
|
@@ -6,8 +6,10 @@ import { useRouter } from 'next/router';
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
EuiButton,
|
|
9
|
+
EuiButtonIcon,
|
|
9
10
|
EuiContextMenuItem,
|
|
10
11
|
EuiContextMenuPanel,
|
|
12
|
+
EuiLoadingSpinner,
|
|
11
13
|
EuiPanel,
|
|
12
14
|
EuiPopover,
|
|
13
15
|
EuiTitle,
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
useWithOrchestratorTheme,
|
|
24
26
|
} from '@/hooks';
|
|
25
27
|
import { WfoXCircleFill } from '@/icons';
|
|
28
|
+
import { WfoDotsHorizontal } from '@/icons/WfoDotsHorizontal';
|
|
26
29
|
import { useGetSubscriptionActionsQuery } from '@/rtk/endpoints/subscriptionActions';
|
|
27
30
|
import { SubscriptionAction, WorkflowTarget } from '@/types';
|
|
28
31
|
|
|
@@ -37,6 +40,7 @@ type MenuItemProps = {
|
|
|
37
40
|
index: number;
|
|
38
41
|
target: WorkflowTarget;
|
|
39
42
|
isTask?: boolean;
|
|
43
|
+
isDisabled?: boolean;
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
type MenuBlockProps = {
|
|
@@ -51,11 +55,13 @@ const MenuBlock: FC<MenuBlockProps> = ({ title }) => (
|
|
|
51
55
|
export type WfoSubscriptionActionsProps = {
|
|
52
56
|
subscriptionId: string;
|
|
53
57
|
isLoading?: boolean;
|
|
58
|
+
compactMode?: boolean;
|
|
54
59
|
};
|
|
55
60
|
|
|
56
61
|
export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
57
62
|
subscriptionId,
|
|
58
63
|
isLoading,
|
|
64
|
+
compactMode = false,
|
|
59
65
|
}) => {
|
|
60
66
|
const { theme } = useOrchestratorTheme();
|
|
61
67
|
const {
|
|
@@ -69,35 +75,30 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
69
75
|
const router = useRouter();
|
|
70
76
|
const t = useTranslations('subscriptions.detail.actions');
|
|
71
77
|
const [isPopoverOpen, setPopover] = useState(false);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
const disableQuery = isLoading || (!isPopoverOpen && compactMode);
|
|
79
|
+
const {
|
|
80
|
+
data: subscriptionActions,
|
|
81
|
+
isLoading: subscriptionActionsIsLoading,
|
|
82
|
+
} = useGetSubscriptionActionsQuery(
|
|
83
|
+
{ subscriptionId },
|
|
84
|
+
{ skip: disableQuery },
|
|
77
85
|
);
|
|
78
86
|
const { isEngineRunningNow } = useCheckEngineStatus();
|
|
79
87
|
const { isAllowed } = usePolicy();
|
|
80
88
|
|
|
81
|
-
const onButtonClick = () =>
|
|
82
|
-
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const closePopover = () => {
|
|
86
|
-
setPopover(false);
|
|
87
|
-
};
|
|
89
|
+
const onButtonClick = () => setPopover(!isPopoverOpen);
|
|
90
|
+
const closePopover = () => setPopover(false);
|
|
88
91
|
|
|
89
92
|
const MenuItem: FC<MenuItemProps> = ({
|
|
90
93
|
action,
|
|
91
94
|
target,
|
|
92
95
|
isTask = false,
|
|
93
96
|
}) => {
|
|
94
|
-
// Change icon to include x if there's a reason
|
|
95
|
-
// Add tooltip with reason
|
|
96
97
|
const linkIt = (actionItem: React.ReactNode) => {
|
|
97
98
|
const path = isTask ? PATH_START_NEW_TASK : PATH_START_NEW_WORKFLOW;
|
|
98
99
|
const url = {
|
|
99
100
|
pathname: `${path}/${action.name}`,
|
|
100
|
-
query: { subscriptionId
|
|
101
|
+
query: { subscriptionId },
|
|
101
102
|
};
|
|
102
103
|
|
|
103
104
|
const handleLinkClick = async (e: React.MouseEvent) => {
|
|
@@ -116,35 +117,7 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
const tooltipIt = (actionItem: React.ReactNode) => {
|
|
119
|
-
/**
|
|
120
|
-
Whether an action is disabled is indicated by it having a reason property.
|
|
121
|
-
The value of the reason property is as a translation key that should
|
|
122
|
-
be part of the local translations under subscription.details.workflow.disableReasons
|
|
123
|
-
Some of these reasons may contain dynamic values. The values are passed as extra keys next to
|
|
124
|
-
the reason key. The complete reason object is passed to the translate function to make this work.
|
|
125
|
-
An extra variable passed in might be of type array, before passing it in arrays are flattened to ,
|
|
126
|
-
concatenated strings.
|
|
127
|
-
|
|
128
|
-
Example action item response for an action that is disabled
|
|
129
|
-
const reason = {
|
|
130
|
-
name: "...",
|
|
131
|
-
description: "...",
|
|
132
|
-
reason: "random_reason_translation_key" =>
|
|
133
|
-
this maps to a key in subscription.details.workflow.disableReasons containing
|
|
134
|
-
".... {randomVar1} .... {randomVar2} "
|
|
135
|
-
randomVar: [
|
|
136
|
-
"array value 1",
|
|
137
|
-
"array value 2"
|
|
138
|
-
],
|
|
139
|
-
randomVar2: "flat string"
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Translation function invocation
|
|
144
|
-
t('randonReason', reason)
|
|
145
|
-
*/
|
|
146
120
|
if (!action.reason) return actionItem;
|
|
147
|
-
|
|
148
121
|
const tooltipContent = t(action.reason, flattenArrayProps(action));
|
|
149
122
|
|
|
150
123
|
return (
|
|
@@ -161,10 +134,10 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
161
134
|
);
|
|
162
135
|
};
|
|
163
136
|
|
|
164
|
-
const getIcon = () =>
|
|
165
|
-
|
|
137
|
+
const getIcon = () =>
|
|
138
|
+
action.reason ? (
|
|
166
139
|
<div css={disabledIconStyle}>
|
|
167
|
-
<WfoTargetTypeIcon target={target} disabled
|
|
140
|
+
<WfoTargetTypeIcon target={target} disabled />
|
|
168
141
|
<div css={secondaryIconStyle}>
|
|
169
142
|
<WfoXCircleFill
|
|
170
143
|
width={20}
|
|
@@ -178,7 +151,6 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
178
151
|
<WfoTargetTypeIcon target={target} />
|
|
179
152
|
</div>
|
|
180
153
|
);
|
|
181
|
-
};
|
|
182
154
|
|
|
183
155
|
const ActionItem = () => (
|
|
184
156
|
<EuiContextMenuItem icon={getIcon()} disabled={!!action.reason}>
|
|
@@ -191,7 +163,14 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
191
163
|
: linkIt(<ActionItem />);
|
|
192
164
|
};
|
|
193
165
|
|
|
194
|
-
const button = (
|
|
166
|
+
const button = compactMode ? (
|
|
167
|
+
<EuiButtonIcon
|
|
168
|
+
iconType={() => <WfoDotsHorizontal />}
|
|
169
|
+
onClick={onButtonClick}
|
|
170
|
+
aria-label="Row context menu"
|
|
171
|
+
isLoading={isLoading}
|
|
172
|
+
/>
|
|
173
|
+
) : (
|
|
195
174
|
<EuiButton
|
|
196
175
|
iconType="arrowDown"
|
|
197
176
|
iconSide="right"
|
|
@@ -202,6 +181,83 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
202
181
|
</EuiButton>
|
|
203
182
|
);
|
|
204
183
|
|
|
184
|
+
const {
|
|
185
|
+
SUBSCRIPTION_VALIDATE,
|
|
186
|
+
SUBSCRIPTION_RECONCILE,
|
|
187
|
+
SUBSCRIPTION_MODIFY,
|
|
188
|
+
SUBSCRIPTION_TERMINATE,
|
|
189
|
+
} = PolicyResource;
|
|
190
|
+
const compactItems = (
|
|
191
|
+
<>
|
|
192
|
+
{isAllowed(SUBSCRIPTION_VALIDATE + subscriptionId) &&
|
|
193
|
+
subscriptionActions?.validate && (
|
|
194
|
+
<>
|
|
195
|
+
{!compactMode && <MenuBlock title={t('tasks')} />}
|
|
196
|
+
{subscriptionActions.validate.map((action, index) => (
|
|
197
|
+
<MenuItem
|
|
198
|
+
key={`s_${index}`}
|
|
199
|
+
action={action}
|
|
200
|
+
index={index}
|
|
201
|
+
target={WorkflowTarget.VALIDATE}
|
|
202
|
+
isTask
|
|
203
|
+
/>
|
|
204
|
+
))}
|
|
205
|
+
</>
|
|
206
|
+
)}
|
|
207
|
+
|
|
208
|
+
{isAllowed(SUBSCRIPTION_RECONCILE + subscriptionId) &&
|
|
209
|
+
(subscriptionActions?.reconcile?.length ?? 0) > 0 && (
|
|
210
|
+
<>
|
|
211
|
+
{!compactMode && <MenuBlock title={t('reconcile')} />}
|
|
212
|
+
{subscriptionActions?.reconcile.map((action, index) => (
|
|
213
|
+
<MenuItem
|
|
214
|
+
key={`r_${index}`}
|
|
215
|
+
action={action}
|
|
216
|
+
index={index}
|
|
217
|
+
target={WorkflowTarget.RECONCILE}
|
|
218
|
+
/>
|
|
219
|
+
))}
|
|
220
|
+
</>
|
|
221
|
+
)}
|
|
222
|
+
</>
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const fullItems = (
|
|
226
|
+
<>
|
|
227
|
+
{isAllowed(SUBSCRIPTION_MODIFY + subscriptionId) &&
|
|
228
|
+
subscriptionActions?.modify && (
|
|
229
|
+
<>
|
|
230
|
+
<MenuBlock title={t('modify')} />
|
|
231
|
+
{subscriptionActions.modify.map((action, index) => (
|
|
232
|
+
<MenuItem
|
|
233
|
+
key={`m_${index}`}
|
|
234
|
+
action={action}
|
|
235
|
+
index={index}
|
|
236
|
+
target={WorkflowTarget.MODIFY}
|
|
237
|
+
/>
|
|
238
|
+
))}
|
|
239
|
+
</>
|
|
240
|
+
)}
|
|
241
|
+
{compactItems}
|
|
242
|
+
{isAllowed(SUBSCRIPTION_TERMINATE + subscriptionId) &&
|
|
243
|
+
subscriptionActions?.terminate && (
|
|
244
|
+
<>
|
|
245
|
+
<MenuBlock title={t('terminate')} />
|
|
246
|
+
{subscriptionActions.terminate.map((action, index) => (
|
|
247
|
+
<MenuItem
|
|
248
|
+
key={`t_${index}`}
|
|
249
|
+
action={action}
|
|
250
|
+
index={index}
|
|
251
|
+
target={WorkflowTarget.TERMINATE}
|
|
252
|
+
/>
|
|
253
|
+
))}
|
|
254
|
+
</>
|
|
255
|
+
)}
|
|
256
|
+
</>
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const MenuItemsList = () => (compactMode ? compactItems : fullItems);
|
|
260
|
+
|
|
205
261
|
return (
|
|
206
262
|
<EuiPopover
|
|
207
263
|
id="subscriptionActionPopover"
|
|
@@ -213,68 +269,11 @@ export const WfoSubscriptionActions: FC<WfoSubscriptionActionsProps> = ({
|
|
|
213
269
|
>
|
|
214
270
|
<EuiContextMenuPanel>
|
|
215
271
|
<EuiPanel color="transparent" paddingSize="s">
|
|
216
|
-
{
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
<>
|
|
222
|
-
<MenuBlock title={t('modify')}></MenuBlock>
|
|
223
|
-
{subscriptionActions.modify.map(
|
|
224
|
-
(action, index) => (
|
|
225
|
-
<MenuItem
|
|
226
|
-
key={`m_${index}`}
|
|
227
|
-
action={action}
|
|
228
|
-
index={index}
|
|
229
|
-
target={WorkflowTarget.MODIFY}
|
|
230
|
-
/>
|
|
231
|
-
),
|
|
232
|
-
)}
|
|
233
|
-
</>
|
|
234
|
-
)}
|
|
235
|
-
|
|
236
|
-
{subscriptionActions &&
|
|
237
|
-
isAllowed(
|
|
238
|
-
PolicyResource.SUBSCRIPTION_VALIDATE +
|
|
239
|
-
subscriptionId,
|
|
240
|
-
) &&
|
|
241
|
-
subscriptionActions.validate && (
|
|
242
|
-
<>
|
|
243
|
-
<MenuBlock title={t('tasks')}></MenuBlock>
|
|
244
|
-
{subscriptionActions.validate.map(
|
|
245
|
-
(action, index) => (
|
|
246
|
-
<MenuItem
|
|
247
|
-
key={`s_${index}`}
|
|
248
|
-
action={action}
|
|
249
|
-
index={index}
|
|
250
|
-
target={WorkflowTarget.VALIDATE}
|
|
251
|
-
isTask={true}
|
|
252
|
-
/>
|
|
253
|
-
),
|
|
254
|
-
)}
|
|
255
|
-
</>
|
|
256
|
-
)}
|
|
257
|
-
|
|
258
|
-
{subscriptionActions &&
|
|
259
|
-
isAllowed(
|
|
260
|
-
PolicyResource.SUBSCRIPTION_TERMINATE +
|
|
261
|
-
subscriptionId,
|
|
262
|
-
) &&
|
|
263
|
-
subscriptionActions.terminate && (
|
|
264
|
-
<>
|
|
265
|
-
<MenuBlock title={t('terminate')}></MenuBlock>
|
|
266
|
-
{subscriptionActions.terminate.map(
|
|
267
|
-
(action, index) => (
|
|
268
|
-
<MenuItem
|
|
269
|
-
key={`t_${index}`}
|
|
270
|
-
action={action}
|
|
271
|
-
index={index}
|
|
272
|
-
target={WorkflowTarget.TERMINATE}
|
|
273
|
-
/>
|
|
274
|
-
),
|
|
275
|
-
)}
|
|
276
|
-
</>
|
|
277
|
-
)}
|
|
272
|
+
{subscriptionActionsIsLoading ? (
|
|
273
|
+
<EuiLoadingSpinner />
|
|
274
|
+
) : (
|
|
275
|
+
<MenuItemsList />
|
|
276
|
+
)}
|
|
278
277
|
</EuiPanel>
|
|
279
278
|
</EuiContextMenuPanel>
|
|
280
279
|
</EuiPopover>
|
|
@@ -74,6 +74,8 @@ export const getWorkflowTargetColor = (
|
|
|
74
74
|
case WorkflowTarget.SYSTEM:
|
|
75
75
|
case WorkflowTarget.VALIDATE:
|
|
76
76
|
return theme.colors.warning;
|
|
77
|
+
case WorkflowTarget.RECONCILE:
|
|
78
|
+
return theme.colors.accent;
|
|
77
79
|
case WorkflowTarget.TERMINATE:
|
|
78
80
|
return theme.colors.danger;
|
|
79
81
|
}
|
|
@@ -93,6 +95,8 @@ export const getWorkflowTargetIconContent = (
|
|
|
93
95
|
return 'T';
|
|
94
96
|
case WorkflowTarget.TERMINATE:
|
|
95
97
|
return 'X';
|
|
98
|
+
case WorkflowTarget.RECONCILE:
|
|
99
|
+
return 'R';
|
|
96
100
|
default:
|
|
97
101
|
return 'M';
|
|
98
102
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
WfoInlineJson,
|
|
16
16
|
WfoInsyncIcon,
|
|
17
17
|
WfoJsonCodeBlock,
|
|
18
|
+
WfoSubscriptionActions,
|
|
18
19
|
WfoSubscriptionNoteEdit,
|
|
19
20
|
WfoSubscriptionStatusBadge,
|
|
20
21
|
getPageIndexChangeHandler,
|
|
@@ -178,6 +179,17 @@ export const WfoSubscriptionsList: FC<WfoSubscriptionsListProps> = ({
|
|
|
178
179
|
);
|
|
179
180
|
},
|
|
180
181
|
},
|
|
182
|
+
actions: {
|
|
183
|
+
columnType: ColumnType.CONTROL,
|
|
184
|
+
label: t('actions'),
|
|
185
|
+
width: '80px',
|
|
186
|
+
renderControl: (row) => (
|
|
187
|
+
<WfoSubscriptionActions
|
|
188
|
+
compactMode={true}
|
|
189
|
+
subscriptionId={row.subscriptionId}
|
|
190
|
+
/>
|
|
191
|
+
),
|
|
192
|
+
},
|
|
181
193
|
metadata: {
|
|
182
194
|
columnType: ColumnType.DATA,
|
|
183
195
|
label: t('metadata'),
|
|
@@ -13,6 +13,7 @@ export enum PolicyResource {
|
|
|
13
13
|
SUBSCRIPTION_CREATE = '/orchestrator/processes/create/process/menu',
|
|
14
14
|
SUBSCRIPTION_MODIFY = '/orchestrator/subscriptions/modify/',
|
|
15
15
|
SUBSCRIPTION_TERMINATE = '/orchestrator/subscriptions/terminate/',
|
|
16
|
+
SUBSCRIPTION_RECONCILE = '/orchestrator/subscriptions/reconcile/',
|
|
16
17
|
SUBSCRIPTION_VALIDATE = '/orchestrator/subscriptions/validate/',
|
|
17
18
|
TASKS_CREATE = '/orchestrator/processes/create/task',
|
|
18
19
|
TASKS_RETRY_ALL = '/orchestrator/processes/all-tasks/retry',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ORCHESTRATOR_UI_LIBRARY_VERSION = '5.
|
|
1
|
+
export const ORCHESTRATOR_UI_LIBRARY_VERSION = '5.8.1';
|
package/src/messages/en-GB.json
CHANGED
|
@@ -307,8 +307,13 @@
|
|
|
307
307
|
"modify": "Modify workflow",
|
|
308
308
|
"tasks": "Tasks",
|
|
309
309
|
"terminate": "Terminate workflow",
|
|
310
|
+
"reconcile": "Reconcile workflow",
|
|
310
311
|
"actions": "Actions",
|
|
311
312
|
"lockedBySubscriptions": "This action is locked by the following subscriptions:",
|
|
313
|
+
"notAvailable": "Not available",
|
|
314
|
+
"notAvailableForWorkflow": "Not available for this workflow",
|
|
315
|
+
"reconcileSubscription": "Reconcile subscription",
|
|
316
|
+
"validateSubscription": "Validate subscription",
|
|
312
317
|
"subscription": {
|
|
313
318
|
"no_modify_deleted_related_objects": "This subscription can not be modified because it contains references to other systems that are deleted.",
|
|
314
319
|
"no_modify_in_use_by_subscription": "This subscription can not be {action} as it is used in other subscriptions: {unterminated_in_use_by_subscriptions}",
|
package/src/messages/nl-NL.json
CHANGED
|
@@ -304,6 +304,11 @@
|
|
|
304
304
|
"modify": "Modify workflow",
|
|
305
305
|
"tasks": "Taken",
|
|
306
306
|
"terminate": "Terminate workflow",
|
|
307
|
+
"reconcile": "Reconcile workflow",
|
|
308
|
+
"notAvailable": "Niet beschikbaar",
|
|
309
|
+
"notAvailableForWorkflow": "Niet beschikbaar voor deze workflow",
|
|
310
|
+
"reconcileSubscription": "Reconcile subscription",
|
|
311
|
+
"validateSubscription": "Validate subscription",
|
|
307
312
|
"actions": "Acties",
|
|
308
313
|
"lockedBySubscriptions": "Deze actie is geblokkeerd door de volgende subscriptions:",
|
|
309
314
|
"subscription": {
|