@sap-ux/control-property-editor 0.5.21 → 0.5.23
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/CHANGELOG.md +12 -0
- package/dist/app.css.map +1 -1
- package/dist/app.js +71 -72
- package/dist/app.js.map +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/i18n/i18n.json +3 -2
- package/src/panels/changes/ChangeStack.tsx +128 -43
- package/src/panels/changes/ChangesPanel.module.scss +20 -9
- package/src/panels/changes/ChangesPanel.tsx +3 -2
- package/src/panels/changes/ControlChange.tsx +139 -0
- package/src/panels/changes/ControlGroup.tsx +5 -7
- package/src/panels/changes/NoChangesFound.tsx +47 -0
- package/src/slice.ts +55 -26
- package/test/unit/panels/changes/ChangesPanel.test.tsx +129 -34
- package/src/panels/changes/OtherChange.module.scss +0 -13
- package/src/panels/changes/OtherChange.tsx +0 -49
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
import type { PendingChange, SavedChange } from '@sap-ux-private/control-property-editor-common';
|
|
2
|
+
import type { FilterOptions, ChangesSlice } from '../../../../src/slice';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
5
|
+
import * as cpeCommon from '@sap-ux-private/control-property-editor-common';
|
|
6
|
+
import * as reactRedux from 'react-redux';
|
|
6
7
|
import { render } from '../../utils';
|
|
7
|
-
|
|
8
8
|
import { FilterName } from '../../../../src/slice';
|
|
9
|
-
import type { FilterOptions, ChangesSlice } from '../../../../src/slice';
|
|
10
9
|
import { ChangesPanel } from '../../../../src/panels/changes';
|
|
11
10
|
|
|
11
|
+
jest.mock('@sap-ux-private/control-property-editor-common', () => {
|
|
12
|
+
return {
|
|
13
|
+
__esModule: true,
|
|
14
|
+
...jest.requireActual('@sap-ux-private/control-property-editor-common')
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
12
18
|
const getChanges = (generateSavedChanges = false): ChangesSlice => {
|
|
13
19
|
const pending: PendingChange[] = !generateSavedChanges
|
|
14
20
|
? [
|
|
@@ -46,22 +52,19 @@ const getChanges = (generateSavedChanges = false): ChangesSlice => {
|
|
|
46
52
|
fileName: 'testFile3'
|
|
47
53
|
},
|
|
48
54
|
{
|
|
49
|
-
kind: '
|
|
55
|
+
kind: 'control',
|
|
50
56
|
controlId: 'ListReport::TableToolbar',
|
|
51
|
-
controlName: 'OverflowToolbar',
|
|
52
57
|
type: 'pending',
|
|
53
58
|
isActive: true,
|
|
54
59
|
changeType: 'addXML',
|
|
55
|
-
fileName: '
|
|
60
|
+
fileName: 'id_1691659414768_128_addXML'
|
|
56
61
|
},
|
|
57
62
|
{
|
|
58
63
|
kind: 'unknown',
|
|
59
|
-
controlId: 'FieldGroup::TechnicalData::FormGroup',
|
|
60
|
-
controlName: 'Group',
|
|
61
64
|
type: 'pending',
|
|
62
65
|
isActive: true,
|
|
63
66
|
changeType: 'addFields',
|
|
64
|
-
fileName: '
|
|
67
|
+
fileName: 'id_1691659414768_128_addFields'
|
|
65
68
|
}
|
|
66
69
|
]
|
|
67
70
|
: [];
|
|
@@ -112,7 +115,6 @@ const getChanges = (generateSavedChanges = false): ChangesSlice => {
|
|
|
112
115
|
changeType: 'propertyChange'
|
|
113
116
|
},
|
|
114
117
|
{
|
|
115
|
-
controlId: 'supplierView--supplierForm',
|
|
116
118
|
changeType: 'move',
|
|
117
119
|
type: 'saved',
|
|
118
120
|
fileName: 'id_1698648267087_373_moveSimpleFormField',
|
|
@@ -120,7 +122,6 @@ const getChanges = (generateSavedChanges = false): ChangesSlice => {
|
|
|
120
122
|
timestamp: new Date('2023-10-11T12:06:53.939Z').getTime()
|
|
121
123
|
},
|
|
122
124
|
{
|
|
123
|
-
controlId: 'supplierView--supplierForm',
|
|
124
125
|
changeType: 'move',
|
|
125
126
|
type: 'saved',
|
|
126
127
|
fileName: 'id_1698648267088_374_moveSimpleFormField',
|
|
@@ -161,8 +162,12 @@ describe('ChangePanel', () => {
|
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
// check no controls found
|
|
164
|
-
const
|
|
165
|
-
expect(
|
|
165
|
+
const noChangesText = screen.getByText('No historic changes');
|
|
166
|
+
expect(noChangesText).toHaveTextContent('No historic changes');
|
|
167
|
+
const modifyApplicationText = screen.getByText('This application was not modified yet');
|
|
168
|
+
expect(modifyApplicationText).toHaveTextContent('This application was not modified yet');
|
|
169
|
+
const noChangesIcon = screen.getByTestId('Control-Property-Editor-No-Changes-Icon');
|
|
170
|
+
expect(noChangesIcon).toBeInTheDocument();
|
|
166
171
|
});
|
|
167
172
|
|
|
168
173
|
test('unsaved changes - all changes', () => {
|
|
@@ -186,11 +191,11 @@ describe('ChangePanel', () => {
|
|
|
186
191
|
const value = screen.getByText(/testValue1/i);
|
|
187
192
|
expect(value).toBeInTheDocument();
|
|
188
193
|
|
|
189
|
-
const
|
|
190
|
-
expect(controlToolbar).toBeInTheDocument();
|
|
191
|
-
|
|
192
|
-
const changeAddXML = screen.getByText(/add fields/i);
|
|
194
|
+
const changeAddXML = screen.getByText(/add xml/i);
|
|
193
195
|
expect(changeAddXML).toBeInTheDocument();
|
|
196
|
+
|
|
197
|
+
const changeAddFields = screen.getByText(/add fields/i);
|
|
198
|
+
expect(changeAddFields).toBeInTheDocument();
|
|
194
199
|
});
|
|
195
200
|
|
|
196
201
|
test('saved changes - property change', () => {
|
|
@@ -252,7 +257,7 @@ describe('ChangePanel', () => {
|
|
|
252
257
|
expect(screen.queryByText(/Test Property Name2/i)).toStrictEqual(null);
|
|
253
258
|
});
|
|
254
259
|
|
|
255
|
-
test('saved changes -
|
|
260
|
+
test('saved changes - Unknown change', () => {
|
|
256
261
|
render(<ChangesPanel />, {
|
|
257
262
|
initialState: {
|
|
258
263
|
changes: {
|
|
@@ -260,11 +265,10 @@ describe('ChangePanel', () => {
|
|
|
260
265
|
pending: [],
|
|
261
266
|
saved: [
|
|
262
267
|
{
|
|
263
|
-
changeType: '',
|
|
264
|
-
fileName: '
|
|
268
|
+
changeType: 'codeExt',
|
|
269
|
+
fileName: 'id_1691659414768_328_codeExt',
|
|
265
270
|
type: 'saved',
|
|
266
|
-
kind: 'unknown'
|
|
267
|
-
controlId: 'someSelectorId'
|
|
271
|
+
kind: 'unknown'
|
|
268
272
|
}
|
|
269
273
|
],
|
|
270
274
|
pendingChangeIds: []
|
|
@@ -277,22 +281,69 @@ describe('ChangePanel', () => {
|
|
|
277
281
|
const savedChangesTitle = screen.getByText(/saved changes/i);
|
|
278
282
|
expect(savedChangesTitle).toBeInTheDocument();
|
|
279
283
|
|
|
280
|
-
const title = screen.getByText(/
|
|
284
|
+
const title = screen.getByText(/code ext/i);
|
|
281
285
|
expect(title).toBeInTheDocument();
|
|
282
286
|
|
|
283
287
|
const fileLabel = screen.getByText(/file:/i);
|
|
284
288
|
expect(fileLabel).toBeInTheDocument();
|
|
285
289
|
|
|
286
|
-
const fileName = screen.getByText(/
|
|
290
|
+
const fileName = screen.getByText(/id_1691659414768_328_codeExt/i);
|
|
287
291
|
expect(fileName).toBeInTheDocument();
|
|
288
292
|
|
|
289
|
-
const
|
|
290
|
-
|
|
293
|
+
const deleteButton = screen.getAllByRole('button')[0];
|
|
294
|
+
const iTagAttributes = deleteButton?.children?.item(0)?.children?.item(0)?.attributes;
|
|
295
|
+
const iconName = iTagAttributes?.getNamedItem('data-icon-name')?.value;
|
|
296
|
+
expect(deleteButton).toBeInTheDocument();
|
|
297
|
+
expect(iconName).toBe('TrashCan');
|
|
291
298
|
|
|
292
|
-
|
|
293
|
-
expect(
|
|
299
|
+
fireEvent.click(deleteButton);
|
|
300
|
+
expect(screen.getByText(/Are you sure you want to delete/i)).toBeInTheDocument();
|
|
294
301
|
|
|
295
|
-
|
|
302
|
+
// first cancel
|
|
303
|
+
const cancelButton = screen.getByRole('button', { name: /^Cancel$/i });
|
|
304
|
+
cancelButton.click();
|
|
305
|
+
|
|
306
|
+
// delete
|
|
307
|
+
fireEvent.click(deleteButton);
|
|
308
|
+
const confirmButton = screen.getByRole('button', { name: /^Delete$/i });
|
|
309
|
+
confirmButton.click();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('saved changes - control change', () => {
|
|
313
|
+
render(<ChangesPanel />, {
|
|
314
|
+
initialState: {
|
|
315
|
+
changes: {
|
|
316
|
+
controls: {},
|
|
317
|
+
pending: [],
|
|
318
|
+
saved: [
|
|
319
|
+
{
|
|
320
|
+
changeType: 'renameLabel',
|
|
321
|
+
controlId: 'testId1',
|
|
322
|
+
fileName: 'id_1691659414768_328_renameLabel',
|
|
323
|
+
timestamp: new Date('2022-02-09T12:06:53.939Z').getTime(),
|
|
324
|
+
type: 'saved',
|
|
325
|
+
kind: 'control'
|
|
326
|
+
}
|
|
327
|
+
],
|
|
328
|
+
pendingChangeIds: []
|
|
329
|
+
},
|
|
330
|
+
filterQuery: filterInitOptions
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const savedChangesTitle = screen.getByText(/saved changes/i);
|
|
335
|
+
expect(savedChangesTitle).toBeInTheDocument();
|
|
336
|
+
|
|
337
|
+
const title = screen.getByText(/Rename Label/i);
|
|
338
|
+
expect(title).toBeInTheDocument();
|
|
339
|
+
|
|
340
|
+
const fileLabel = screen.getByText(/file:/i);
|
|
341
|
+
expect(fileLabel).toBeInTheDocument();
|
|
342
|
+
|
|
343
|
+
const fileName = screen.getByText(/id_1691659414768_328_renameLabel/i);
|
|
344
|
+
expect(fileName).toBeInTheDocument();
|
|
345
|
+
|
|
346
|
+
const deleteButton = screen.getAllByRole('button')[1];
|
|
296
347
|
const iTagAttributes = deleteButton?.children?.item(0)?.children?.item(0)?.attributes;
|
|
297
348
|
const iconName = iTagAttributes?.getNamedItem('data-icon-name')?.value;
|
|
298
349
|
expect(deleteButton).toBeInTheDocument();
|
|
@@ -311,8 +362,52 @@ describe('ChangePanel', () => {
|
|
|
311
362
|
confirmButton.click();
|
|
312
363
|
});
|
|
313
364
|
|
|
365
|
+
test('saved control change - link', () => {
|
|
366
|
+
jest.spyOn(cpeCommon, 'selectControl').mockImplementationOnce(jest.fn());
|
|
367
|
+
jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(jest.fn());
|
|
368
|
+
|
|
369
|
+
render(<ChangesPanel />, {
|
|
370
|
+
initialState: {
|
|
371
|
+
changes: {
|
|
372
|
+
controls: {},
|
|
373
|
+
pending: [],
|
|
374
|
+
saved: [
|
|
375
|
+
{
|
|
376
|
+
changeType: 'renameLabel',
|
|
377
|
+
controlId: 'testId1',
|
|
378
|
+
fileName: 'id_1691659414768_328_renameLabel',
|
|
379
|
+
type: 'saved',
|
|
380
|
+
kind: 'control'
|
|
381
|
+
}
|
|
382
|
+
],
|
|
383
|
+
pendingChangeIds: []
|
|
384
|
+
},
|
|
385
|
+
filterQuery: filterInitOptions
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const savedChangesTitle = screen.getByText(/saved changes/i);
|
|
390
|
+
expect(savedChangesTitle).toBeInTheDocument();
|
|
391
|
+
|
|
392
|
+
const title = screen.getByText(/Rename Label/i);
|
|
393
|
+
expect(title).toBeInTheDocument();
|
|
394
|
+
|
|
395
|
+
const fileLabel = screen.getByText(/file:/i);
|
|
396
|
+
expect(fileLabel).toBeInTheDocument();
|
|
397
|
+
|
|
398
|
+
const fileName = screen.getByText(/id_1691659414768_328_renameLabel/i);
|
|
399
|
+
expect(fileName).toBeInTheDocument();
|
|
400
|
+
|
|
401
|
+
const link = screen.getByRole('button', { name: /Rename Label Change/i });
|
|
402
|
+
expect(link).toBeInTheDocument();
|
|
403
|
+
|
|
404
|
+
link.click();
|
|
405
|
+
expect(reactRedux.useDispatch).toBeCalled();
|
|
406
|
+
expect(cpeCommon.selectControl).toBeCalledWith('testId1');
|
|
407
|
+
});
|
|
408
|
+
|
|
314
409
|
test('Filter unsaved changes', () => {
|
|
315
|
-
const filterInitOptions: FilterOptions[] = [{ name: FilterName.changeSummaryFilterQuery, value: '
|
|
410
|
+
const filterInitOptions: FilterOptions[] = [{ name: FilterName.changeSummaryFilterQuery, value: 'fields' }];
|
|
316
411
|
render(<ChangesPanel />, {
|
|
317
412
|
initialState: {
|
|
318
413
|
changes: getChanges(),
|
|
@@ -324,8 +419,8 @@ describe('ChangePanel', () => {
|
|
|
324
419
|
const savedChangesTitle = screen.getByText(/unsaved changes/i);
|
|
325
420
|
expect(savedChangesTitle).toBeInTheDocument();
|
|
326
421
|
|
|
327
|
-
const
|
|
328
|
-
expect(
|
|
422
|
+
const changeAddXML = screen.getByText(/add fields/i);
|
|
423
|
+
expect(changeAddXML).toBeInTheDocument();
|
|
329
424
|
});
|
|
330
425
|
|
|
331
426
|
test('Filter saved changes', () => {
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { ReactElement } from 'react';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
|
|
4
|
-
import { Stack, Text } from '@fluentui/react';
|
|
5
|
-
import type { PendingOtherChange, UnknownSavedChange } from '@sap-ux-private/control-property-editor-common';
|
|
6
|
-
import { convertCamelCaseToPascalCase, SAVED_CHANGE_TYPE } from '@sap-ux-private/control-property-editor-common';
|
|
7
|
-
|
|
8
|
-
import styles from './OtherChange.module.scss';
|
|
9
|
-
|
|
10
|
-
export interface OtherChangeProps {
|
|
11
|
-
/**
|
|
12
|
-
* Class used for showing and hiding actions
|
|
13
|
-
*/
|
|
14
|
-
actionClassName: string;
|
|
15
|
-
change: PendingOtherChange | UnknownSavedChange;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* React element for Other change.
|
|
20
|
-
*
|
|
21
|
-
* @param props OtherChangeProps
|
|
22
|
-
* @returns ReactElement
|
|
23
|
-
*/
|
|
24
|
-
export function OtherChange(props: Readonly<OtherChangeProps>): ReactElement {
|
|
25
|
-
const { change } = props;
|
|
26
|
-
return (
|
|
27
|
-
<Stack
|
|
28
|
-
tokens={{
|
|
29
|
-
childrenGap: 5
|
|
30
|
-
}}
|
|
31
|
-
className={styles.container}
|
|
32
|
-
style={{
|
|
33
|
-
opacity: change.type === SAVED_CHANGE_TYPE || change.isActive ? 1 : 0.4
|
|
34
|
-
}}>
|
|
35
|
-
<Stack.Item className={styles.changeType}>
|
|
36
|
-
<Stack
|
|
37
|
-
horizontal
|
|
38
|
-
horizontalAlign={'space-between'}
|
|
39
|
-
tokens={{
|
|
40
|
-
childrenGap: 5
|
|
41
|
-
}}>
|
|
42
|
-
<Stack.Item>
|
|
43
|
-
<Text className={styles.text}>{convertCamelCaseToPascalCase(change.changeType)}</Text>
|
|
44
|
-
</Stack.Item>
|
|
45
|
-
</Stack>
|
|
46
|
-
</Stack.Item>
|
|
47
|
-
</Stack>
|
|
48
|
-
);
|
|
49
|
-
}
|