@orchestrator-ui/orchestrator-ui-components 5.7.0 → 5.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchestrator-ui/orchestrator-ui-components",
3
- "version": "5.7.0",
3
+ "version": "5.8.0",
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.0",
51
+ "pydantic-forms": "^0.9.1",
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),
@@ -16,7 +16,7 @@ export const WfoLabel: PydanticFormElement = ({ pydanticFormField }) => {
16
16
  }}
17
17
  id={pydanticFormField.id}
18
18
  >
19
- {pydanticFormField.title}
19
+ {pydanticFormField.default || pydanticFormField.title}
20
20
  </label>
21
21
  </div>
22
22
  );
@@ -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 { data: subscriptionActions } = useGetSubscriptionActionsQuery(
73
- {
74
- subscriptionId,
75
- },
76
- { skip: isLoading },
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
- setPopover(!isPopoverOpen);
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: 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
- return action.reason ? (
137
+ const getIcon = () =>
138
+ action.reason ? (
166
139
  <div css={disabledIconStyle}>
167
- <WfoTargetTypeIcon target={target} disabled={true} />
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
- {subscriptionActions &&
217
- isAllowed(
218
- PolicyResource.SUBSCRIPTION_MODIFY + subscriptionId,
219
- ) &&
220
- subscriptionActions.modify && (
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.7.0';
1
+ export const ORCHESTRATOR_UI_LIBRARY_VERSION = '5.8.0';
@@ -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}",
@@ -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": {
@@ -35,7 +35,7 @@ query MetadataWorkflows(
35
35
  after: $after
36
36
  sortBy: $sortBy
37
37
  query: $query
38
- filterBy: { field: "target", value: "CREATE|MODIFY|TERMINATE" }
38
+ filterBy: { field: "target", value: "CREATE|MODIFY|TERMINATE|RECONCILE" }
39
39
  ) {
40
40
  page {
41
41
  workflowId
@@ -145,6 +145,7 @@ export enum WorkflowTarget {
145
145
  TERMINATE = 'terminate',
146
146
  SYSTEM = 'system',
147
147
  VALIDATE = 'validate',
148
+ RECONCILE = 'reconcile',
148
149
  }
149
150
 
150
151
  export type Process = {
@@ -621,6 +622,7 @@ export type SubscriptionActions = {
621
622
  terminate: SubscriptionAction[];
622
623
  system: SubscriptionAction[];
623
624
  validate: SubscriptionAction[];
625
+ reconcile: SubscriptionAction[];
624
626
  };
625
627
 
626
628
  export enum CacheTagType {