@orchestrator-ui/orchestrator-ui-components 1.6.1 → 1.7.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": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Library of UI Components used to display the workflow orchestrator frontend",
6
6
  "author": {
@@ -42,6 +42,7 @@ export function WfoProductBlockBadge({
42
42
  textColor: primaryText,
43
43
  };
44
44
  case BadgeType.WORKFLOW:
45
+ case BadgeType.TASK:
45
46
  case BadgeType.PRODUCT:
46
47
  return {
47
48
  badgeColor: toSecondaryColor(danger),
@@ -16,6 +16,7 @@ import {
16
16
  PATH_METADATA_PRODUCTS,
17
17
  PATH_METADATA_PRODUCT_BLOCKS,
18
18
  PATH_METADATA_RESOURCE_TYPES,
19
+ PATH_METADATA_TASKS,
19
20
  PATH_METADATA_WORKFLOWS,
20
21
  PATH_SETTINGS,
21
22
  PATH_START,
@@ -128,6 +129,15 @@ export const WfoSidebar: FC<WfoSidebarProps> = ({ overrideMenuItems }) => {
128
129
  router.push(PATH_METADATA_WORKFLOWS);
129
130
  },
130
131
  },
132
+ {
133
+ name: t('metadataTasks'),
134
+ id: '5.5',
135
+ isSelected: router.pathname === PATH_METADATA_TASKS,
136
+ onClick: (e) => {
137
+ e.preventDefault();
138
+ router.push(PATH_METADATA_TASKS);
139
+ },
140
+ },
131
141
  ],
132
142
  },
133
143
  {
@@ -8,5 +8,6 @@ export const PATH_METADATA_PRODUCTS = '/metadata/products';
8
8
  export const PATH_METADATA_PRODUCT_BLOCKS = '/metadata/productblocks';
9
9
  export const PATH_METADATA_RESOURCE_TYPES = '/metadata/resource-types';
10
10
  export const PATH_METADATA_WORKFLOWS = '/metadata/workflows';
11
+ export const PATH_METADATA_TASKS = '/metadata/tasks';
11
12
  export const PATH_TASKS = '/tasks';
12
13
  export const PATH_SETTINGS = '/settings';
@@ -17,5 +17,6 @@ export const METADATA_PRODUCT_BLOCKS_TABLE_LOCAL_STORAGE_KEY =
17
17
  export const METADATA_PRODUCT_TABLE_LOCAL_STORAGE_KEY = 'metadataProductTable';
18
18
  export const METADATA_WORKFLOWS_TABLE_LOCAL_STORAGE_KEY =
19
19
  'metadataWorkflowsTable';
20
+ export const METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY = 'metadataTasksTable';
20
21
 
21
22
  export const SUBSCRIPTIONS_TABLE_LOCAL_STORAGE_KEY = 'subscriptionsTable';
@@ -5,6 +5,7 @@
5
5
  "metadataProductblocks": "Product blocks",
6
6
  "metadataResourceTypes": "Resource types",
7
7
  "metadataWorkflows": "Workflows",
8
+ "metadataTasks": "Tasks",
8
9
  "mobileTitle": "Main menu",
9
10
  "settings": "Settings",
10
11
  "start": "Start",
@@ -126,7 +127,8 @@
126
127
  "products": "Products",
127
128
  "productBlocks": "Product blocks",
128
129
  "resourceTypes": "Resource types",
129
- "workflows": "Workflows"
130
+ "workflows": "Workflows",
131
+ "tasks": "Tasks"
130
132
  },
131
133
  "products": {
132
134
  "id": "ID",
@@ -163,6 +165,13 @@
163
165
  "target": "Target",
164
166
  "productTags": "Product tags",
165
167
  "createdAt": "Created"
168
+ },
169
+ "tasks": {
170
+ "name": "Task",
171
+ "description": "Task description",
172
+ "target": "Target",
173
+ "productTags": "Product tags",
174
+ "createdAt": "Created"
166
175
  }
167
176
  },
168
177
  "processes": {
@@ -5,6 +5,7 @@
5
5
  "metadataProductblocks": "Product blocks",
6
6
  "metadataResourceTypes": "Resource types",
7
7
  "metadataWorkflows": "Workflows",
8
+ "metadataTasks": "Taken",
8
9
  "mobileTitle": "Hoofdmenu",
9
10
  "settings": "Settings",
10
11
  "start": "Start",
@@ -125,7 +126,8 @@
125
126
  "products": "Producten",
126
127
  "productBlocks": "Product blocks",
127
128
  "resourceTypes": "Resource types",
128
- "workflows": "Workflows"
129
+ "workflows": "Workflows",
130
+ "tasks": "Taken"
129
131
  },
130
132
  "products": {
131
133
  "id": "ID",
@@ -162,6 +164,13 @@
162
164
  "target": "Target",
163
165
  "productTags": "Product tags",
164
166
  "createdAt": "Aangemaakt"
167
+ },
168
+ "tasks": {
169
+ "name": "Taak",
170
+ "description": "Taak beschrijving",
171
+ "target": "Target",
172
+ "productTags": "Product tags",
173
+ "createdAt": "Aangemaakt"
165
174
  }
166
175
  },
167
176
  "processes": {
@@ -34,10 +34,15 @@ export const metaDataTabs: MetaDataTab[] = [
34
34
  path: '/metadata/resource-types',
35
35
  },
36
36
  {
37
- id: 5,
37
+ id: 4,
38
38
  translationKey: 'workflows',
39
39
  path: '/metadata/workflows',
40
40
  },
41
+ {
42
+ id: 5,
43
+ translationKey: 'tasks',
44
+ path: '/metadata/tasks',
45
+ },
41
46
  ];
42
47
 
43
48
  export const WfoMetadataPageLayout = ({
@@ -0,0 +1,226 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import { EuiBadgeGroup } from '@elastic/eui';
6
+ import type { Pagination } from '@elastic/eui/src/components';
7
+
8
+ import { WfoTableWithFilter, WfoWorkflowTargetBadge } from '@/components';
9
+ import type { WfoDataSorting, WfoTableColumns } from '@/components';
10
+ import { StoredTableConfig } from '@/components';
11
+ import {
12
+ DEFAULT_PAGE_SIZE,
13
+ DEFAULT_PAGE_SIZES,
14
+ METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY,
15
+ WfoProductBlockBadge,
16
+ } from '@/components';
17
+ import {
18
+ getDataSortHandler,
19
+ getPageChangeHandler,
20
+ getQueryStringHandler,
21
+ } from '@/components';
22
+ import { WfoDateTime } from '@/components/WfoDateTime/WfoDateTime';
23
+ import { mapSortableAndFilterableValuesToTableColumnConfig } from '@/components/WfoTable/utils/mapSortableAndFilterableValuesToTableColumnConfig';
24
+ import {
25
+ useDataDisplayParams,
26
+ useShowToastMessage,
27
+ useStoredTableConfig,
28
+ } from '@/hooks';
29
+ import { useGetTasksQuery, useLazyGetTasksQuery } from '@/rtk';
30
+ import type { GraphqlQueryVariables, TaskDefinition } from '@/types';
31
+ import { BadgeType, SortOrder } from '@/types';
32
+ import {
33
+ getQueryVariablesForExport,
34
+ onlyUnique,
35
+ parseDateToLocaleDateTimeString,
36
+ parseIsoString,
37
+ } from '@/utils';
38
+ import {
39
+ csvDownloadHandler,
40
+ getCsvFileNameWithDate,
41
+ } from '@/utils/csvDownload';
42
+
43
+ import { WfoMetadataPageLayout } from './WfoMetadataPageLayout';
44
+ import {
45
+ graphQlTaskListMapper,
46
+ mapTaskDefinitionToTaskListItem,
47
+ } from './taskListObjectMapper';
48
+
49
+ export type TaskListItem = Pick<
50
+ TaskDefinition,
51
+ 'name' | 'description' | 'target' | 'createdAt'
52
+ > & {
53
+ productTags: string[];
54
+ };
55
+
56
+ export const WfoTasksPage = () => {
57
+ const t = useTranslations('metadata.tasks');
58
+ const tError = useTranslations('errors');
59
+ const { showToastMessage } = useShowToastMessage();
60
+
61
+ const [tableDefaults, setTableDefaults] =
62
+ useState<StoredTableConfig<TaskListItem>>();
63
+
64
+ const getStoredTableConfig = useStoredTableConfig<TaskListItem>(
65
+ METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY,
66
+ );
67
+
68
+ useEffect(() => {
69
+ const storedConfig = getStoredTableConfig();
70
+
71
+ if (storedConfig) {
72
+ setTableDefaults(storedConfig);
73
+ }
74
+ }, [getStoredTableConfig]);
75
+
76
+ const { dataDisplayParams, setDataDisplayParam } =
77
+ useDataDisplayParams<TaskListItem>({
78
+ // TODO: Improvement: A default pageSize value is set to avoid a graphql error when the query is executed
79
+ // the fist time before the useEffect has populated the tableDefaults. Better is to create a way for
80
+ // the query to wait for the values to be available
81
+ // https://github.com/workfloworchestrator/orchestrator-ui/issues/261
82
+ pageSize: tableDefaults?.selectedPageSize || DEFAULT_PAGE_SIZE,
83
+ sortBy: {
84
+ field: 'name',
85
+ order: SortOrder.ASC,
86
+ },
87
+ });
88
+
89
+ const tableColumns: WfoTableColumns<TaskListItem> = {
90
+ name: {
91
+ field: 'name',
92
+ name: t('name'),
93
+ width: '20%',
94
+ render: (name) => (
95
+ <WfoProductBlockBadge badgeType={BadgeType.TASK}>
96
+ {name}
97
+ </WfoProductBlockBadge>
98
+ ),
99
+ },
100
+ description: {
101
+ field: 'description',
102
+ name: t('description'),
103
+ width: '40%',
104
+ },
105
+ target: {
106
+ field: 'target',
107
+ name: t('target'),
108
+ width: '15%',
109
+ render: (target) => <WfoWorkflowTargetBadge target={target} />,
110
+ },
111
+ productTags: {
112
+ field: 'productTags',
113
+ name: t('productTags'),
114
+ width: '20%',
115
+ render: (productTags) => (
116
+ <>
117
+ {productTags
118
+ ?.filter(onlyUnique)
119
+ .map((productTag, index) => (
120
+ <WfoProductBlockBadge
121
+ key={index}
122
+ badgeType={BadgeType.PRODUCT_TAG}
123
+ >
124
+ {productTag}
125
+ </WfoProductBlockBadge>
126
+ ))}
127
+ </>
128
+ ),
129
+ renderDetails: (productTags) => (
130
+ <EuiBadgeGroup gutterSize="s">
131
+ {productTags
132
+ ?.filter(onlyUnique)
133
+ .map((productTag, index) => (
134
+ <WfoProductBlockBadge
135
+ key={index}
136
+ badgeType={BadgeType.PRODUCT_TAG}
137
+ >
138
+ {productTag}
139
+ </WfoProductBlockBadge>
140
+ ))}
141
+ </EuiBadgeGroup>
142
+ ),
143
+ },
144
+ createdAt: {
145
+ field: 'createdAt',
146
+ name: t('createdAt'),
147
+ width: '15%',
148
+ render: (date) => <WfoDateTime dateOrIsoString={date} />,
149
+ renderDetails: parseIsoString(parseDateToLocaleDateTimeString),
150
+ clipboardText: parseIsoString(parseDateToLocaleDateTimeString),
151
+ },
152
+ };
153
+
154
+ const { pageSize, pageIndex, sortBy, queryString } = dataDisplayParams;
155
+
156
+ const taskListQueryVariables: GraphqlQueryVariables<TaskDefinition> = {
157
+ first: pageSize,
158
+ after: pageIndex * pageSize,
159
+ sortBy: graphQlTaskListMapper(sortBy),
160
+ query: queryString || undefined,
161
+ };
162
+ const { data, isFetching, isError } = useGetTasksQuery(
163
+ taskListQueryVariables,
164
+ );
165
+
166
+ const [getTasksTrigger, { isFetching: isFetchingCsv }] =
167
+ useLazyGetTasksQuery();
168
+
169
+ const getTasksForExport = () =>
170
+ getTasksTrigger(
171
+ getQueryVariablesForExport(taskListQueryVariables),
172
+ ).unwrap();
173
+
174
+ const dataSorting: WfoDataSorting<TaskListItem> = {
175
+ field: sortBy?.field ?? 'name',
176
+ sortOrder: sortBy?.order ?? SortOrder.ASC,
177
+ };
178
+
179
+ const { totalItems, sortFields, filterFields } = data?.pageInfo || {};
180
+
181
+ const pagination: Pagination = {
182
+ pageSize: pageSize,
183
+ pageIndex: pageIndex,
184
+ pageSizeOptions: DEFAULT_PAGE_SIZES,
185
+ totalItemCount: totalItems ? totalItems : 0,
186
+ };
187
+
188
+ return (
189
+ <WfoMetadataPageLayout>
190
+ <WfoTableWithFilter<TaskListItem>
191
+ data={data ? mapTaskDefinitionToTaskListItem(data.tasks) : []}
192
+ tableColumns={mapSortableAndFilterableValuesToTableColumnConfig(
193
+ tableColumns,
194
+ sortFields,
195
+ filterFields,
196
+ )}
197
+ dataSorting={dataSorting}
198
+ defaultHiddenColumns={tableDefaults?.hiddenColumns}
199
+ onUpdateDataSort={getDataSortHandler<TaskListItem>(
200
+ setDataDisplayParam,
201
+ )}
202
+ onUpdatePage={getPageChangeHandler<TaskListItem>(
203
+ setDataDisplayParam,
204
+ )}
205
+ onUpdateQueryString={getQueryStringHandler<TaskListItem>(
206
+ setDataDisplayParam,
207
+ )}
208
+ pagination={pagination}
209
+ isLoading={isFetching}
210
+ hasError={isError}
211
+ queryString={queryString}
212
+ localStorageKey={METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY}
213
+ onExportData={csvDownloadHandler(
214
+ getTasksForExport,
215
+ (data) => data.tasks,
216
+ (data) => data.pageInfo,
217
+ Object.keys(tableColumns),
218
+ getCsvFileNameWithDate('Tasks'),
219
+ showToastMessage,
220
+ tError,
221
+ )}
222
+ exportDataIsLoading={isFetchingCsv}
223
+ />
224
+ </WfoMetadataPageLayout>
225
+ );
226
+ };
@@ -98,7 +98,7 @@ export const WfoWorkflowsPage = () => {
98
98
  name: {
99
99
  field: 'name',
100
100
  name: t('name'),
101
- width: '200',
101
+ width: '20%',
102
102
  render: (name) => (
103
103
  <WfoProductBlockBadge badgeType={BadgeType.WORKFLOW}>
104
104
  {name}
@@ -108,17 +108,18 @@ export const WfoWorkflowsPage = () => {
108
108
  description: {
109
109
  field: 'description',
110
110
  name: t('description'),
111
- width: '300',
111
+ width: '40%',
112
112
  },
113
113
  target: {
114
114
  field: 'target',
115
115
  name: t('target'),
116
- width: '90',
116
+ width: '15%',
117
117
  render: (target) => <WfoWorkflowTargetBadge target={target} />,
118
118
  },
119
119
  productTags: {
120
120
  field: 'productTags',
121
121
  name: t('productTags'),
122
+ width: '20%',
122
123
  render: (productTags) => (
123
124
  <>
124
125
  {productTags
@@ -151,7 +152,7 @@ export const WfoWorkflowsPage = () => {
151
152
  createdAt: {
152
153
  field: 'createdAt',
153
154
  name: t('createdAt'),
154
- width: '110',
155
+ width: '15%',
155
156
  render: (date) => <WfoDateTime dateOrIsoString={date} />,
156
157
  renderDetails: parseIsoString(parseDateToLocaleDateTimeString),
157
158
  clipboardText: parseIsoString(parseDateToLocaleDateTimeString),
@@ -2,5 +2,6 @@ export * from './WfoProductBlocksPage';
2
2
  export * from './WfoResourceTypesPage';
3
3
  export * from './WfoProductsPage';
4
4
  export * from './WfoWorkflowsPage';
5
+ export * from './WfoTasksPage';
5
6
  export * from './WfoMetadataPageLayout';
6
7
  export * from './workflowListObjectMapper';
@@ -0,0 +1,40 @@
1
+ import { GraphQLSort, TaskDefinition } from '@/types';
2
+
3
+ import { TaskListItem } from './WfoTasksPage';
4
+
5
+ export const mapTaskDefinitionToTaskListItem = (
6
+ tasks: TaskDefinition[],
7
+ ): TaskListItem[] =>
8
+ tasks.map((taskDefinition) => {
9
+ const { name, target, description, createdAt, products } =
10
+ taskDefinition;
11
+
12
+ const productTags = products.map((product) => product.tag);
13
+
14
+ return {
15
+ name,
16
+ description,
17
+ target,
18
+ createdAt,
19
+ productTags,
20
+ };
21
+ });
22
+
23
+ export const taskFieldMapper = (
24
+ field: keyof TaskListItem,
25
+ ): keyof TaskDefinition => {
26
+ switch (field) {
27
+ case 'productTags':
28
+ return 'productTag' as keyof TaskDefinition;
29
+ default:
30
+ return field;
31
+ }
32
+ };
33
+
34
+ export const graphQlTaskListMapper = ({
35
+ field,
36
+ order,
37
+ }: GraphQLSort<TaskListItem>) => ({
38
+ field: taskFieldMapper(field),
39
+ order,
40
+ });
@@ -1,3 +1,4 @@
1
1
  export * from './productBlocks';
2
2
  export * from './resourceTypes';
3
3
  export * from './workflows';
4
+ export * from './tasks';
@@ -0,0 +1,74 @@
1
+ import { orchestratorApi } from '@/rtk';
2
+ import {
3
+ BaseGraphQlResult,
4
+ GraphqlQueryVariables,
5
+ TaskDefinition,
6
+ TaskDefinitionsResult,
7
+ } from '@/types';
8
+
9
+ export const tasksQuery = `
10
+ query MetadataWorkflows(
11
+ $first: Int!
12
+ $after: Int!
13
+ $sortBy: [GraphqlSort!]
14
+ $query: String
15
+ ) {
16
+ workflows(
17
+ first: $first
18
+ after: $after
19
+ sortBy: $sortBy
20
+ query: $query
21
+ filterBy: { field: "target", value: "SYSTEM" }
22
+ ) {
23
+ page {
24
+ name
25
+ description
26
+ target
27
+ products {
28
+ tag
29
+ }
30
+ createdAt
31
+ }
32
+ pageInfo {
33
+ endCursor
34
+ hasNextPage
35
+ hasPreviousPage
36
+ startCursor
37
+ totalItems
38
+ sortFields
39
+ filterFields
40
+ }
41
+ }
42
+ }
43
+ `;
44
+
45
+ export type TasksResponse = {
46
+ tasks: TaskDefinition[];
47
+ } & BaseGraphQlResult;
48
+
49
+ const tasksApi = orchestratorApi.injectEndpoints({
50
+ endpoints: (builder) => ({
51
+ getTasks: builder.query<
52
+ TasksResponse,
53
+ GraphqlQueryVariables<TaskDefinition>
54
+ >({
55
+ query: (variables) => ({
56
+ document: tasksQuery,
57
+ variables,
58
+ }),
59
+ transformResponse: (
60
+ response: TaskDefinitionsResult,
61
+ ): TasksResponse => {
62
+ const tasks = response.workflows.page || [];
63
+ const pageInfo = response.workflows.pageInfo || {};
64
+
65
+ return {
66
+ tasks,
67
+ pageInfo,
68
+ };
69
+ },
70
+ }),
71
+ }),
72
+ });
73
+
74
+ export const { useGetTasksQuery, useLazyGetTasksQuery } = tasksApi;
@@ -77,6 +77,7 @@ export enum BadgeType {
77
77
  PRODUCT_BLOCK_TAG = 'product_block_tag',
78
78
  PRODUCT_TAG = 'product_tag',
79
79
  PRODUCT = 'product',
80
+ TASK = 'task',
80
81
  }
81
82
 
82
83
  export interface FixedInputDefinition {
@@ -236,6 +237,14 @@ export interface WorkflowDefinition {
236
237
  createdAt: string;
237
238
  }
238
239
 
240
+ export interface TaskDefinition {
241
+ name: string;
242
+ description?: string;
243
+ target: WorkflowTarget;
244
+ products: Pick<ProductDefinition, 'tag' | 'productId' | 'name'>[];
245
+ createdAt: string;
246
+ }
247
+
239
248
  export type Field<Type> = keyof Type;
240
249
 
241
250
  //// Utility types
@@ -333,6 +342,10 @@ export interface CustomersResult {
333
342
  customers: GraphQlSinglePage<Customer>;
334
343
  }
335
344
 
345
+ export interface TaskDefinitionsResult<T = TaskDefinition> {
346
+ workflows: GraphQlResultPage<T>;
347
+ }
348
+
336
349
  export interface WorkflowDefinitionsResult<T = WorkflowDefinition> {
337
350
  workflows: GraphQlResultPage<T>;
338
351
  }
@@ -7,6 +7,7 @@ import {
7
7
  METADATA_PRODUCT_BLOCKS_TABLE_LOCAL_STORAGE_KEY,
8
8
  METADATA_PRODUCT_TABLE_LOCAL_STORAGE_KEY,
9
9
  METADATA_RESOURCE_TYPES_TABLE_LOCAL_STORAGE_KEY,
10
+ METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY,
10
11
  METADATA_WORKFLOWS_TABLE_LOCAL_STORAGE_KEY,
11
12
  SUBSCRIPTIONS_TABLE_LOCAL_STORAGE_KEY,
12
13
  } from '@/components';
@@ -57,6 +58,7 @@ export const getDefaultTableConfig = <T>(storageKey: string) => {
57
58
  return getTableConfig<T>(productColumns as (keyof T)[]);
58
59
 
59
60
  case METADATA_WORKFLOWS_TABLE_LOCAL_STORAGE_KEY:
61
+ case METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY:
60
62
  const workflowColumns: (keyof WorkflowDefinition)[] = ['createdAt'];
61
63
  return getTableConfig<T>(workflowColumns as (keyof T)[]);
62
64