@etsoo/react 1.3.99 → 1.4.3
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/lib/mu/DnDList.d.ts +5 -1
- package/lib/mu/DnDList.js +29 -7
- package/lib/mu/NotifierMU.js +20 -6
- package/lib/mu/pages/EditPage.js +2 -2
- package/package.json +9 -9
- package/src/mu/DnDList.tsx +43 -7
- package/src/mu/NotifierMU.tsx +33 -6
- package/src/mu/pages/EditPage.tsx +2 -2
package/lib/mu/DnDList.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
6
6
|
/**
|
|
7
7
|
* Item renderer
|
|
8
8
|
*/
|
|
9
|
-
children: (item: D, index: number, deleteItem: (index: number) => void) => React.ReactNode;
|
|
9
|
+
children: (item: D, index: number, deleteItem: (index: number) => void, editItem: (newItem: D, index: number) => boolean) => React.ReactNode;
|
|
10
10
|
/**
|
|
11
11
|
* List container component
|
|
12
12
|
* https://javascript.plainenglish.io/building-a-polymorphic-component-in-react-and-typescript-d9f236950af4
|
|
@@ -32,6 +32,10 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
32
32
|
* Load data
|
|
33
33
|
*/
|
|
34
34
|
loadData: (name: string) => PromiseLike<D[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Data change handler
|
|
37
|
+
*/
|
|
38
|
+
onChange?: (items: D[]) => void;
|
|
35
39
|
/**
|
|
36
40
|
* Top and bottom sides renderer
|
|
37
41
|
*/
|
package/lib/mu/DnDList.js
CHANGED
|
@@ -9,9 +9,16 @@ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
|
|
9
9
|
*/
|
|
10
10
|
export function DnDList(props) {
|
|
11
11
|
// Destruct
|
|
12
|
-
const { children, Component = 'div', componentProps, getItemStyle = (_isDragging) => ({}), getListStyle = () => undefined, labelField, loadData, name, sideRenderer } = props;
|
|
12
|
+
const { children, Component = 'div', componentProps, getItemStyle = (_isDragging) => ({}), getListStyle = () => undefined, labelField, loadData, name, onChange, sideRenderer } = props;
|
|
13
13
|
// State
|
|
14
14
|
const [items, setItems] = React.useState([]);
|
|
15
|
+
const changeItems = (items) => {
|
|
16
|
+
// Possible to alter items with the handler
|
|
17
|
+
if (onChange)
|
|
18
|
+
onChange(items);
|
|
19
|
+
// Update state
|
|
20
|
+
setItems(items);
|
|
21
|
+
};
|
|
15
22
|
// Drag end handler
|
|
16
23
|
const onDragEnd = (result) => {
|
|
17
24
|
// Dropped outside the list
|
|
@@ -25,18 +32,32 @@ export function DnDList(props) {
|
|
|
25
32
|
// Insert to the destination index
|
|
26
33
|
newItems.splice(result.destination.index, 0, removed);
|
|
27
34
|
// Update the state
|
|
28
|
-
|
|
35
|
+
changeItems(newItems);
|
|
29
36
|
};
|
|
30
37
|
// Add item
|
|
31
38
|
const addItem = (newItem) => {
|
|
32
39
|
// Existence check
|
|
33
|
-
if (items.some((item) => item[labelField]
|
|
40
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
34
41
|
return false;
|
|
35
42
|
}
|
|
36
43
|
// Clone
|
|
37
44
|
const newItems = [newItem, ...items];
|
|
38
45
|
// Update the state
|
|
39
|
-
|
|
46
|
+
changeItems(newItems);
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
// Edit item
|
|
50
|
+
const editItem = (newItem, index) => {
|
|
51
|
+
// Existence check
|
|
52
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
// Clone
|
|
56
|
+
const newItems = [...items];
|
|
57
|
+
// Remove the item
|
|
58
|
+
newItems.splice(index, 1, newItem);
|
|
59
|
+
// Update the state
|
|
60
|
+
changeItems(newItems);
|
|
40
61
|
return true;
|
|
41
62
|
};
|
|
42
63
|
// Add items
|
|
@@ -52,7 +73,7 @@ export function DnDList(props) {
|
|
|
52
73
|
newItems.push(newItem);
|
|
53
74
|
});
|
|
54
75
|
// Update the state
|
|
55
|
-
|
|
76
|
+
changeItems(newItems);
|
|
56
77
|
return newItems.length - items.length;
|
|
57
78
|
};
|
|
58
79
|
// Delete item
|
|
@@ -62,9 +83,10 @@ export function DnDList(props) {
|
|
|
62
83
|
// Remove the item
|
|
63
84
|
newItems.splice(index, 1);
|
|
64
85
|
// Update the state
|
|
65
|
-
|
|
86
|
+
changeItems(newItems);
|
|
66
87
|
};
|
|
67
88
|
React.useEffect(() => {
|
|
89
|
+
// Load data
|
|
68
90
|
loadData(name).then((items) => setItems(items));
|
|
69
91
|
}, [name]);
|
|
70
92
|
// Layout
|
|
@@ -83,7 +105,7 @@ export function DnDList(props) {
|
|
|
83
105
|
...provided
|
|
84
106
|
.draggableProps
|
|
85
107
|
.style
|
|
86
|
-
} }, children(item, index, deleteItem)))));
|
|
108
|
+
} }, children(item, index, deleteItem, editItem)))));
|
|
87
109
|
}),
|
|
88
110
|
provided.placeholder))))),
|
|
89
111
|
sideRenderer && sideRenderer(false, addItem, addItems)));
|
package/lib/mu/NotifierMU.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NotificationAlign, NotificationMessageType, NotificationType } from '@etsoo/notificationbase';
|
|
2
|
-
import { Alert, AlertTitle, Backdrop, Box, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Fade, Slider, Snackbar, styled, Switch, TextField } from '@mui/material';
|
|
2
|
+
import { Alert, AlertTitle, Backdrop, Box, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Fade, Slider, Snackbar, styled, Switch, TextField, Typography } from '@mui/material';
|
|
3
3
|
import { Error, Info, Help, Warning, Done } from '@mui/icons-material';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { Labels } from '../app/Labels';
|
|
@@ -120,14 +120,21 @@ export class NotificationMU extends NotificationReact {
|
|
|
120
120
|
const labels = Labels.NotificationMU;
|
|
121
121
|
const title = (_a = this.title) !== null && _a !== void 0 ? _a : labels.promptTitle;
|
|
122
122
|
const { cancelLabel = labels.promptCancel, okLabel = labels.promptOK, inputs, type, fullScreen, fullWidth = true, maxWidth, primaryButton, ...rest } = (_b = this.inputProps) !== null && _b !== void 0 ? _b : {};
|
|
123
|
+
const inputRef = React.createRef();
|
|
124
|
+
const errorRef = React.createRef();
|
|
125
|
+
const setError = (error) => {
|
|
126
|
+
if (errorRef.current == null)
|
|
127
|
+
return;
|
|
128
|
+
errorRef.current.innerText = error !== null && error !== void 0 ? error : '';
|
|
129
|
+
};
|
|
123
130
|
const handleSubmit = async (event) => {
|
|
124
131
|
// Result
|
|
125
132
|
let result = undefined;
|
|
133
|
+
const input = inputRef.current;
|
|
126
134
|
if (this.onReturn) {
|
|
127
135
|
// Inputs case, no HTMLForm set to value, set the current form
|
|
128
136
|
if (inputs && value == null)
|
|
129
137
|
value = event.currentTarget.form;
|
|
130
|
-
const input = inputRef.current;
|
|
131
138
|
if (input) {
|
|
132
139
|
if (type === 'date') {
|
|
133
140
|
const dateValue = input.valueAsDate;
|
|
@@ -165,12 +172,18 @@ export class NotificationMU extends NotificationReact {
|
|
|
165
172
|
// Get the value
|
|
166
173
|
// returns false to prevent default dismiss
|
|
167
174
|
const v = await result;
|
|
168
|
-
if (v === false)
|
|
175
|
+
if (v === false) {
|
|
176
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
169
177
|
return;
|
|
178
|
+
}
|
|
179
|
+
if (typeof v === 'string') {
|
|
180
|
+
setError(v);
|
|
181
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
170
184
|
this.dismiss();
|
|
171
185
|
};
|
|
172
186
|
let localInputs;
|
|
173
|
-
let inputRef = React.createRef();
|
|
174
187
|
let value = undefined;
|
|
175
188
|
if (inputs == null) {
|
|
176
189
|
if (type === 'switch') {
|
|
@@ -180,7 +193,7 @@ export class NotificationMU extends NotificationReact {
|
|
|
180
193
|
localInputs = React.createElement(Slider, { onChange: (_e, v) => (value = v) });
|
|
181
194
|
}
|
|
182
195
|
else {
|
|
183
|
-
localInputs = (React.createElement(TextField, { inputRef: inputRef, autoFocus: true, margin: "dense", fullWidth: true, type: type, required: true, ...rest }));
|
|
196
|
+
localInputs = (React.createElement(TextField, { inputRef: inputRef, onChange: () => setError(undefined), autoFocus: true, margin: "dense", fullWidth: true, type: type, required: true, ...rest }));
|
|
184
197
|
}
|
|
185
198
|
}
|
|
186
199
|
else {
|
|
@@ -193,7 +206,8 @@ export class NotificationMU extends NotificationReact {
|
|
|
193
206
|
React.createElement("span", { className: "dialogTitle" }, title)),
|
|
194
207
|
React.createElement(DialogContent, null,
|
|
195
208
|
React.createElement(DialogContentText, null, this.content),
|
|
196
|
-
localInputs
|
|
209
|
+
localInputs,
|
|
210
|
+
React.createElement(Typography, { variant: "caption", display: "block", ref: errorRef, color: (theme) => theme.palette.error.main })),
|
|
197
211
|
React.createElement(DialogActions, null,
|
|
198
212
|
React.createElement(Button, { color: "secondary", onClick: () => {
|
|
199
213
|
if (this.onReturn)
|
package/lib/mu/pages/EditPage.js
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { Labels } from '../../app/Labels';
|
|
4
4
|
import { MUGlobal } from '../MUGlobal';
|
|
5
5
|
import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
6
|
-
import
|
|
6
|
+
import SaveIcon from '@mui/icons-material/Save';
|
|
7
7
|
/**
|
|
8
8
|
* Edit page
|
|
9
9
|
* @param props Props
|
|
@@ -21,5 +21,5 @@ export function EditPage(props) {
|
|
|
21
21
|
bottom: (theme) => MUGlobal.updateWithTheme(paddings, theme.spacing),
|
|
22
22
|
paddingTop: paddings
|
|
23
23
|
} },
|
|
24
|
-
React.createElement(Button, { variant: "contained", type: "submit", fullWidth: true, startIcon: React.createElement(
|
|
24
|
+
React.createElement(Button, { variant: "contained", type: "submit", fullWidth: true, startIcon: React.createElement(SaveIcon, null) }, labels.save)))));
|
|
25
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.3
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"@emotion/react": "^11.7.1",
|
|
51
51
|
"@emotion/style": "^0.8.0",
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
|
-
"@etsoo/appscript": "^1.2.
|
|
54
|
-
"@etsoo/notificationbase": "^1.0
|
|
53
|
+
"@etsoo/appscript": "^1.2.15",
|
|
54
|
+
"@etsoo/notificationbase": "^1.1.0",
|
|
55
55
|
"@etsoo/shared": "^1.0.97",
|
|
56
56
|
"@mui/icons-material": "^5.2.5",
|
|
57
57
|
"@mui/material": "^5.2.6",
|
|
@@ -76,12 +76,12 @@
|
|
|
76
76
|
"react-window": "^1.8.6"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@babel/cli": "^7.16.
|
|
80
|
-
"@babel/core": "^7.16.
|
|
81
|
-
"@babel/plugin-transform-runtime": "^7.16.
|
|
82
|
-
"@babel/preset-env": "^7.16.
|
|
83
|
-
"@babel/runtime-corejs3": "^7.16.
|
|
84
|
-
"@types/jest": "^27.0
|
|
79
|
+
"@babel/cli": "^7.16.7",
|
|
80
|
+
"@babel/core": "^7.16.7",
|
|
81
|
+
"@babel/plugin-transform-runtime": "^7.16.7",
|
|
82
|
+
"@babel/preset-env": "^7.16.7",
|
|
83
|
+
"@babel/runtime-corejs3": "^7.16.7",
|
|
84
|
+
"@types/jest": "^27.4.0",
|
|
85
85
|
"@types/react-test-renderer": "^17.0.1",
|
|
86
86
|
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
|
87
87
|
"@typescript-eslint/parser": "^5.8.1",
|
package/src/mu/DnDList.tsx
CHANGED
|
@@ -17,7 +17,8 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
17
17
|
children: (
|
|
18
18
|
item: D,
|
|
19
19
|
index: number,
|
|
20
|
-
deleteItem: (index: number) => void
|
|
20
|
+
deleteItem: (index: number) => void,
|
|
21
|
+
editItem: (newItem: D, index: number) => boolean
|
|
21
22
|
) => React.ReactNode;
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -51,6 +52,11 @@ export interface DnDListProps<D extends {}, E extends React.ElementType> {
|
|
|
51
52
|
*/
|
|
52
53
|
loadData: (name: string) => PromiseLike<D[]>;
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Data change handler
|
|
57
|
+
*/
|
|
58
|
+
onChange?: (items: D[]) => void;
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* Top and bottom sides renderer
|
|
56
62
|
*/
|
|
@@ -86,12 +92,21 @@ export function DnDList<
|
|
|
86
92
|
labelField,
|
|
87
93
|
loadData,
|
|
88
94
|
name,
|
|
95
|
+
onChange,
|
|
89
96
|
sideRenderer
|
|
90
97
|
} = props;
|
|
91
98
|
|
|
92
99
|
// State
|
|
93
100
|
const [items, setItems] = React.useState<D[]>([]);
|
|
94
101
|
|
|
102
|
+
const changeItems = (items: D[]) => {
|
|
103
|
+
// Possible to alter items with the handler
|
|
104
|
+
if (onChange) onChange(items);
|
|
105
|
+
|
|
106
|
+
// Update state
|
|
107
|
+
setItems(items);
|
|
108
|
+
};
|
|
109
|
+
|
|
95
110
|
// Drag end handler
|
|
96
111
|
const onDragEnd = (result: DropResult) => {
|
|
97
112
|
// Dropped outside the list
|
|
@@ -109,13 +124,13 @@ export function DnDList<
|
|
|
109
124
|
newItems.splice(result.destination.index, 0, removed);
|
|
110
125
|
|
|
111
126
|
// Update the state
|
|
112
|
-
|
|
127
|
+
changeItems(newItems);
|
|
113
128
|
};
|
|
114
129
|
|
|
115
130
|
// Add item
|
|
116
131
|
const addItem = (newItem: D) => {
|
|
117
132
|
// Existence check
|
|
118
|
-
if (items.some((item) => item[labelField]
|
|
133
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
119
134
|
return false;
|
|
120
135
|
}
|
|
121
136
|
|
|
@@ -123,7 +138,26 @@ export function DnDList<
|
|
|
123
138
|
const newItems = [newItem, ...items];
|
|
124
139
|
|
|
125
140
|
// Update the state
|
|
126
|
-
|
|
141
|
+
changeItems(newItems);
|
|
142
|
+
|
|
143
|
+
return true;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Edit item
|
|
147
|
+
const editItem = (newItem: D, index: number) => {
|
|
148
|
+
// Existence check
|
|
149
|
+
if (items.some((item) => item[labelField] === newItem[labelField])) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Clone
|
|
154
|
+
const newItems = [...items];
|
|
155
|
+
|
|
156
|
+
// Remove the item
|
|
157
|
+
newItems.splice(index, 1, newItem);
|
|
158
|
+
|
|
159
|
+
// Update the state
|
|
160
|
+
changeItems(newItems);
|
|
127
161
|
|
|
128
162
|
return true;
|
|
129
163
|
};
|
|
@@ -146,7 +180,7 @@ export function DnDList<
|
|
|
146
180
|
});
|
|
147
181
|
|
|
148
182
|
// Update the state
|
|
149
|
-
|
|
183
|
+
changeItems(newItems);
|
|
150
184
|
|
|
151
185
|
return newItems.length - items.length;
|
|
152
186
|
};
|
|
@@ -160,10 +194,11 @@ export function DnDList<
|
|
|
160
194
|
newItems.splice(index, 1);
|
|
161
195
|
|
|
162
196
|
// Update the state
|
|
163
|
-
|
|
197
|
+
changeItems(newItems);
|
|
164
198
|
};
|
|
165
199
|
|
|
166
200
|
React.useEffect(() => {
|
|
201
|
+
// Load data
|
|
167
202
|
loadData(name).then((items) => setItems(items));
|
|
168
203
|
}, [name]);
|
|
169
204
|
|
|
@@ -212,7 +247,8 @@ export function DnDList<
|
|
|
212
247
|
{children(
|
|
213
248
|
item,
|
|
214
249
|
index,
|
|
215
|
-
deleteItem
|
|
250
|
+
deleteItem,
|
|
251
|
+
editItem
|
|
216
252
|
)}
|
|
217
253
|
</div>
|
|
218
254
|
)}
|
package/src/mu/NotifierMU.tsx
CHANGED
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
Snackbar,
|
|
26
26
|
styled,
|
|
27
27
|
Switch,
|
|
28
|
-
TextField
|
|
28
|
+
TextField,
|
|
29
|
+
Typography
|
|
29
30
|
} from '@mui/material';
|
|
30
31
|
import { Error, Info, Help, Warning, Done } from '@mui/icons-material';
|
|
31
32
|
import React from 'react';
|
|
@@ -238,18 +239,30 @@ export class NotificationMU extends NotificationReact {
|
|
|
238
239
|
...rest
|
|
239
240
|
} = this.inputProps ?? {};
|
|
240
241
|
|
|
242
|
+
const inputRef = React.createRef<HTMLInputElement>();
|
|
243
|
+
const errorRef = React.createRef<HTMLSpanElement>();
|
|
244
|
+
|
|
245
|
+
const setError = (error?: string) => {
|
|
246
|
+
if (errorRef.current == null) return;
|
|
247
|
+
errorRef.current.innerText = error ?? '';
|
|
248
|
+
};
|
|
249
|
+
|
|
241
250
|
const handleSubmit = async (
|
|
242
251
|
event: React.MouseEvent<HTMLButtonElement>
|
|
243
252
|
) => {
|
|
244
253
|
// Result
|
|
245
|
-
let result:
|
|
246
|
-
|
|
254
|
+
let result:
|
|
255
|
+
| boolean
|
|
256
|
+
| string
|
|
257
|
+
| void
|
|
258
|
+
| PromiseLike<boolean | string | void> = undefined;
|
|
259
|
+
|
|
260
|
+
const input = inputRef.current;
|
|
247
261
|
|
|
248
262
|
if (this.onReturn) {
|
|
249
263
|
// Inputs case, no HTMLForm set to value, set the current form
|
|
250
264
|
if (inputs && value == null) value = event.currentTarget.form;
|
|
251
265
|
|
|
252
|
-
const input = inputRef.current;
|
|
253
266
|
if (input) {
|
|
254
267
|
if (type === 'date') {
|
|
255
268
|
const dateValue = input.valueAsDate;
|
|
@@ -284,13 +297,20 @@ export class NotificationMU extends NotificationReact {
|
|
|
284
297
|
// Get the value
|
|
285
298
|
// returns false to prevent default dismiss
|
|
286
299
|
const v = await result;
|
|
287
|
-
if (v === false)
|
|
300
|
+
if (v === false) {
|
|
301
|
+
input?.focus();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (typeof v === 'string') {
|
|
305
|
+
setError(v);
|
|
306
|
+
input?.focus();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
288
309
|
|
|
289
310
|
this.dismiss();
|
|
290
311
|
};
|
|
291
312
|
|
|
292
313
|
let localInputs: React.ReactNode;
|
|
293
|
-
let inputRef = React.createRef<HTMLInputElement>();
|
|
294
314
|
let value: any = undefined;
|
|
295
315
|
|
|
296
316
|
if (inputs == null) {
|
|
@@ -310,6 +330,7 @@ export class NotificationMU extends NotificationReact {
|
|
|
310
330
|
localInputs = (
|
|
311
331
|
<TextField
|
|
312
332
|
inputRef={inputRef}
|
|
333
|
+
onChange={() => setError(undefined)}
|
|
313
334
|
autoFocus
|
|
314
335
|
margin="dense"
|
|
315
336
|
fullWidth
|
|
@@ -341,6 +362,12 @@ export class NotificationMU extends NotificationReact {
|
|
|
341
362
|
<DialogContent>
|
|
342
363
|
<DialogContentText>{this.content}</DialogContentText>
|
|
343
364
|
{localInputs}
|
|
365
|
+
<Typography
|
|
366
|
+
variant="caption"
|
|
367
|
+
display="block"
|
|
368
|
+
ref={errorRef}
|
|
369
|
+
color={(theme) => theme.palette.error.main}
|
|
370
|
+
/>
|
|
344
371
|
</DialogContent>
|
|
345
372
|
<DialogActions>
|
|
346
373
|
<Button
|
|
@@ -6,7 +6,7 @@ import { Labels } from '../../app/Labels';
|
|
|
6
6
|
import { MUGlobal } from '../MUGlobal';
|
|
7
7
|
import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
8
8
|
import { CommonPageProps } from './CommonPageProps';
|
|
9
|
-
import
|
|
9
|
+
import SaveIcon from '@mui/icons-material/Save';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Edit page router props, include 'id' (/:id) query parameter
|
|
@@ -70,7 +70,7 @@ export function EditPage(props: EditPageProps) {
|
|
|
70
70
|
variant="contained"
|
|
71
71
|
type="submit"
|
|
72
72
|
fullWidth
|
|
73
|
-
startIcon={<
|
|
73
|
+
startIcon={<SaveIcon />}
|
|
74
74
|
>
|
|
75
75
|
{labels.save}
|
|
76
76
|
</Button>
|