@sap-ux/control-property-editor 0.5.21 → 0.5.22
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 +6 -0
- package/dist/app.css.map +1 -1
- package/dist/app.js +51 -63
- package/dist/app.js.map +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/panels/changes/ChangeStack.tsx +128 -43
- package/src/panels/changes/ControlChange.tsx +139 -0
- package/src/panels/changes/ControlGroup.tsx +5 -7
- package/src/slice.ts +55 -26
- package/test/unit/panels/changes/ChangesPanel.test.tsx +123 -32
- package/src/panels/changes/OtherChange.module.scss +0 -13
- package/src/panels/changes/OtherChange.tsx +0 -49
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"displayName": "Control Property Editor",
|
|
4
4
|
"description": "Control Property Editor",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"version": "0.5.
|
|
6
|
+
"version": "0.5.22",
|
|
7
7
|
"main": "dist/app.js",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"autoprefixer": "10.4.7",
|
|
50
50
|
"postcss": "8.4.31",
|
|
51
51
|
"yargs-parser": "21.1.1",
|
|
52
|
-
"@sap-ux/ui-components": "1.
|
|
53
|
-
"@sap-ux-private/control-property-editor-common": "0.5.
|
|
52
|
+
"@sap-ux/ui-components": "1.20.1",
|
|
53
|
+
"@sap-ux-private/control-property-editor-common": "0.5.5"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"clean": "rimraf --glob dist coverage *.tsbuildinfo",
|
|
@@ -3,6 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { Stack } from '@fluentui/react';
|
|
4
4
|
import type { Change } from '@sap-ux-private/control-property-editor-common';
|
|
5
5
|
import {
|
|
6
|
+
CONTROL_CHANGE_KIND,
|
|
6
7
|
convertCamelCaseToPascalCase,
|
|
7
8
|
PENDING_CHANGE_TYPE,
|
|
8
9
|
PROPERTY_CHANGE_KIND,
|
|
@@ -22,6 +23,8 @@ import type { FilterOptions } from '../../slice';
|
|
|
22
23
|
import { FilterName } from '../../slice';
|
|
23
24
|
import type { RootState } from '../../store';
|
|
24
25
|
import { getFormattedDateAndTime } from './utils';
|
|
26
|
+
import type { ControlItemProps } from './ControlChange';
|
|
27
|
+
import { ControlChange } from './ControlChange';
|
|
25
28
|
|
|
26
29
|
export interface ChangeStackProps {
|
|
27
30
|
changes: Change[];
|
|
@@ -44,31 +47,57 @@ export function ChangeStack(changeStackProps: ChangeStackProps): ReactElement {
|
|
|
44
47
|
const stackName = changes[0].type === PENDING_CHANGE_TYPE ? 'unsaved-changes-stack' : 'saved-changes-stack';
|
|
45
48
|
return (
|
|
46
49
|
<Stack data-testid={stackName} tokens={{ childrenGap: 5, padding: '5px 0px 5px 0px' }}>
|
|
47
|
-
{groups.map((item, i) => [
|
|
48
|
-
isControlGroup(item) ? (
|
|
49
|
-
<Stack.Item
|
|
50
|
-
data-testid={`${stackName}-${item.controlId}-${item.index}`}
|
|
51
|
-
key={`${item.controlId}-${item.index}`}>
|
|
52
|
-
<ControlGroup {...item} />
|
|
53
|
-
</Stack.Item>
|
|
54
|
-
) : (
|
|
55
|
-
<Stack.Item key={`${item.fileName}`}>
|
|
56
|
-
<UnknownChange {...item} />
|
|
57
|
-
</Stack.Item>
|
|
58
|
-
),
|
|
59
|
-
|
|
60
|
-
i + 1 < groups.length ? (
|
|
61
|
-
<Stack.Item key={getKey(i)}>
|
|
62
|
-
<Separator className={styles.item} />
|
|
63
|
-
</Stack.Item>
|
|
64
|
-
) : (
|
|
65
|
-
<></>
|
|
66
|
-
)
|
|
67
|
-
])}
|
|
50
|
+
{groups.map((item, i) => [renderChangeItem(item, stackName), renderSeparator(i, groups)])}
|
|
68
51
|
</Stack>
|
|
69
52
|
);
|
|
70
53
|
}
|
|
71
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Renders the appropriate change item component based on the type of the item.
|
|
57
|
+
*
|
|
58
|
+
* @param item - The current item from the group to be rendered.
|
|
59
|
+
* @param stackName - The name of the stack used for test IDs.
|
|
60
|
+
* @returns The rendered change item (`ControlGroup`, `ControlChange`, or `UnknownChange`).
|
|
61
|
+
*/
|
|
62
|
+
function renderChangeItem(item: Item, stackName: string): ReactElement {
|
|
63
|
+
if (isPropertyGroup(item)) {
|
|
64
|
+
return (
|
|
65
|
+
<Stack.Item
|
|
66
|
+
data-testid={`${stackName}-${item.controlId}-${item.index}`}
|
|
67
|
+
key={`${item.controlId}-${item.index}`}>
|
|
68
|
+
<ControlGroup {...item} />
|
|
69
|
+
</Stack.Item>
|
|
70
|
+
);
|
|
71
|
+
} else if (isControlItem(item)) {
|
|
72
|
+
return (
|
|
73
|
+
<Stack.Item key={`${item.fileName}`}>
|
|
74
|
+
<ControlChange {...item} />
|
|
75
|
+
</Stack.Item>
|
|
76
|
+
);
|
|
77
|
+
} else {
|
|
78
|
+
return (
|
|
79
|
+
<Stack.Item key={`${item.fileName}`}>
|
|
80
|
+
<UnknownChange {...item} />
|
|
81
|
+
</Stack.Item>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Renders a separator between items, except for the last one.
|
|
88
|
+
*
|
|
89
|
+
* @param i - The index of the current item in the group.
|
|
90
|
+
* @param groups - The array of all groups to check if it's the last item.
|
|
91
|
+
* @returns {ReactElement | null} The rendered separator or `null` if it's the last item.
|
|
92
|
+
*/
|
|
93
|
+
function renderSeparator(i: number, groups: Item[]): ReactElement | null {
|
|
94
|
+
return i + 1 < groups.length ? (
|
|
95
|
+
<Stack.Item key={getKey(i)}>
|
|
96
|
+
<Separator className={styles.item} />
|
|
97
|
+
</Stack.Item>
|
|
98
|
+
) : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
72
101
|
/**
|
|
73
102
|
* Generate react attribute key.
|
|
74
103
|
*
|
|
@@ -79,13 +108,13 @@ function getKey(i: number): string {
|
|
|
79
108
|
return `${i}-separator`;
|
|
80
109
|
}
|
|
81
110
|
|
|
82
|
-
type Item = ControlGroupProps | UnknownChangeProps;
|
|
111
|
+
type Item = ControlGroupProps | UnknownChangeProps | ControlItemProps;
|
|
83
112
|
|
|
84
113
|
/**
|
|
85
|
-
*
|
|
114
|
+
* Converts an array of changes into an array of items, grouping changes by controlId and handling different kinds of changes.
|
|
86
115
|
*
|
|
87
|
-
* @param
|
|
88
|
-
* @returns Item[]
|
|
116
|
+
* @param {Change[]} changes - An array of changes to be converted.
|
|
117
|
+
* @returns {Item[]} An array of items, some of which may be control groups.
|
|
89
118
|
*/
|
|
90
119
|
function convertChanges(changes: Change[]): Item[] {
|
|
91
120
|
const items: Item[] = [];
|
|
@@ -93,28 +122,24 @@ function convertChanges(changes: Change[]): Item[] {
|
|
|
93
122
|
while (i < changes.length) {
|
|
94
123
|
const change: Change = changes[i];
|
|
95
124
|
let group: ControlGroupProps;
|
|
96
|
-
if (change.kind === UNKNOWN_CHANGE_KIND
|
|
97
|
-
items.push(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
controlId: change.controlId ?? ''
|
|
102
|
-
});
|
|
125
|
+
if (change.kind === UNKNOWN_CHANGE_KIND) {
|
|
126
|
+
items.push(handleUnknownChange(change));
|
|
127
|
+
i++;
|
|
128
|
+
} else if (change.kind === CONTROL_CHANGE_KIND) {
|
|
129
|
+
items.push(handleControlChange(change));
|
|
103
130
|
i++;
|
|
104
131
|
} else {
|
|
105
|
-
group =
|
|
106
|
-
controlId: change.controlId,
|
|
107
|
-
controlName: change.controlName,
|
|
108
|
-
text: convertCamelCaseToPascalCase(change.controlName),
|
|
109
|
-
index: i,
|
|
110
|
-
changes: [change]
|
|
111
|
-
};
|
|
132
|
+
group = handleGroupedChange(change, i);
|
|
112
133
|
items.push(group);
|
|
113
134
|
i++;
|
|
114
135
|
while (i < changes.length) {
|
|
115
136
|
// We don't need to add header again if the next control is the same
|
|
116
137
|
const nextChange = changes[i];
|
|
117
|
-
if (
|
|
138
|
+
if (
|
|
139
|
+
nextChange.kind === UNKNOWN_CHANGE_KIND ||
|
|
140
|
+
nextChange.kind === CONTROL_CHANGE_KIND ||
|
|
141
|
+
change.controlId !== nextChange.controlId
|
|
142
|
+
) {
|
|
118
143
|
break;
|
|
119
144
|
}
|
|
120
145
|
group.changes.push(nextChange);
|
|
@@ -125,16 +150,76 @@ function convertChanges(changes: Change[]): Item[] {
|
|
|
125
150
|
return items;
|
|
126
151
|
}
|
|
127
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Handles changes of kind `unknown` and creates an item with a header.
|
|
155
|
+
*
|
|
156
|
+
* @param {Change} change - The change object of kind `unknown`.
|
|
157
|
+
* @returns {Item} An item object containing the filename and header information.
|
|
158
|
+
*/
|
|
159
|
+
function handleUnknownChange(change: Change): Item {
|
|
160
|
+
return {
|
|
161
|
+
fileName: change.fileName,
|
|
162
|
+
header: true,
|
|
163
|
+
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Handles changes of kind `control` and creates an item with controlId and type.
|
|
169
|
+
*
|
|
170
|
+
* @param {Change} change - The change object of kind `control`.
|
|
171
|
+
* @returns {Item} An item object containing the filename, controlId, type, and optional timestamp.
|
|
172
|
+
*/
|
|
173
|
+
function handleControlChange(change: Change & { controlId: string }): Item {
|
|
174
|
+
return {
|
|
175
|
+
fileName: change.fileName,
|
|
176
|
+
controlId: change.controlId,
|
|
177
|
+
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined,
|
|
178
|
+
type: change.type
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Handles grouped changes by initializing a control group with a list of changes that share the same controlId.
|
|
184
|
+
*
|
|
185
|
+
* @param {Change} change - The initial change object to start the group.
|
|
186
|
+
* @param {number} i - The index of the initial change in the list.
|
|
187
|
+
* @returns {ControlGroupProps} A control group object containing grouped changes.
|
|
188
|
+
*/
|
|
189
|
+
function handleGroupedChange(
|
|
190
|
+
change: Change & { controlId: string; controlName: string },
|
|
191
|
+
i: number
|
|
192
|
+
): ControlGroupProps {
|
|
193
|
+
return {
|
|
194
|
+
controlId: change.controlId,
|
|
195
|
+
controlName: change.controlName,
|
|
196
|
+
text: convertCamelCaseToPascalCase(change.controlName),
|
|
197
|
+
index: i,
|
|
198
|
+
changes: [change],
|
|
199
|
+
timestamp: change.type === SAVED_CHANGE_TYPE ? change.timestamp : undefined
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
128
203
|
/**
|
|
129
204
|
* Checks if item is of type {@link ControlGroupProps}.
|
|
130
205
|
*
|
|
131
|
-
* @param item ControlGroupProps | UnknownChangeProps
|
|
206
|
+
* @param item ControlGroupProps | UnknownChangeProps | ControlItemProps
|
|
132
207
|
* @returns boolean
|
|
133
208
|
*/
|
|
134
|
-
function
|
|
209
|
+
function isPropertyGroup(item: ControlGroupProps | UnknownChangeProps | ControlItemProps): item is ControlGroupProps {
|
|
135
210
|
return (item as ControlGroupProps).controlName !== undefined;
|
|
136
211
|
}
|
|
137
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Checks if item is of type {@link ControlItemProps}.
|
|
215
|
+
*
|
|
216
|
+
* @param item UnknownChangeProps | ControlItemProps
|
|
217
|
+
* @returns boolean
|
|
218
|
+
*/
|
|
219
|
+
function isControlItem(item: UnknownChangeProps | ControlItemProps): item is ControlItemProps {
|
|
220
|
+
return item?.controlId !== undefined;
|
|
221
|
+
}
|
|
222
|
+
|
|
138
223
|
const filterPropertyChanges = (changes: Change[], query: string): Change[] => {
|
|
139
224
|
return changes.filter((item): boolean => {
|
|
140
225
|
if (item.kind === PROPERTY_CHANGE_KIND) {
|
|
@@ -184,7 +269,7 @@ function filterGroup(model: Item[], query: string): Item[] {
|
|
|
184
269
|
}
|
|
185
270
|
for (const item of model) {
|
|
186
271
|
let parentMatch = false;
|
|
187
|
-
if (!
|
|
272
|
+
if (!isPropertyGroup(item)) {
|
|
188
273
|
if (isQueryMatchesChange(item, query)) {
|
|
189
274
|
filteredModel.push({ ...item, changes: [] });
|
|
190
275
|
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import React, { useMemo, useState } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Text, Stack, Link } from '@fluentui/react';
|
|
5
|
+
import { useDispatch } from 'react-redux';
|
|
6
|
+
import styles from './UnknownChange.module.scss';
|
|
7
|
+
import { UIIconButton, UiIcons, UIDialog } from '@sap-ux/ui-components';
|
|
8
|
+
import type {
|
|
9
|
+
PropertyChangeDeletionDetails,
|
|
10
|
+
PENDING_CHANGE_TYPE
|
|
11
|
+
} from '@sap-ux-private/control-property-editor-common';
|
|
12
|
+
import {
|
|
13
|
+
SAVED_CHANGE_TYPE,
|
|
14
|
+
convertCamelCaseToPascalCase,
|
|
15
|
+
deletePropertyChanges,
|
|
16
|
+
selectControl
|
|
17
|
+
} from '@sap-ux-private/control-property-editor-common';
|
|
18
|
+
import { getFormattedDateAndTime } from './utils';
|
|
19
|
+
|
|
20
|
+
export interface ControlItemProps {
|
|
21
|
+
fileName: string;
|
|
22
|
+
timestamp?: number;
|
|
23
|
+
controlId: string;
|
|
24
|
+
type: typeof SAVED_CHANGE_TYPE | typeof PENDING_CHANGE_TYPE;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* React element for control change in the change stack.
|
|
29
|
+
*
|
|
30
|
+
* @param {Readonly<ControlItemProps>} props - The props object.
|
|
31
|
+
* @param {string} props.controlId - The ID of the control being changed.
|
|
32
|
+
* @param {string} props.fileName - The name of the file associated with the change.
|
|
33
|
+
* @param {number} [props.timestamp] - The timestamp of the change, optional.
|
|
34
|
+
* @param {string} props.type - The type of the change (e.g., 'saved' | 'pending').
|
|
35
|
+
* @returns {ReactElement} A React element that renders the control change UI.
|
|
36
|
+
*/
|
|
37
|
+
export function ControlChange({ controlId, fileName, timestamp, type }: Readonly<ControlItemProps>): ReactElement {
|
|
38
|
+
const { t } = useTranslation();
|
|
39
|
+
const dispatch = useDispatch();
|
|
40
|
+
const [dialogState, setDialogState] = useState<PropertyChangeDeletionDetails | undefined>(undefined);
|
|
41
|
+
|
|
42
|
+
const name = useMemo(() => {
|
|
43
|
+
const parts = fileName.split('_');
|
|
44
|
+
const changeName = parts[parts.length - 1];
|
|
45
|
+
return convertCamelCaseToPascalCase(changeName);
|
|
46
|
+
}, [fileName]);
|
|
47
|
+
|
|
48
|
+
const onConfirmDelete = (): void => {
|
|
49
|
+
if (dialogState) {
|
|
50
|
+
dispatch(deletePropertyChanges(dialogState));
|
|
51
|
+
setDialogState(undefined);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const onCancelDelete = (): void => {
|
|
56
|
+
setDialogState(undefined);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<Stack className={styles.item}>
|
|
62
|
+
<Stack.Item className={styles.property}>
|
|
63
|
+
<Stack horizontal>
|
|
64
|
+
<Stack.Item>
|
|
65
|
+
<Link
|
|
66
|
+
className={styles.textHeader}
|
|
67
|
+
onClick={(): void => {
|
|
68
|
+
const action = selectControl(controlId);
|
|
69
|
+
dispatch(action);
|
|
70
|
+
}}
|
|
71
|
+
style={{
|
|
72
|
+
color: 'var(--vscode-textLink-foreground)',
|
|
73
|
+
fontSize: '13px',
|
|
74
|
+
fontWeight: 'bold',
|
|
75
|
+
textOverflow: 'ellipsis',
|
|
76
|
+
whiteSpace: 'nowrap',
|
|
77
|
+
overflowX: 'hidden',
|
|
78
|
+
lineHeight: '18px'
|
|
79
|
+
}}>
|
|
80
|
+
{name} {t('CHANGE')}
|
|
81
|
+
</Link>
|
|
82
|
+
|
|
83
|
+
<Stack horizontal>
|
|
84
|
+
<Stack.Item className={styles.fileLabel}>{t('FILE')}</Stack.Item>
|
|
85
|
+
<Stack.Item className={styles.fileText} title={fileName}>
|
|
86
|
+
{fileName}
|
|
87
|
+
</Stack.Item>
|
|
88
|
+
</Stack>
|
|
89
|
+
{controlId && (
|
|
90
|
+
<Stack horizontal>
|
|
91
|
+
<Stack.Item className={styles.controlLabel}>{t('CONTROL')}</Stack.Item>
|
|
92
|
+
<Stack.Item className={styles.controlText} title={controlId}>
|
|
93
|
+
{controlId}
|
|
94
|
+
</Stack.Item>
|
|
95
|
+
</Stack>
|
|
96
|
+
)}
|
|
97
|
+
</Stack.Item>
|
|
98
|
+
|
|
99
|
+
{type === SAVED_CHANGE_TYPE && (
|
|
100
|
+
<Stack.Item className={styles.actions}>
|
|
101
|
+
<UIIconButton
|
|
102
|
+
iconProps={{ iconName: UiIcons.TrashCan }}
|
|
103
|
+
onClick={(): void => {
|
|
104
|
+
setDialogState({
|
|
105
|
+
controlId: '',
|
|
106
|
+
propertyName: '',
|
|
107
|
+
fileName
|
|
108
|
+
});
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
</Stack.Item>
|
|
112
|
+
)}
|
|
113
|
+
</Stack>
|
|
114
|
+
</Stack.Item>
|
|
115
|
+
{timestamp && (
|
|
116
|
+
<Stack.Item>
|
|
117
|
+
<Stack horizontal horizontalAlign="space-between">
|
|
118
|
+
<Text className={styles.timestamp}>{getFormattedDateAndTime(timestamp ?? 0)}</Text>
|
|
119
|
+
</Stack>
|
|
120
|
+
</Stack.Item>
|
|
121
|
+
)}
|
|
122
|
+
</Stack>
|
|
123
|
+
|
|
124
|
+
{dialogState && (
|
|
125
|
+
<UIDialog
|
|
126
|
+
hidden={dialogState === undefined}
|
|
127
|
+
onAccept={onConfirmDelete}
|
|
128
|
+
acceptButtonText={t('CONFIRM_DELETE')}
|
|
129
|
+
cancelButtonText={t('CANCEL_DELETE')}
|
|
130
|
+
onCancel={onCancelDelete}
|
|
131
|
+
dialogContentProps={{
|
|
132
|
+
title: t('CONFIRM_OTHER_CHANGE_DELETE_TITLE'),
|
|
133
|
+
subText: t('CONFIRM_OTHER_CHANGE_DELETE_SUBTEXT', { name })
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { ReactElement } from 'react';
|
|
2
1
|
import React from 'react';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
3
|
import { Link, Stack } from '@fluentui/react';
|
|
4
4
|
|
|
5
|
-
import { useAppDispatch } from '../../store';
|
|
6
|
-
import type { Change } from '@sap-ux-private/control-property-editor-common';
|
|
7
5
|
import { PROPERTY_CHANGE_KIND, SAVED_CHANGE_TYPE, selectControl } from '@sap-ux-private/control-property-editor-common';
|
|
6
|
+
import type { Change } from '@sap-ux-private/control-property-editor-common';
|
|
8
7
|
|
|
9
8
|
import { PropertyChange } from './PropertyChange';
|
|
10
|
-
import {
|
|
9
|
+
import { useAppDispatch } from '../../store';
|
|
11
10
|
|
|
12
11
|
import styles from './ControlGroup.module.scss';
|
|
13
12
|
|
|
@@ -17,6 +16,7 @@ export interface ControlGroupProps {
|
|
|
17
16
|
controlName: string;
|
|
18
17
|
index: number;
|
|
19
18
|
changes: Change[];
|
|
19
|
+
timestamp?: number;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -59,9 +59,7 @@ export function ControlGroup(controlGroupProps: ControlGroupProps): ReactElement
|
|
|
59
59
|
className={styles.item}>
|
|
60
60
|
{change.kind === PROPERTY_CHANGE_KIND ? (
|
|
61
61
|
<PropertyChange change={change} actionClassName={styles.actions} />
|
|
62
|
-
) :
|
|
63
|
-
<OtherChange change={change} actionClassName={styles.actions} />
|
|
64
|
-
)}
|
|
62
|
+
) : null}
|
|
65
63
|
</Stack.Item>
|
|
66
64
|
);
|
|
67
65
|
})}
|
package/src/slice.ts
CHANGED
|
@@ -35,7 +35,8 @@ import {
|
|
|
35
35
|
applicationModeChanged,
|
|
36
36
|
UNKNOWN_CHANGE_KIND,
|
|
37
37
|
SAVED_CHANGE_TYPE,
|
|
38
|
-
PENDING_CHANGE_TYPE
|
|
38
|
+
PENDING_CHANGE_TYPE,
|
|
39
|
+
PROPERTY_CHANGE_KIND
|
|
39
40
|
} from '@sap-ux-private/control-property-editor-common';
|
|
40
41
|
import { DeviceType } from './devices';
|
|
41
42
|
|
|
@@ -158,6 +159,53 @@ export const initialState: SliceState = {
|
|
|
158
159
|
quickActions: []
|
|
159
160
|
};
|
|
160
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Process a control and update the control stats.
|
|
164
|
+
*
|
|
165
|
+
* @param control The control to update
|
|
166
|
+
* @param changeType The type of change
|
|
167
|
+
*/
|
|
168
|
+
const processControl = (control: ControlChangeStats, changeType: string): void => {
|
|
169
|
+
if (changeType === PENDING_CHANGE_TYPE) {
|
|
170
|
+
control.pending++;
|
|
171
|
+
} else if (changeType === SAVED_CHANGE_TYPE) {
|
|
172
|
+
control.saved++;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Process a property change and update the property stats.
|
|
178
|
+
*
|
|
179
|
+
* @param control The control to update
|
|
180
|
+
* @param change The change to process
|
|
181
|
+
*/
|
|
182
|
+
const processPropertyChange = (
|
|
183
|
+
control: ControlChangeStats,
|
|
184
|
+
change: PendingPropertyChange | SavedPropertyChange
|
|
185
|
+
): void => {
|
|
186
|
+
const { propertyName } = change;
|
|
187
|
+
|
|
188
|
+
const property = control.properties[propertyName]
|
|
189
|
+
? {
|
|
190
|
+
pending: control.properties[propertyName].pending,
|
|
191
|
+
saved: control.properties[propertyName].saved,
|
|
192
|
+
lastSavedChange: control.properties[propertyName].lastSavedChange,
|
|
193
|
+
lastChange: control.properties[propertyName].lastChange
|
|
194
|
+
}
|
|
195
|
+
: {
|
|
196
|
+
pending: 0,
|
|
197
|
+
saved: 0
|
|
198
|
+
};
|
|
199
|
+
if (change.type === PENDING_CHANGE_TYPE) {
|
|
200
|
+
property.pending++;
|
|
201
|
+
property.lastChange = change;
|
|
202
|
+
} else if (change.type === SAVED_CHANGE_TYPE) {
|
|
203
|
+
property.lastSavedChange = change;
|
|
204
|
+
property.saved++;
|
|
205
|
+
}
|
|
206
|
+
control.properties[propertyName] = property;
|
|
207
|
+
};
|
|
208
|
+
|
|
161
209
|
const slice = createSlice<SliceState, SliceCaseReducers<SliceState>, string>({
|
|
162
210
|
name: 'app',
|
|
163
211
|
initialState,
|
|
@@ -238,7 +286,7 @@ const slice = createSlice<SliceState, SliceCaseReducers<SliceState>, string>({
|
|
|
238
286
|
if (change.kind === UNKNOWN_CHANGE_KIND) {
|
|
239
287
|
continue;
|
|
240
288
|
}
|
|
241
|
-
const { controlId,
|
|
289
|
+
const { controlId, type } = change;
|
|
242
290
|
const key = `${controlId}`;
|
|
243
291
|
const control = state.changes.controls[key]
|
|
244
292
|
? {
|
|
@@ -250,33 +298,14 @@ const slice = createSlice<SliceState, SliceCaseReducers<SliceState>, string>({
|
|
|
250
298
|
: {
|
|
251
299
|
pending: 0,
|
|
252
300
|
saved: 0,
|
|
253
|
-
controlName: controlName
|
|
301
|
+
controlName: change.kind === PROPERTY_CHANGE_KIND ? change.controlName : '',
|
|
254
302
|
properties: {}
|
|
255
303
|
};
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
control.saved++;
|
|
260
|
-
}
|
|
261
|
-
const property = control.properties[propertyName]
|
|
262
|
-
? {
|
|
263
|
-
pending: control.properties[propertyName].pending,
|
|
264
|
-
saved: control.properties[propertyName].saved,
|
|
265
|
-
lastSavedChange: control.properties[propertyName].lastSavedChange,
|
|
266
|
-
lastChange: control.properties[propertyName].lastChange
|
|
267
|
-
}
|
|
268
|
-
: {
|
|
269
|
-
pending: 0,
|
|
270
|
-
saved: 0
|
|
271
|
-
};
|
|
272
|
-
if (change.type === PENDING_CHANGE_TYPE) {
|
|
273
|
-
property.pending++;
|
|
274
|
-
property.lastChange = change;
|
|
275
|
-
} else if (change.type === SAVED_CHANGE_TYPE) {
|
|
276
|
-
property.lastSavedChange = change;
|
|
277
|
-
property.saved++;
|
|
304
|
+
processControl(control, type);
|
|
305
|
+
if (change.kind === PROPERTY_CHANGE_KIND) {
|
|
306
|
+
processPropertyChange(control, change);
|
|
278
307
|
}
|
|
279
|
-
|
|
308
|
+
|
|
280
309
|
state.changes.controls[key] = control;
|
|
281
310
|
}
|
|
282
311
|
})
|