@orchestrator-ui/orchestrator-ui-components 1.36.0 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.turbo/turbo-build.log +5 -5
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/.turbo/turbo-test.log +9 -9
  4. package/CHANGELOG.md +23 -0
  5. package/dist/index.d.ts +111 -88
  6. package/dist/index.js +570 -448
  7. package/package.json +1 -1
  8. package/src/components/WfoError/WfoError.tsx +25 -1
  9. package/src/components/WfoForms/formFields/CustomerField.tsx +15 -1
  10. package/src/components/WfoForms/formFields/SubscriptionSummaryField.tsx +7 -2
  11. package/src/components/WfoForms/formFields/deprecated/ImsPortIdField.tsx +1 -0
  12. package/src/components/WfoPageTemplate/WfoPageHeader/WfoHamburgerMenu.tsx +3 -0
  13. package/src/components/WfoPageTemplate/WfoPageHeader/styles.ts +1 -3
  14. package/src/components/WfoPageTemplate/WfoSidebar/WfoMenuLink.tsx +5 -0
  15. package/src/components/WfoPageTemplate/WfoSidebar/WfoSidebar.tsx +1 -0
  16. package/src/components/WfoPageTemplate/WfoSidebar/styles.ts +36 -12
  17. package/src/components/WfoProcessList/WfoProcessesList.tsx +3 -2
  18. package/src/components/WfoSettings/WfoFlushSettings.tsx +24 -20
  19. package/src/components/WfoSubscription/WfoInSyncField.tsx +12 -4
  20. package/src/components/WfoSubscription/WfoRelatedSubscriptions.tsx +2 -2
  21. package/src/components/WfoSubscription/WfoSubscription.tsx +5 -3
  22. package/src/components/WfoSubscription/WfoSubscriptionGeneral.tsx +8 -1
  23. package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +3 -2
  24. package/src/components/WfoTable/WfoTableWithFilter/WfoTableWithFilter.tsx +5 -8
  25. package/src/configuration/policy-resources.ts +1 -0
  26. package/src/hooks/useOrchestratorTheme.ts +3 -3
  27. package/src/messages/en-GB.json +3 -1
  28. package/src/messages/nl-NL.json +2 -1
  29. package/src/pages/metadata/WfoProductBlocksPage.tsx +3 -2
  30. package/src/pages/metadata/WfoProductsPage.tsx +3 -2
  31. package/src/pages/metadata/WfoResourceTypesPage.tsx +3 -2
  32. package/src/pages/metadata/WfoTasksPage.tsx +3 -2
  33. package/src/pages/metadata/WfoWorkflowsPage.tsx +3 -2
  34. package/src/rtk/api.ts +10 -0
  35. package/src/rtk/endpoints/formFields.ts +1 -1
  36. package/src/rtk/endpoints/inSync.ts +7 -1
  37. package/src/rtk/endpoints/streamMessages.ts +6 -11
  38. package/src/rtk/utils.ts +65 -0
  39. package/src/rtk/wfoGraphqlRequestBaseQuery.ts +4 -3
  40. package/src/theme/defaultOrchestratorTheme.ts +99 -89
@@ -29,6 +29,7 @@ import {
29
29
  } from '@/hooks';
30
30
  import { useGetProductBlocksQuery, useLazyGetProductBlocksQuery } from '@/rtk';
31
31
  import type { ProductBlocksResponse } from '@/rtk';
32
+ import { mapRtkErrorToWfoError } from '@/rtk/utils';
32
33
  import {
33
34
  BadgeType,
34
35
  GraphqlQueryVariables,
@@ -204,7 +205,7 @@ export const WfoProductBlocksPage = () => {
204
205
  sortBy: sortBy,
205
206
  query: queryString || undefined,
206
207
  };
207
- const { data, isFetching, isError } = useGetProductBlocksQuery(
208
+ const { data, isFetching, error } = useGetProductBlocksQuery(
208
209
  graphqlQueryVariables,
209
210
  );
210
211
  const [getProductBlocksTrigger, { isFetching: isFetchingCsv }] =
@@ -264,7 +265,7 @@ export const WfoProductBlocksPage = () => {
264
265
  )}
265
266
  pagination={pagination}
266
267
  isLoading={isFetching}
267
- hasError={isError}
268
+ error={mapRtkErrorToWfoError(error)}
268
269
  queryString={queryString}
269
270
  localStorageKey={
270
271
  METADATA_PRODUCT_BLOCKS_TABLE_LOCAL_STORAGE_KEY
@@ -27,6 +27,7 @@ import {
27
27
  } from '@/hooks';
28
28
  import { useGetProductsQuery, useLazyGetProductsQuery } from '@/rtk';
29
29
  import { ProductsResponse } from '@/rtk';
30
+ import { mapRtkErrorToWfoError } from '@/rtk/utils';
30
31
  import type { GraphqlQueryVariables, ProductDefinition } from '@/types';
31
32
  import { BadgeType, SortOrder } from '@/types';
32
33
  import {
@@ -183,7 +184,7 @@ export const WfoProductsPage = () => {
183
184
  sortBy: sortBy,
184
185
  query: queryString || undefined,
185
186
  };
186
- const { data, isFetching, isError } = useGetProductsQuery(
187
+ const { data, isFetching, error } = useGetProductsQuery(
187
188
  graphqlQueryVariables,
188
189
  );
189
190
  const [getProductsTrigger, { isFetching: isFetchingCsv }] =
@@ -259,7 +260,7 @@ export const WfoProductsPage = () => {
259
260
  )}
260
261
  pagination={pagination}
261
262
  isLoading={isFetching}
262
- hasError={isError}
263
+ error={mapRtkErrorToWfoError(error)}
263
264
  queryString={queryString}
264
265
  localStorageKey={METADATA_PRODUCT_TABLE_LOCAL_STORAGE_KEY}
265
266
  onExportData={csvDownloadHandler(
@@ -30,6 +30,7 @@ import {
30
30
  useGetResourceTypesQuery,
31
31
  useLazyGetResourceTypesQuery,
32
32
  } from '@/rtk';
33
+ import { mapRtkErrorToWfoError } from '@/rtk/utils';
33
34
  import {
34
35
  BadgeType,
35
36
  GraphqlQueryVariables,
@@ -151,7 +152,7 @@ export const WfoResourceTypesPage = () => {
151
152
  sortBy: sortBy,
152
153
  query: queryString || undefined,
153
154
  };
154
- const { data, isFetching, isError } = useGetResourceTypesQuery(
155
+ const { data, isFetching, error } = useGetResourceTypesQuery(
155
156
  graphqlQueryVariables,
156
157
  );
157
158
 
@@ -210,7 +211,7 @@ export const WfoResourceTypesPage = () => {
210
211
  )}
211
212
  pagination={pagination}
212
213
  isLoading={isFetching}
213
- hasError={isError}
214
+ error={mapRtkErrorToWfoError(error)}
214
215
  queryString={queryString}
215
216
  localStorageKey={
216
217
  METADATA_RESOURCE_TYPES_TABLE_LOCAL_STORAGE_KEY
@@ -27,6 +27,7 @@ import {
27
27
  useStoredTableConfig,
28
28
  } from '@/hooks';
29
29
  import { TasksResponse, useGetTasksQuery, useLazyGetTasksQuery } from '@/rtk';
30
+ import { mapRtkErrorToWfoError } from '@/rtk/utils';
30
31
  import type { GraphqlQueryVariables, TaskDefinition } from '@/types';
31
32
  import { BadgeType, SortOrder } from '@/types';
32
33
  import {
@@ -163,7 +164,7 @@ export const WfoTasksPage = () => {
163
164
  sortBy: graphQlTaskListMapper(sortBy),
164
165
  query: queryString || undefined,
165
166
  };
166
- const { data, isFetching, isError } = useGetTasksQuery(
167
+ const { data, isFetching, error } = useGetTasksQuery(
167
168
  taskListQueryVariables,
168
169
  );
169
170
 
@@ -231,7 +232,7 @@ export const WfoTasksPage = () => {
231
232
  )}
232
233
  pagination={pagination}
233
234
  isLoading={isFetching}
234
- hasError={isError}
235
+ error={mapRtkErrorToWfoError(error)}
235
236
  queryString={queryString}
236
237
  localStorageKey={METADATA_TASKS_TABLE_LOCAL_STORAGE_KEY}
237
238
  onExportData={csvDownloadHandler(
@@ -29,6 +29,7 @@ import {
29
29
  useGetWorkflowsQuery,
30
30
  useLazyGetWorkflowsQuery,
31
31
  } from '@/rtk';
32
+ import { mapRtkErrorToWfoError } from '@/rtk/utils';
32
33
  import type { GraphqlQueryVariables, WorkflowDefinition } from '@/types';
33
34
  import { BadgeType, SortOrder } from '@/types';
34
35
  import {
@@ -168,7 +169,7 @@ export const WfoWorkflowsPage = () => {
168
169
  sortBy: graphQlWorkflowListMapper(sortBy),
169
170
  query: queryString || undefined,
170
171
  };
171
- const { data, isFetching, isError } = useGetWorkflowsQuery(
172
+ const { data, isFetching, error } = useGetWorkflowsQuery(
172
173
  workflowListQueryVariables,
173
174
  );
174
175
 
@@ -237,7 +238,7 @@ export const WfoWorkflowsPage = () => {
237
238
  )}
238
239
  pagination={pagination}
239
240
  isLoading={isFetching}
240
- hasError={isError}
241
+ error={mapRtkErrorToWfoError(error)}
241
242
  queryString={queryString}
242
243
  localStorageKey={METADATA_WORKFLOWS_TABLE_LOCAL_STORAGE_KEY}
243
244
  onExportData={csvDownloadHandler(
package/src/rtk/api.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ClientError } from 'graphql-request';
2
+ import { GraphQLErrorExtensions } from 'graphql/error/GraphQLError';
1
3
  import { getSession, signOut } from 'next-auth/react';
2
4
 
3
5
  import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
@@ -73,6 +75,11 @@ export const catchErrorResponse = async (
73
75
  }
74
76
  };
75
77
 
78
+ export type WfoGraphqlError = {
79
+ extensions: GraphQLErrorExtensions;
80
+ message: string;
81
+ };
82
+
76
83
  export const orchestratorApi = createApi({
77
84
  reducerPath: 'orchestratorApi',
78
85
  baseQuery: (args, api, extraOptions: ExtraOptions) => {
@@ -104,6 +111,9 @@ export const orchestratorApi = createApi({
104
111
  ? customApi.apiBaseUrl
105
112
  : graphqlEndpointCore,
106
113
  prepareHeaders,
114
+ customErrors: (args: ClientError) => {
115
+ return args.response?.errors;
116
+ },
107
117
  },
108
118
  authActive,
109
119
  );
@@ -21,7 +21,7 @@ const nodeSubscriptionsQuery = `query NodeSubscriptions(
21
21
  subscriptions(filterBy: [
22
22
  {field: "tag", value: "Node"},
23
23
  {field: "status", value: $statuses}
24
-
24
+
25
25
  ], first: ${NUMBER_OF_ITEMS_REPRESENTING_ALL_ITEMS}, after: 0) {
26
26
  page {
27
27
  description
@@ -1,4 +1,4 @@
1
- import { Subscription } from '@/types';
1
+ import { CacheTagType, Subscription } from '@/types';
2
2
 
3
3
  import { BaseQueryTypes, orchestratorApi } from '../api';
4
4
 
@@ -15,6 +15,12 @@ const inSyncApi = orchestratorApi.injectEndpoints({
15
15
  extraOptions: {
16
16
  baseQueryType: BaseQueryTypes.fetch,
17
17
  },
18
+ invalidatesTags: (_result, _error, subscriptionId) => [
19
+ {
20
+ type: CacheTagType.subscriptions,
21
+ id: subscriptionId,
22
+ },
23
+ ],
18
24
  }),
19
25
  }),
20
26
  });
@@ -1,4 +1,3 @@
1
- import { debounce } from 'lodash';
2
1
  import { getSession } from 'next-auth/react';
3
2
 
4
3
  import type { WfoSession } from '@/hooks';
@@ -24,8 +23,11 @@ const getWebSocket = async (url: string) => {
24
23
  }
25
24
  };
26
25
 
27
- const PING_INTERVAL_MS = 45000; // Recommended values are between 30 and 60 seconds
28
- const DEBOUNCE_CLOSE_INTERVAL_MS = 60000;
26
+ // Recommended values are between 30 and 60 seconds
27
+ // Note: When the browser tab is suspended, the browser will give this suspended tab approximately every 60 seconds time
28
+ // to execute code. This means that the ping message will be sent every 60 seconds in suspended mode. This depends
29
+ // on the browser and can differ.
30
+ const PING_INTERVAL_MS = 45000;
29
31
 
30
32
  type WebSocketMessage = {
31
33
  name: MessageTypes;
@@ -88,12 +90,6 @@ const streamMessagesApi = orchestratorApi.injectEndpoints({
88
90
  webSocket.send('__ping__');
89
91
  }, PING_INTERVAL_MS);
90
92
 
91
- const debounceCloseWebSocket = debounce(() => {
92
- webSocket.close();
93
- }, DEBOUNCE_CLOSE_INTERVAL_MS);
94
- // Start the debounced function to close the websocket when no 'pong' message is received after DEBOUNCE_CLOSE_INTERVAL
95
- debounceCloseWebSocket();
96
-
97
93
  await cacheDataLoaded;
98
94
 
99
95
  const state = getState() as RootState;
@@ -114,8 +110,7 @@ const streamMessagesApi = orchestratorApi.injectEndpoints({
114
110
  const data = messageEvent.data;
115
111
 
116
112
  if (data === '__pong__') {
117
- // Reset the debounced every time a 'pong' message is received
118
- debounceCloseWebSocket();
113
+ // __pong__ is an accepted message, but should not be processed
119
114
  return;
120
115
  }
121
116
  const message = JSON.parse(data) as WebSocketMessage;
package/src/rtk/utils.ts CHANGED
@@ -1,5 +1,11 @@
1
+ import { GraphQLError } from 'graphql/error/GraphQLError';
1
2
  import { isPlainObject } from 'lodash';
2
3
 
4
+ import { SerializedError } from '@reduxjs/toolkit';
5
+ import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
6
+
7
+ import { WfoGraphqlError } from '@/rtk/api';
8
+
3
9
  export function stripUndefined(obj: object): Record<string, unknown> {
4
10
  if (!isPlainObject(obj)) {
5
11
  return obj as Record<string, unknown>;
@@ -12,3 +18,62 @@ export function stripUndefined(obj: object): Record<string, unknown> {
12
18
  }
13
19
  return copy;
14
20
  }
21
+
22
+ function isSerializedError(
23
+ error: SerializedError | undefined,
24
+ ): error is SerializedError {
25
+ if (error) {
26
+ return (
27
+ error &&
28
+ typeof error === 'object' &&
29
+ ('name' in error ||
30
+ 'message' in error ||
31
+ 'stack' in error ||
32
+ 'code' in error)
33
+ );
34
+ }
35
+ return false;
36
+ }
37
+
38
+ const UNKNOWN_ERROR_MESSAGE = 'Unknown error';
39
+
40
+ const getSerializedErrorMessage = (error: SerializedError) => {
41
+ if (error.message) {
42
+ return error.message;
43
+ } else if (error.name) {
44
+ return error.name;
45
+ } else if (error.code) {
46
+ return error.code;
47
+ } else if (error.stack) {
48
+ return error.stack;
49
+ }
50
+ return UNKNOWN_ERROR_MESSAGE;
51
+ };
52
+
53
+ export const mapRtkErrorToWfoError = (
54
+ error: FetchBaseQueryError | GraphQLError[] | SerializedError | undefined,
55
+ ): WfoGraphqlError[] | undefined => {
56
+ if (Array.isArray(error)) {
57
+ return error.map((err): WfoGraphqlError => {
58
+ return {
59
+ extensions: err.extensions,
60
+ message: err.message,
61
+ };
62
+ });
63
+ } else if (error && 'status' in error && error.status !== undefined) {
64
+ return [
65
+ {
66
+ extensions: {},
67
+ message: String(error.status),
68
+ },
69
+ ];
70
+ } else if (isSerializedError(error)) {
71
+ return [
72
+ {
73
+ extensions: {},
74
+ message: getSerializedErrorMessage(error),
75
+ },
76
+ ];
77
+ }
78
+ return error;
79
+ };
@@ -1,4 +1,5 @@
1
1
  import { ClientError, GraphQLClient } from 'graphql-request';
2
+ import type { GraphQLError } from 'graphql/error/GraphQLError.js';
2
3
  import { signOut } from 'next-auth/react';
3
4
 
4
5
  import { BaseQueryFn } from '@reduxjs/toolkit/query';
@@ -53,7 +54,7 @@ export const wfoGraphqlRequestBaseQuery = <T, E = ErrorResponse>(
53
54
  );
54
55
 
55
56
  if (errors?.length && authActive) {
56
- errors.map((error) => {
57
+ errors.map((error: GraphQLError) => {
57
58
  if (error.extensions?.error_type === 'not_authenticated') {
58
59
  signOut();
59
60
  }
@@ -74,9 +75,9 @@ export const wfoGraphqlRequestBaseQuery = <T, E = ErrorResponse>(
74
75
  };
75
76
  } catch (error) {
76
77
  if (error instanceof ClientError) {
77
- const { name, message, stack, request, response } = error;
78
+ const { request, response } = error;
78
79
  const customErrors =
79
- options.customErrors ?? (() => ({ name, message, stack }));
80
+ options.customErrors ?? ((error) => error.response.errors);
80
81
  const customizedErrors = customErrors(error) as E;
81
82
  return { error: customizedErrors, meta: { request, response } };
82
83
  }
@@ -1,94 +1,104 @@
1
- import { EuiThemeModifications } from '@elastic/eui';
1
+ import type { EuiThemeComputed, EuiThemeModifications } from '@elastic/eui';
2
2
 
3
- export const defaultOrchestratorTheme: EuiThemeModifications = {
4
- base: 16,
5
- breakpoint: {
6
- xs: 0,
7
- s: 575,
8
- m: 768,
9
- l: 992,
10
- xl: 1200,
11
- xxl: 1600,
12
- },
13
- size: {
14
- base: '16px',
15
- xxs: '2px',
16
- xs: '4px',
17
- s: '8px',
18
- m: '12px',
19
- l: '24px',
20
- xl: '32px',
21
- xxl: '40px',
22
- xxxl: '48px',
23
- xxxxl: '64px',
24
- },
3
+ export type WfoThemeExtraColors = {
25
4
  colors: {
26
- DARK: {
27
- primary: '#0077C8',
28
- accent: '#E67300',
29
- success: '#13B054',
30
- warning: '#FFC514',
31
- danger: '#FF4F46',
32
- primaryText: '#1F8DD8',
33
- accentText: '#E67300',
34
- successText: '#13B054',
35
- warningText: '#FFC514',
36
- dangerText: '#FF4F46',
37
- emptyShade: '#101827',
38
- lightestShade: '#1F2937',
39
- lightShade: '#374151',
40
- mediumShade: '#4B5563',
41
- darkShade: '#64758B',
42
- darkestShade: '#F1F5F9',
43
- fullShade: '#ffffff',
44
- text: '#9CA3AF',
45
- title: '#ffffff',
46
- subduedText: '#9CA3AF',
47
- link: '#1F8DD8',
48
- body: '#1F2937',
49
- highlight: '#51482F',
50
- disabled: '#4B5563',
51
- disabledText: '#4B5563',
52
- shadow: '#000000',
5
+ header: string;
6
+ };
7
+ };
8
+
9
+ export type WfoThemeComputed = EuiThemeComputed<WfoThemeExtraColors>;
10
+
11
+ export const defaultOrchestratorTheme: EuiThemeModifications<WfoThemeExtraColors> =
12
+ {
13
+ base: 16,
14
+ breakpoint: {
15
+ xs: 0,
16
+ s: 575,
17
+ m: 768,
18
+ l: 992,
19
+ xl: 1200,
20
+ xxl: 1600,
53
21
  },
54
- LIGHT: {
55
- primary: '#0077C8',
56
- accent: '#E67300',
57
- success: '#008939',
58
- warning: '#FFC514',
59
- danger: '#BD271F',
60
- primaryText: '#0067AC',
61
- accentText: '#B05200',
62
- successText: '#007832',
63
- warningText: '#8E6A00',
64
- dangerText: '#AC0A01',
65
- emptyShade: '#FFFFFF',
66
- lightestShade: '#F1F5F9',
67
- lightShade: '#CCD5E2',
68
- mediumShade: '#94A4B8',
69
- darkShade: '#64758B',
70
- darkestShade: '#334255',
71
- fullShade: '#0F172B',
72
- text: '#334255',
73
- title: '#0F172B',
74
- subduedText: '#64758B',
75
- link: '#0067AC',
76
- body: '#F1F5F9',
77
- highlight: '#FFF6DE',
78
- disabled: '#94A4B8',
79
- disabledText: '#94A4B8',
80
- shadow: '#000000',
22
+ size: {
23
+ base: '16px',
24
+ xxs: '2px',
25
+ xs: '4px',
26
+ s: '8px',
27
+ m: '12px',
28
+ l: '24px',
29
+ xl: '32px',
30
+ xxl: '40px',
31
+ xxxl: '48px',
32
+ xxxxl: '64px',
81
33
  },
82
- },
83
- font: {
84
- weight: {
85
- regular: 400,
86
- medium: 500,
87
- semiBold: 600,
88
- bold: 700,
34
+ colors: {
35
+ DARK: {
36
+ primary: '#0077C8',
37
+ accent: '#E67300',
38
+ success: '#13B054',
39
+ warning: '#FFC514',
40
+ danger: '#FF4F46',
41
+ primaryText: '#1F8DD8',
42
+ accentText: '#E67300',
43
+ successText: '#13B054',
44
+ warningText: '#FFC514',
45
+ dangerText: '#FF4F46',
46
+ emptyShade: '#101827',
47
+ lightestShade: '#1F2937',
48
+ lightShade: '#374151',
49
+ mediumShade: '#4B5563',
50
+ darkShade: '#64758B',
51
+ darkestShade: '#F1F5F9',
52
+ fullShade: '#ffffff',
53
+ text: '#9CA3AF',
54
+ title: '#ffffff',
55
+ subduedText: '#9CA3AF',
56
+ link: '#1F8DD8',
57
+ body: '#1F2937',
58
+ highlight: '#51482F',
59
+ disabled: '#4B5563',
60
+ disabledText: '#4B5563',
61
+ shadow: '#000000',
62
+ },
63
+ LIGHT: {
64
+ primary: '#0077C8',
65
+ accent: '#E67300',
66
+ success: '#008939',
67
+ warning: '#FFC514',
68
+ danger: '#BD271F',
69
+ primaryText: '#0067AC',
70
+ accentText: '#B05200',
71
+ successText: '#007832',
72
+ warningText: '#8E6A00',
73
+ dangerText: '#AC0A01',
74
+ emptyShade: '#FFFFFF',
75
+ lightestShade: '#F1F5F9',
76
+ lightShade: '#CCD5E2',
77
+ mediumShade: '#94A4B8',
78
+ darkShade: '#64758B',
79
+ darkestShade: '#334255',
80
+ fullShade: '#0F172B',
81
+ text: '#334255',
82
+ title: '#0F172B',
83
+ subduedText: '#64758B',
84
+ link: '#0067AC',
85
+ body: '#F1F5F9',
86
+ highlight: '#FFF6DE',
87
+ disabled: '#94A4B8',
88
+ disabledText: '#94A4B8',
89
+ shadow: '#000000',
90
+ },
91
+ header: '#04385F',
89
92
  },
90
- },
91
- border: {
92
- thin: 'solid 1px #ddd',
93
- },
94
- };
93
+ font: {
94
+ weight: {
95
+ regular: 400,
96
+ medium: 500,
97
+ semiBold: 600,
98
+ bold: 700,
99
+ },
100
+ },
101
+ border: {
102
+ thin: 'solid 1px #ddd',
103
+ },
104
+ };