@integry/sdk 4.7.14 → 4.7.16
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/.eslintignore +1 -0
- package/.vscode/launch.json +1 -0
- package/dist/esm/index.csm.d.ts +2 -1
- package/dist/esm/index.csm.js +1 -1
- package/dist/umd/index.umd.d.ts +2 -1
- package/dist/umd/index.umd.js +1 -1
- package/package.json +1 -1
- package/src/components/MultipurposeField/Dropdown/index.tsx +13 -12
- package/src/components/form/ObjectField/index.ts.test.tsx +213 -0
- package/src/features/common/FunctionForm/index.ts +2 -0
- package/src/index.ts +11 -1
- package/src/modules/api/index.ts +8 -3
- package/src/types/index.ts +1 -0
- package/src/components/Button/index.test.ts +0 -0
- package/src/renderFlowStep.test.ts +0 -0
package/package.json
CHANGED
|
@@ -322,22 +322,23 @@ const ListBox = (props: ListBoxProps) => {
|
|
|
322
322
|
>(new URL(endpointUrl), data, requestBodyData)
|
|
323
323
|
.then((res: any) => {
|
|
324
324
|
if (res) {
|
|
325
|
-
|
|
325
|
+
const tempFilteredItems = dynamicResponseMapper(res);
|
|
326
|
+
setItems(tempFilteredItems);
|
|
326
327
|
if (res.hasOwnProperty('_cursor') && res._cursor !== null) {
|
|
327
|
-
const tempFilteredItems = dynamicResponseMapper(res);
|
|
328
328
|
setFilteredItems(tempFilteredItems);
|
|
329
329
|
setSortedFilteredItems(tempFilteredItems);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
330
|
+
} else {
|
|
331
|
+
setSortedFilteredItems(tempFilteredItems);
|
|
332
|
+
}
|
|
333
|
+
if (tempFilteredItems.length === 1) {
|
|
334
|
+
setEditableTextValue(tempFilteredItems[0].value);
|
|
335
|
+
onChange(tempFilteredItems[0].id, true);
|
|
336
|
+
} else if (value) {
|
|
337
|
+
const item = tempFilteredItems.find((a) => a.id === value);
|
|
338
|
+
if (item) {
|
|
339
|
+
setEditableTextValue(item.value);
|
|
340
|
+
onChange(item.id, true);
|
|
339
341
|
}
|
|
340
|
-
setSortedFilteredItems(dynamicResponseMapper(res));
|
|
341
342
|
}
|
|
342
343
|
// if value was selected before items were loaded, select it again
|
|
343
344
|
if (value && isSearchable) {
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// ```bash
|
|
2
|
+
// npm install vitest @testing-library/preact @testing-library/user-event --save-dev
|
|
3
|
+
// ```
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
+
import { render, fireEvent, screen } from '@testing-library/preact';
|
|
7
|
+
import userEvent from '@testing-library/user-event';
|
|
8
|
+
import '@testing-library/jest-dom/vitest';
|
|
9
|
+
import { ObjectField } from './index';
|
|
10
|
+
|
|
11
|
+
// Mock components and styles if necessary
|
|
12
|
+
vi.mock('@/components/Input', () => ({ Input: () => <div>Input</div> }));
|
|
13
|
+
vi.mock('@/components/TextArea', () => ({
|
|
14
|
+
TextArea: () => <div>TextArea</div>,
|
|
15
|
+
}));
|
|
16
|
+
vi.mock('@/components/CheckboxGroup', () => ({
|
|
17
|
+
CheckboxGroup: () => <div>CheckboxGroup</div>,
|
|
18
|
+
}));
|
|
19
|
+
vi.mock('@/components/ConfigureFieldWrapper', () => ({
|
|
20
|
+
default: ({ children }: { children: React.ReactNode }) => (
|
|
21
|
+
<div>{children}</div>
|
|
22
|
+
),
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('@/components/MultipurposeField/Dropdown', () => ({
|
|
25
|
+
ListBox: () => <div>ListBox</div>,
|
|
26
|
+
}));
|
|
27
|
+
vi.mock('@/components/MultipurposeField', () => ({
|
|
28
|
+
MultipurposeField: () => <div>MultipurposeField</div>,
|
|
29
|
+
}));
|
|
30
|
+
vi.mock('./styles.module.scss', () => ({
|
|
31
|
+
objectContainer: 'objectContainer',
|
|
32
|
+
objectFieldWrap: 'objectFieldWrap',
|
|
33
|
+
label: 'label',
|
|
34
|
+
subLabel: 'subLabel',
|
|
35
|
+
removeButton: 'removeButton',
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
describe('ObjectField Component', () => {
|
|
39
|
+
const mockOnChange = vi.fn();
|
|
40
|
+
const mockOnChangeInFlow = vi.fn();
|
|
41
|
+
const mockApiHandler = vi.fn();
|
|
42
|
+
|
|
43
|
+
const baseProps = {
|
|
44
|
+
field: {
|
|
45
|
+
title: 'Test Field',
|
|
46
|
+
description: 'Test Description',
|
|
47
|
+
template_fields: [],
|
|
48
|
+
type: 'TEXTFIELD',
|
|
49
|
+
properties: {},
|
|
50
|
+
},
|
|
51
|
+
functionArguments: {},
|
|
52
|
+
connectedAccount: 'test-account',
|
|
53
|
+
appName: 'Test App',
|
|
54
|
+
onChange: mockOnChange,
|
|
55
|
+
onChangeInFlow: mockOnChangeInFlow,
|
|
56
|
+
apiHandler: mockApiHandler,
|
|
57
|
+
activityOutputData: {},
|
|
58
|
+
activityOutputDataRaw: {},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
it('renders without crashing', () => {
|
|
62
|
+
const { container } = render(<ObjectField {...baseProps} />);
|
|
63
|
+
expect(container).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('calls onChange when input changes', async () => {
|
|
67
|
+
const user = userEvent.setup();
|
|
68
|
+
render(<ObjectField {...baseProps} />);
|
|
69
|
+
const input = screen.getByRole('textbox');
|
|
70
|
+
await user.type(input, 'New Value');
|
|
71
|
+
expect(mockOnChange).toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('conditionally renders add more button based on isArray prop', () => {
|
|
75
|
+
const { rerender } = render(<ObjectField {...baseProps} isArray={true} />);
|
|
76
|
+
expect(screen.queryByText('+ Add another Test Field')).toBeInTheDocument();
|
|
77
|
+
|
|
78
|
+
rerender(<ObjectField {...baseProps} isArray={false} />);
|
|
79
|
+
expect(
|
|
80
|
+
screen.queryByText('+ Add another Test Field'),
|
|
81
|
+
).not.toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('handles array of objects and adds more on button click', async () => {
|
|
85
|
+
const user = userEvent.setup();
|
|
86
|
+
render(<ObjectField {...baseProps} isArray={true} />);
|
|
87
|
+
await user.click(screen.getByText('+ Add another Test Field'));
|
|
88
|
+
expect(screen.getAllByText('Test Field').length).toBe(2);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('removes an item from the list when delete is clicked', async () => {
|
|
92
|
+
const user = userEvent.setup();
|
|
93
|
+
render(
|
|
94
|
+
<ObjectField {...baseProps} isArray={true} objectValue={[{}, {}]} />,
|
|
95
|
+
);
|
|
96
|
+
expect(screen.getAllByText('Test Field').length).toBe(2);
|
|
97
|
+
await user.click(screen.getAllByRole('button')[0]); // Assuming the delete button is the first button
|
|
98
|
+
expect(screen.getAllByText('Test Field').length).toBe(1);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('validates props and throws if required props are missing', () => {
|
|
102
|
+
const consoleError = vi.spyOn(console, 'error');
|
|
103
|
+
consoleError.mockImplementation(() => {});
|
|
104
|
+
|
|
105
|
+
expect(() => render(<ObjectField />)).toThrow();
|
|
106
|
+
expect(consoleError).toHaveBeenCalled();
|
|
107
|
+
|
|
108
|
+
consoleError.mockRestore();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('renders with minimal props', () => {
|
|
112
|
+
const { container } = render(
|
|
113
|
+
<ObjectField field={{}} onChange={vi.fn()} apiHandler={vi.fn()} />,
|
|
114
|
+
);
|
|
115
|
+
expect(container).toMatchSnapshot();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('handles add more fields', async () => {
|
|
119
|
+
const onChange = vi.fn();
|
|
120
|
+
render(
|
|
121
|
+
<ObjectField
|
|
122
|
+
field={{ title: 'Test Field', isArray: true }}
|
|
123
|
+
onChange={onChange}
|
|
124
|
+
apiHandler={vi.fn()}
|
|
125
|
+
/>,
|
|
126
|
+
);
|
|
127
|
+
const addButton = screen.getByText('+ Add another Test Field');
|
|
128
|
+
await fireEvent.click(addButton);
|
|
129
|
+
expect(screen.getAllByText('Test Field').length).toBe(2);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('handles field changes', async () => {
|
|
133
|
+
const onChange = vi.fn();
|
|
134
|
+
const field = {
|
|
135
|
+
title: 'Number Field',
|
|
136
|
+
isArray: true,
|
|
137
|
+
properties: {
|
|
138
|
+
numberField: {
|
|
139
|
+
meta: {
|
|
140
|
+
title: 'Number',
|
|
141
|
+
ui: { ui_field: { type: 'TEXTFIELD' } },
|
|
142
|
+
is_required: true,
|
|
143
|
+
},
|
|
144
|
+
type: 'number',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
render(
|
|
149
|
+
<ObjectField field={field} onChange={onChange} apiHandler={vi.fn()} />,
|
|
150
|
+
);
|
|
151
|
+
const input = screen.getByTitle('Number');
|
|
152
|
+
await fireEvent.change(input, { target: { value: '123' } });
|
|
153
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
154
|
+
expect.anything(),
|
|
155
|
+
'123',
|
|
156
|
+
expect.anything(),
|
|
157
|
+
true,
|
|
158
|
+
expect.anything(),
|
|
159
|
+
expect.anything(),
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('renders a textarea when no fields are provided', () => {
|
|
164
|
+
const field = { type: 'TEXTAREA' };
|
|
165
|
+
const { container } = render(
|
|
166
|
+
<ObjectField field={field} onChange={vi.fn()} apiHandler={vi.fn()} />,
|
|
167
|
+
);
|
|
168
|
+
expect(container.querySelector('textarea')).not.toBeNull();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('renders nested fields correctly', () => {
|
|
172
|
+
const field = {
|
|
173
|
+
properties: {
|
|
174
|
+
nestedField: {
|
|
175
|
+
meta: {
|
|
176
|
+
title: 'Nested Field',
|
|
177
|
+
ui: { ui_field: { type: 'CHECKBOX' } },
|
|
178
|
+
is_required: false,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
render(
|
|
184
|
+
<ObjectField field={field} onChange={vi.fn()} apiHandler={vi.fn()} />,
|
|
185
|
+
);
|
|
186
|
+
expect(screen.getByText('CheckboxGroup')).toBeInTheDocument();
|
|
187
|
+
});
|
|
188
|
+
it('handles empty array as objectValue gracefully', () => {
|
|
189
|
+
render(
|
|
190
|
+
<ObjectField
|
|
191
|
+
field={{}}
|
|
192
|
+
onChange={vi.fn()}
|
|
193
|
+
apiHandler={vi.fn()}
|
|
194
|
+
objectValue={[]}
|
|
195
|
+
/>,
|
|
196
|
+
);
|
|
197
|
+
expect(screen.getByText('+ Add another')).toBeInTheDocument();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('handles null objectValue without crashing', () => {
|
|
201
|
+
render(
|
|
202
|
+
<ObjectField
|
|
203
|
+
field={{}}
|
|
204
|
+
onChange={vi.fn()}
|
|
205
|
+
apiHandler={vi.fn()}
|
|
206
|
+
objectValue={null}
|
|
207
|
+
/>,
|
|
208
|
+
);
|
|
209
|
+
expect(screen.queryByText('TextArea')).toBeNull(); // Assuming TextArea is not rendered by default
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Additional tests can be added here to cover more complex interactions and edge cases
|
|
213
|
+
});
|
|
@@ -29,6 +29,7 @@ interface FunctionFormPropsType extends StoreType {
|
|
|
29
29
|
functionArguments: any;
|
|
30
30
|
variables: any;
|
|
31
31
|
autoMapVars: boolean;
|
|
32
|
+
version?: string | null;
|
|
32
33
|
onClose: (response: any) => void;
|
|
33
34
|
apiHandler: any;
|
|
34
35
|
customSaveCallback?: (response: any) => void; // Optional callback: Helps the implementor to implement their own save button
|
|
@@ -99,6 +100,7 @@ class FunctionForm extends Component<
|
|
|
99
100
|
.getFunctionDetails(
|
|
100
101
|
this.props.functionName,
|
|
101
102
|
this.props.autoMapVars ? this.props.variables : {},
|
|
103
|
+
this.props.version,
|
|
102
104
|
)
|
|
103
105
|
.then((response: any) => {
|
|
104
106
|
this.setState({ functionDetails: response });
|
package/src/index.ts
CHANGED
|
@@ -592,6 +592,7 @@ export class IntegryJS {
|
|
|
592
592
|
payload: {},
|
|
593
593
|
connectedAccountId: '',
|
|
594
594
|
autoMapPayload: false,
|
|
595
|
+
version: null,
|
|
595
596
|
},
|
|
596
597
|
): Promise<Record<any, any>> => {
|
|
597
598
|
const store = createSDKStore();
|
|
@@ -601,6 +602,7 @@ export class IntegryJS {
|
|
|
601
602
|
.getFunctionDetails(
|
|
602
603
|
functionName,
|
|
603
604
|
options.autoMapPayload ? options.payload : {},
|
|
605
|
+
options.version,
|
|
604
606
|
)
|
|
605
607
|
.then((response: any) => {
|
|
606
608
|
if (!response) {
|
|
@@ -668,6 +670,7 @@ export class IntegryJS {
|
|
|
668
670
|
functionArguments=${options.params}
|
|
669
671
|
variables=${options.payload}
|
|
670
672
|
autoMapVars=${options.autoMapPayload}
|
|
673
|
+
version=${options.version}
|
|
671
674
|
apiHandler=${this.apiHandler}
|
|
672
675
|
onClose=${(functionUIResponse: any) => {
|
|
673
676
|
const authIdElement = document.getElementById(
|
|
@@ -735,13 +738,20 @@ export class IntegryJS {
|
|
|
735
738
|
[key: string]: any;
|
|
736
739
|
} = {},
|
|
737
740
|
connectedAccountId: string,
|
|
741
|
+
version: string | null = null,
|
|
738
742
|
): Promise<Record<any, any>> =>
|
|
739
743
|
new Promise((resolve, reject) => {
|
|
740
744
|
// Prepare the request body by encoding `args` to JSON
|
|
745
|
+
const headers: Record<string, string> = {
|
|
746
|
+
...this.getHeaders(),
|
|
747
|
+
};
|
|
748
|
+
if (version) {
|
|
749
|
+
headers.Version = version;
|
|
750
|
+
}
|
|
741
751
|
const functionDetails = {
|
|
742
752
|
method: this.getMethod(),
|
|
743
753
|
url: `${this.getBaseAPIUrl()}/functions/${functionName}/call/`,
|
|
744
|
-
headers
|
|
754
|
+
headers,
|
|
745
755
|
args: params,
|
|
746
756
|
vars,
|
|
747
757
|
};
|
package/src/modules/api/index.ts
CHANGED
|
@@ -1172,6 +1172,7 @@ class IntegryAPI {
|
|
|
1172
1172
|
public getFunctionDetails = async (
|
|
1173
1173
|
functionName: string,
|
|
1174
1174
|
variables: Record<string, unknown> = {},
|
|
1175
|
+
version: string | null = null,
|
|
1175
1176
|
): Promise<any | null> => {
|
|
1176
1177
|
const url = new URL(
|
|
1177
1178
|
`${this.config.baseAPIUrl}/functions/${functionName}/get/`,
|
|
@@ -1185,14 +1186,18 @@ class IntegryAPI {
|
|
|
1185
1186
|
});
|
|
1186
1187
|
|
|
1187
1188
|
try {
|
|
1189
|
+
const headers: Record<string, string> = {
|
|
1190
|
+
'Content-Type': 'application/json',
|
|
1191
|
+
};
|
|
1192
|
+
if (version) {
|
|
1193
|
+
headers.Version = version;
|
|
1194
|
+
}
|
|
1188
1195
|
const response = await fetch(url.toString(), {
|
|
1189
1196
|
method: 'POST',
|
|
1190
1197
|
body: JSON.stringify({
|
|
1191
1198
|
_variables: variables,
|
|
1192
1199
|
}),
|
|
1193
|
-
headers
|
|
1194
|
-
'Content-Type': 'application/json',
|
|
1195
|
-
},
|
|
1200
|
+
headers,
|
|
1196
1201
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1197
1202
|
}).then((data) => ResponseHandler<BrandingApp>(data));
|
|
1198
1203
|
return response.data;
|
package/src/types/index.ts
CHANGED
|
File without changes
|
|
File without changes
|