@orchestrator-ui/orchestrator-ui-components 5.0.0 → 5.2.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 (41) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/.turbo/turbo-test.log +4 -4
  4. package/CHANGELOG.md +21 -0
  5. package/dist/index.d.ts +2858 -345
  6. package/dist/index.js +1967 -1714
  7. package/dist/index.js.map +1 -1
  8. package/package.json +2 -2
  9. package/src/components/WfoForms/formFields/SubscriptionSummaryField.tsx +1 -1
  10. package/src/components/WfoForms/formFields/commonStyles.ts +6 -0
  11. package/src/components/WfoForms/formFields/{SubscriptionField.tsx → deprecated/SubscriptionField.tsx} +53 -157
  12. package/src/components/WfoForms/formFields/deprecated/index.ts +1 -0
  13. package/src/components/WfoForms/formFields/index.ts +1 -1
  14. package/src/components/WfoPydanticForm/Footer.tsx +75 -34
  15. package/src/components/WfoPydanticForm/Header.tsx +18 -0
  16. package/src/components/WfoPydanticForm/Row.tsx +17 -5
  17. package/src/components/WfoPydanticForm/WfoPydanticForm.tsx +101 -9
  18. package/src/components/WfoPydanticForm/fields/Checkbox.tsx +22 -0
  19. package/src/components/WfoPydanticForm/fields/Divider.tsx +17 -0
  20. package/src/components/WfoPydanticForm/fields/Label.tsx +23 -0
  21. package/src/components/WfoPydanticForm/fields/Summary.tsx +125 -0
  22. package/src/components/WfoPydanticForm/fields/Text.tsx +28 -0
  23. package/src/components/WfoPydanticForm/fields/index.ts +5 -0
  24. package/src/configuration/constants.ts +2 -0
  25. package/src/configuration/version.ts +1 -1
  26. package/src/hooks/deprecated/useGetSurfSubcriptionDropdownOptions.ts +37 -0
  27. package/src/icons/WfoExclamationTriangle.tsx +29 -0
  28. package/src/icons/index.ts +1 -0
  29. package/src/pages/metadata/WfoTasksPage.tsx +11 -26
  30. package/src/pages/metadata/WfoWorkflowsPage.tsx +11 -12
  31. package/src/rtk/api.ts +3 -1
  32. package/src/rtk/endpoints/deprecated/index.ts +1 -0
  33. package/src/rtk/endpoints/deprecated/surfSubscriptionDropdownOptions.ts +53 -0
  34. package/src/rtk/endpoints/index.ts +2 -1
  35. package/src/types/deprecated/SurfSubscriptionDropdownOptionsFilterParams.ts +10 -0
  36. package/src/types/deprecated/index.ts +1 -0
  37. package/src/types/index.ts +1 -0
  38. package/src/types/types.ts +2 -2
  39. package/src/hooks/deprecated/useGetSubscriptionDropdownOptions.ts +0 -39
  40. package/src/rtk/endpoints/subscriptionsDropdownOptions.ts +0 -71
  41. /package/src/components/WfoForms/formFields/{SubscriptionFieldStyling.ts → deprecated/SubscriptionFieldStyling.ts} +0 -0
@@ -2,17 +2,18 @@ import React from 'react';
2
2
 
3
3
  import { AbstractIntlMessages, useMessages, useTranslations } from 'next-intl';
4
4
  import { useRouter } from 'next/router';
5
- import {
6
- PydanticForm,
7
- PydanticFormFieldFormat,
8
- PydanticFormFieldType,
9
- } from 'pydantic-forms';
10
5
  import type {
11
6
  ComponentMatcher,
12
7
  PydanticComponentMatcher,
13
8
  PydanticFormApiProvider,
14
9
  PydanticFormLabelProvider,
15
10
  } from 'pydantic-forms';
11
+ import {
12
+ PydanticForm,
13
+ PydanticFormFieldFormat,
14
+ PydanticFormFieldType,
15
+ zodValidationPresets,
16
+ } from 'pydantic-forms';
16
17
 
17
18
  import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
18
19
 
@@ -21,10 +22,12 @@ import { StartWorkflowPayload } from '@/pages/processes/WfoStartProcessPage';
21
22
  import { HttpStatus } from '@/rtk';
22
23
  import { useStartProcessMutation } from '@/rtk/endpoints/forms';
23
24
  import { useAppSelector } from '@/rtk/hooks';
25
+ import { FormValidationError } from '@/types';
24
26
 
25
27
  import { Footer } from './Footer';
28
+ import { Header } from './Header';
26
29
  import { Row } from './Row';
27
- import { TextArea } from './fields/TextArea';
30
+ import { Checkbox, Divider, Label, Summary, Text, TextArea } from './fields';
28
31
 
29
32
  interface WfoPydanticFormProps {
30
33
  processName: string;
@@ -54,6 +57,11 @@ export const WfoPydanticForm = ({
54
57
  typeof translationMessages?.pydanticForms !== 'string'
55
58
  ? translationMessages.pydanticForms.backendTranslations
56
59
  : {};
60
+ const widgetsTranslations =
61
+ translationMessages?.pydanticForms &&
62
+ typeof translationMessages?.pydanticForms !== 'string'
63
+ ? translationMessages.pydanticForms.widgets
64
+ : {};
57
65
 
58
66
  const onSuccess = (_fieldValues: object, req: object) => {
59
67
  const request = req as { response: StartProcessResponse };
@@ -88,6 +96,18 @@ export const WfoPydanticForm = ({
88
96
  object | string
89
97
  >;
90
98
  resolve(data);
99
+ } else if (
100
+ typeof error === 'object' &&
101
+ error !== null
102
+ ) {
103
+ const validationError =
104
+ error as FormValidationError;
105
+ if (validationError?.status === 400) {
106
+ resolve({
107
+ ...validationError.data,
108
+ status: validationError.status.toString(),
109
+ });
110
+ }
91
111
  }
92
112
  } else if (result.data) {
93
113
  resolve(result.data);
@@ -112,11 +132,13 @@ export const WfoPydanticForm = ({
112
132
  return pydanticFormProvider;
113
133
  };
114
134
 
135
+ const orchestratorTranslations = formTranslations as unknown;
136
+
115
137
  const pydanticLabelProvider: PydanticFormLabelProvider = async () => {
116
138
  return new Promise((resolve) => {
117
139
  resolve({
118
140
  labels: {
119
- ...(formTranslations as object),
141
+ ...(orchestratorTranslations as object),
120
142
  },
121
143
  data: {},
122
144
  });
@@ -138,22 +160,88 @@ export const WfoPydanticForm = ({
138
160
  );
139
161
  },
140
162
  },
141
- ...currentMatchers,
163
+ {
164
+ id: 'summary',
165
+ ElementMatch: {
166
+ Element: Summary,
167
+ isControlledElement: false,
168
+ },
169
+ matcher(field) {
170
+ return (
171
+ field.type === PydanticFormFieldType.STRING &&
172
+ (field.format as string) === 'summary'
173
+ );
174
+ },
175
+ },
176
+ {
177
+ id: 'label',
178
+ ElementMatch: {
179
+ Element: Label,
180
+ isControlledElement: false,
181
+ },
182
+ matcher(field) {
183
+ return (
184
+ field.type === PydanticFormFieldType.STRING &&
185
+ field.format === PydanticFormFieldFormat.LABEL
186
+ );
187
+ },
188
+ },
189
+ {
190
+ id: 'divider',
191
+ ElementMatch: {
192
+ Element: Divider,
193
+ isControlledElement: false,
194
+ },
195
+ matcher(field) {
196
+ return (
197
+ field.type === PydanticFormFieldType.STRING &&
198
+ field.format === PydanticFormFieldFormat.DIVIDER
199
+ );
200
+ },
201
+ },
202
+ {
203
+ id: 'checkbox',
204
+ ElementMatch: {
205
+ Element: Checkbox,
206
+ isControlledElement: true,
207
+ },
208
+ matcher(field) {
209
+ return field.type === PydanticFormFieldType.BOOLEAN;
210
+ },
211
+ },
212
+ ...currentMatchers.filter((matcher) => matcher.id !== 'text'),
213
+ {
214
+ id: 'text',
215
+ ElementMatch: {
216
+ Element: Text,
217
+ isControlledElement: true,
218
+ },
219
+ matcher(field) {
220
+ return field.type === PydanticFormFieldType.STRING;
221
+ },
222
+ validator: zodValidationPresets.string,
223
+ },
142
224
  ];
143
225
 
144
226
  return componentMatcher ? componentMatcher(wfoMatchers) : wfoMatchers;
145
227
  };
146
228
 
229
+ const handleCancel = () => {
230
+ const pfBasePath = isTask ? PATH_TASKS : PATH_WORKFLOWS;
231
+ router.replace(pfBasePath);
232
+ };
233
+
147
234
  return (
148
235
  <PydanticForm
149
- title={''}
150
236
  id={processName}
151
237
  onSuccess={onSuccess}
238
+ onCancel={handleCancel}
152
239
  loadingComponent={<WfoLoading />}
153
240
  config={{
154
241
  apiProvider: getPydanticFormProvider(),
155
242
  allowUntouchedSubmit: true,
156
243
  footerRenderer: Footer,
244
+ headerRenderer: Header,
157
245
  skipSuccessNotice: true,
158
246
  componentMatcher: wfoComponentMatcher,
159
247
  labelProvider: pydanticLabelProvider,
@@ -161,6 +249,10 @@ export const WfoPydanticForm = ({
161
249
  customTranslations: {
162
250
  cancel: t('cancel'),
163
251
  startWorkflow: t('startWorkflow'),
252
+ widgets: {
253
+ ...(widgetsTranslations as object),
254
+ },
255
+ ...translationMessages,
164
256
  },
165
257
  }}
166
258
  />
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+
3
+ import type { PydanticFormControlledElement } from 'pydantic-forms';
4
+
5
+ import { EuiCheckbox } from '@elastic/eui';
6
+
7
+ export const Checkbox: PydanticFormControlledElement = ({
8
+ pydanticFormField,
9
+ onChange,
10
+ value,
11
+ disabled,
12
+ }) => {
13
+ return (
14
+ <EuiCheckbox
15
+ checked={value || false}
16
+ disabled={disabled}
17
+ id={pydanticFormField.id}
18
+ label={pydanticFormField.title || <div>&nbsp;</div>}
19
+ onChange={() => !disabled && onChange(!value)}
20
+ />
21
+ );
22
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+
3
+ import type { PydanticFormElement } from 'pydantic-forms';
4
+
5
+ import { EuiHorizontalRule } from '@elastic/eui';
6
+
7
+ import { useOrchestratorTheme } from '@/hooks';
8
+
9
+ export const Divider: PydanticFormElement = ({ pydanticFormField }) => {
10
+ const { theme } = useOrchestratorTheme();
11
+ return (
12
+ <EuiHorizontalRule
13
+ style={{ marginTop: theme.base }}
14
+ id={pydanticFormField.id}
15
+ />
16
+ );
17
+ };
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+
3
+ import { PydanticFormElement } from 'pydantic-forms';
4
+
5
+ import { useOrchestratorTheme } from '@/hooks';
6
+
7
+ export const Label: PydanticFormElement = ({ pydanticFormField }) => {
8
+ const { theme } = useOrchestratorTheme();
9
+
10
+ return (
11
+ <div>
12
+ <label
13
+ css={{
14
+ color: theme.colors.text,
15
+ display: 'block',
16
+ }}
17
+ id={pydanticFormField.id}
18
+ >
19
+ {pydanticFormField.title}
20
+ </label>
21
+ </div>
22
+ );
23
+ };
@@ -0,0 +1,125 @@
1
+ import React from 'react';
2
+
3
+ import type { PydanticFormElement } from 'pydantic-forms';
4
+
5
+ import { EuiFlexItem, EuiFormRow, EuiText } from '@elastic/eui';
6
+ import { tint } from '@elastic/eui';
7
+ import { css } from '@emotion/react';
8
+ import type { WfoTheme } from '@orchestrator-ui/orchestrator-ui-components';
9
+
10
+ import { getCommonFormFieldStyles } from '@/components/WfoForms/formFields/commonStyles';
11
+ import { useWithOrchestratorTheme } from '@/hooks';
12
+
13
+ export const getStyles = ({ theme }: WfoTheme) => {
14
+ const toShadeColor = (color: string) => tint(color, 0.9);
15
+
16
+ const summaryFieldStyle = css({
17
+ 'div.emailMessage': {
18
+ td: {
19
+ color: theme.colors.text,
20
+ },
21
+ p: {
22
+ color: theme.colors.text,
23
+ },
24
+ html: {
25
+ marginLeft: '-10px',
26
+ },
27
+ },
28
+ 'section.table-summary': {
29
+ marginTop: '20px',
30
+ width: '100%',
31
+ td: {
32
+ padding: '10px',
33
+ verticalAlign: 'top',
34
+ },
35
+ 'td:not(:first-child):not(:last-child)': {
36
+ borderRight: `1px solid ${theme.colors.lightestShade}`,
37
+ },
38
+ '.label': {
39
+ fontWeight: 'bold',
40
+ color: theme.colors.lightestShade,
41
+ backgroundColor: theme.colors.primary,
42
+ borderRight: `2px solid ${theme.colors.lightestShade}`,
43
+ borderBottom: `1px solid ${theme.colors.lightestShade}`,
44
+ },
45
+ '.value': {
46
+ backgroundColor: toShadeColor(theme.colors.primary),
47
+ borderBottom: `1px solid ${theme.colors.lightestShade}`,
48
+ },
49
+ },
50
+ });
51
+ return {
52
+ summaryFieldStyle: summaryFieldStyle,
53
+ };
54
+ };
55
+
56
+ export const Summary: PydanticFormElement = ({ pydanticFormField }) => {
57
+ const { summaryFieldStyle } = useWithOrchestratorTheme(getStyles);
58
+ const { formRowStyle } = useWithOrchestratorTheme(getCommonFormFieldStyles);
59
+
60
+ const { id, title, description } = pydanticFormField;
61
+ const uniforms = pydanticFormField.schema.uniforms;
62
+ const summaryData = uniforms?.data as unknown as {
63
+ headers: string[][];
64
+ labels: string[];
65
+ columns: string[][];
66
+ };
67
+
68
+ const headers = summaryData?.headers as string[][];
69
+ const labels = summaryData?.labels as string[];
70
+ const columns = summaryData?.columns || [];
71
+
72
+ const extraColumnsData = columns.filter((_, index) => index !== 0);
73
+
74
+ const rows = columns[0].map((row, index) => (
75
+ <tr key={index}>
76
+ {labels && <td className={`label`}>{labels[index]}</td>}
77
+ <td className={`value`}>
78
+ {typeof row === 'string' && row.includes('<!doctype html>') ? (
79
+ <div
80
+ className="emailMessage"
81
+ dangerouslySetInnerHTML={{ __html: row }}
82
+ ></div>
83
+ ) : (
84
+ row
85
+ )}
86
+ </td>
87
+ {extraColumnsData &&
88
+ extraColumnsData.map((_, idx) => (
89
+ <td className={`value`} key={idx}>
90
+ {extraColumnsData[idx][index]}
91
+ </td>
92
+ ))}
93
+ </tr>
94
+ ));
95
+
96
+ const tableHeader =
97
+ !headers || headers.length === 0 ? null : (
98
+ <tr>
99
+ {labels && <th />}
100
+ {headers.map((header, idx) => (
101
+ <th key={idx}>{header}</th>
102
+ ))}
103
+ </tr>
104
+ );
105
+
106
+ return (
107
+ <EuiFlexItem css={[summaryFieldStyle, formRowStyle]}>
108
+ <section>
109
+ <EuiFormRow
110
+ label={description}
111
+ labelAppend={<EuiText size="m">{title}</EuiText>}
112
+ id={id}
113
+ fullWidth
114
+ >
115
+ <section className="table-summary">
116
+ <table id={`${id}-table`}>
117
+ <thead>{tableHeader}</thead>
118
+ <tbody>{rows}</tbody>
119
+ </table>
120
+ </section>
121
+ </EuiFormRow>
122
+ </section>
123
+ </EuiFlexItem>
124
+ );
125
+ };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+
3
+ import type { PydanticFormControlledElement } from 'pydantic-forms';
4
+
5
+ import { EuiFieldText } from '@elastic/eui';
6
+
7
+ import { useWithOrchestratorTheme } from '@/hooks';
8
+ import { getFormFieldsBaseStyle } from '@/theme';
9
+
10
+ export const Text: PydanticFormControlledElement = ({
11
+ onChange,
12
+ value,
13
+ disabled,
14
+ }) => {
15
+ const { formFieldBaseStyle } = useWithOrchestratorTheme(
16
+ getFormFieldsBaseStyle,
17
+ );
18
+
19
+ return (
20
+ <EuiFieldText
21
+ css={formFieldBaseStyle}
22
+ disabled={disabled}
23
+ onChange={(event) => onChange(event.target.value)}
24
+ value={value ?? ''}
25
+ fullWidth
26
+ />
27
+ );
28
+ };
@@ -1 +1,6 @@
1
1
  export * from './TextArea';
2
+ export * from './Text';
3
+ export * from './Label';
4
+ export * from './Divider';
5
+ export * from './Checkbox';
6
+ export * from './Summary';
@@ -25,6 +25,8 @@ export const IPAM_FREE_SUBNETS_ENDPOINT = `${IPAM_ENDPOINT}/free_subnets`;
25
25
 
26
26
  //subscriptions
27
27
  export const SUBSCRIPTION_ACTIONS_ENDPOINT = 'subscriptions/workflows';
28
+ export const SUBSCRIPTION_DROPDOWN_OPTIONS_ENDPOINT =
29
+ 'surf/subscriptions/dropdown-options';
28
30
  export const CUSTOMER_DESCRIPTION_ENDPOINT =
29
31
  '/subscription_customer_descriptions';
30
32
 
@@ -1 +1 @@
1
- export const ORCHESTRATOR_UI_LIBRARY_VERSION = '5.0.0';
1
+ export const ORCHESTRATOR_UI_LIBRARY_VERSION = '5.2.0';
@@ -0,0 +1,37 @@
1
+ import { useGetSurfSubscriptionDropdownOptionsQuery } from '@/rtk/endpoints/deprecated/surfSubscriptionDropdownOptions';
2
+ import { SurfSubscriptionDropdownOptionsFilterParams } from '@/types';
3
+
4
+ export const useGetSurfSubscriptionDropdownOptions = (
5
+ tags: string[] = [],
6
+ statuses: string[] = ['active'],
7
+ productIds: string[] = [],
8
+ excludeSubscriptionIds: string[] = [],
9
+ customerId?: string,
10
+ portModes: string[] = [],
11
+ bandwidth?: number,
12
+ ) => {
13
+ const filter_params: SurfSubscriptionDropdownOptionsFilterParams = {
14
+ product_tags: tags,
15
+ statuses,
16
+ product_ids: productIds,
17
+ exclude_subscription_ids: excludeSubscriptionIds,
18
+ port_modes: portModes,
19
+ bandwidth,
20
+ };
21
+
22
+ if (customerId) {
23
+ filter_params.customer_ids = [customerId];
24
+ }
25
+
26
+ const { data, isFetching, refetch, isError } =
27
+ useGetSurfSubscriptionDropdownOptionsQuery({ params: filter_params });
28
+
29
+ const options = (() => {
30
+ if (!isFetching && !isError && data) {
31
+ return data;
32
+ }
33
+ return [];
34
+ })();
35
+
36
+ return { isFetching, refetch, options };
37
+ };
@@ -0,0 +1,29 @@
1
+ import React, { FC } from 'react';
2
+
3
+ import { WfoIconProps } from './WfoIconProps';
4
+
5
+ export const WfoExclamationTriangle: FC<WfoIconProps> = ({
6
+ width = 24,
7
+ height = 24,
8
+ color = '#000000',
9
+ }) => (
10
+ <svg
11
+ width={width}
12
+ height={height}
13
+ viewBox="0 0 24 24"
14
+ version="1.1"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ color={color}
17
+ >
18
+ <title>icon/exclamation-circle</title>
19
+ <g id="Symbols" strokeWidth="1.5" fill="currentColor">
20
+ <g id="icon/exclamation-triangle" fill="currentColor">
21
+ <path
22
+ fillRule="evenodd"
23
+ d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
24
+ clipRule="evenodd"
25
+ />
26
+ </g>
27
+ </g>
28
+ </svg>
29
+ );
@@ -39,3 +39,4 @@ export * from './WfoActualWork';
39
39
  export * from './WfoMalfunction';
40
40
  export * from './WfoPlannedWork';
41
41
  export * from './WfoCubeFill';
42
+ export * from './WfoExclamationTriangle';
@@ -128,33 +128,18 @@ export const WfoTasksPage = () => {
128
128
  columnType: ColumnType.DATA,
129
129
  label: t('description'),
130
130
  width: '700px',
131
- renderData: (value, row) =>
132
- value ? (
133
- <WfoMetadataDescriptionField
134
- onSave={(updatedNote) =>
135
- updateWorkflow({
136
- id: row.workflowId,
137
- description: updatedNote,
138
- })
139
- }
140
- description={value}
141
- />
142
- ) : null,
131
+ renderData: (value, row) => (
132
+ <WfoMetadataDescriptionField
133
+ onSave={(updatedNote) =>
134
+ updateWorkflow({
135
+ id: row.workflowId,
136
+ description: updatedNote,
137
+ })
138
+ }
139
+ description={value}
140
+ />
141
+ ),
143
142
  },
144
-
145
- // description: {
146
- // columnType: ColumnType.DATA,
147
- // label: t('description'),
148
- // width: '450px',
149
- // renderData: (value, row) =>
150
- // value ? (
151
- // <WfoWorkflowDescriptionField
152
- // workflow_id={row.workflowId}
153
- // description={value}
154
- // />
155
- // ) : null,
156
- // },
157
-
158
143
  target: {
159
144
  columnType: ColumnType.DATA,
160
145
  label: t('target'),
@@ -131,18 +131,17 @@ export const WfoWorkflowsPage = () => {
131
131
  columnType: ColumnType.DATA,
132
132
  label: t('description'),
133
133
  width: '700px',
134
- renderData: (value, row) =>
135
- value ? (
136
- <WfoMetadataDescriptionField
137
- onSave={(updatedNote) =>
138
- updateWorkflow({
139
- id: row.workflowId,
140
- description: updatedNote,
141
- })
142
- }
143
- description={value}
144
- />
145
- ) : null,
134
+ renderData: (value, row) => (
135
+ <WfoMetadataDescriptionField
136
+ onSave={(updatedNote) =>
137
+ updateWorkflow({
138
+ id: row.workflowId,
139
+ description: updatedNote,
140
+ })
141
+ }
142
+ description={value}
143
+ />
144
+ ),
146
145
  },
147
146
  target: {
148
147
  columnType: ColumnType.DATA,
package/src/rtk/api.ts CHANGED
@@ -61,6 +61,7 @@ export type UseQuery<T, U> = (
61
61
  type ExtraOptions = {
62
62
  baseQueryType?: BaseQueryTypes;
63
63
  apiName?: string;
64
+ paramsSerializer?: (params: Record<string, unknown>) => string;
64
65
  };
65
66
 
66
67
  export type WfoGraphqlError = {
@@ -131,7 +132,7 @@ export const catchErrorResponse = async (
131
132
  export const orchestratorApi = createApi({
132
133
  reducerPath: 'orchestratorApi',
133
134
  baseQuery: (args, api, extraOptions: ExtraOptions) => {
134
- const { baseQueryType, apiName } = extraOptions || {};
135
+ const { baseQueryType, apiName, paramsSerializer } = extraOptions || {};
135
136
 
136
137
  const state = api.getState() as RootState;
137
138
  const { orchestratorApiBaseUrl, graphqlEndpointCore, authActive } =
@@ -148,6 +149,7 @@ export const orchestratorApi = createApi({
148
149
  ? customApi.apiBaseUrl
149
150
  : orchestratorApiBaseUrl,
150
151
  prepareHeaders,
152
+ paramsSerializer,
151
153
  responseHandler: (response) =>
152
154
  catchErrorResponse(response, authActive),
153
155
  });
@@ -0,0 +1 @@
1
+ export * from './surfSubscriptionDropdownOptions';
@@ -0,0 +1,53 @@
1
+ import { Option } from '@/components/WfoForms/formFields/types';
2
+ import { SUBSCRIPTION_DROPDOWN_OPTIONS_ENDPOINT } from '@/configuration';
3
+ import { BaseQueryTypes, orchestratorApi } from '@/rtk';
4
+ import { SurfSubscriptionDropdownOptionsFilterParams } from '@/types';
5
+
6
+ // Custom endpoint used by the deprecated SubscriptionField formfield.
7
+ // Has to be present in the library for now.
8
+ // In the future, pydantic-forms will make it possible to add/override custom endpoints in the app implementation.
9
+
10
+ /**
11
+ * Serialize URL parameters object to a string.
12
+ *
13
+ * @param params Object with url parameters, values can be scalar or array, i.e. {a: [1, 2], b: [3], c: 4}
14
+ * @returns the url parameter string, i.e. ?a=1&a=2&b=3&c=4
15
+ */
16
+ export function toUrlParams(params: Record<string, unknown>): string {
17
+ const urlParams = new URLSearchParams();
18
+
19
+ Object.entries(params).forEach(([key, value]) => {
20
+ if (Array.isArray(value)) {
21
+ value.forEach((v) => {
22
+ urlParams.append(key, String(v));
23
+ });
24
+ } else if (value !== undefined) {
25
+ urlParams.append(key, String(value));
26
+ }
27
+ });
28
+
29
+ return urlParams.toString();
30
+ }
31
+
32
+ const surfSubscriptionDropdownOptionsApi = orchestratorApi.injectEndpoints({
33
+ endpoints: (build) => ({
34
+ getSurfSubscriptionDropdownOptions: build.query<
35
+ Option<string>[],
36
+ { params: SurfSubscriptionDropdownOptionsFilterParams }
37
+ >({
38
+ query: ({ params }) => ({
39
+ url: SUBSCRIPTION_DROPDOWN_OPTIONS_ENDPOINT,
40
+ params: params,
41
+ }),
42
+ extraOptions: {
43
+ baseQueryType: BaseQueryTypes.fetch,
44
+ paramsSerializer: toUrlParams,
45
+ },
46
+ }),
47
+ }),
48
+ });
49
+
50
+ export const {
51
+ useGetSurfSubscriptionDropdownOptionsQuery,
52
+ useLazyGetSurfSubscriptionDropdownOptionsQuery,
53
+ } = surfSubscriptionDropdownOptionsApi;
@@ -16,5 +16,6 @@ export * from './subscriptionDetail';
16
16
  export * from './subscriptionInUseByRelationsList';
17
17
  export * from './subscriptionList';
18
18
  export * from './subscriptionListSummary';
19
- export * from './subscriptionsDropdownOptions';
20
19
  export * from './forms';
20
+ export * from './deprecated';
21
+ export * from './formFields';