@panneau/app 1.0.1-alpha.0 → 1.0.3-alpha.2
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/assets/css/styles.css +7 -0
- package/es/index.js +1810 -5
- package/lib/index.js +1841 -15
- package/package.json +66 -54
- package/scss/styles.scss +3 -0
- package/es/Panneau.js +0 -318
- package/es/actions/AuthActions.js +0 -16
- package/es/actions/LayoutActions.js +0 -14
- package/es/components/App.js +0 -129
- package/es/components/Layout.js +0 -68
- package/es/components/Panneau.js +0 -79
- package/es/components/index.js +0 -3
- package/es/components/pages/Account.js +0 -38
- package/es/components/pages/Home.js +0 -12
- package/es/components/pages/ResourceCreate.js +0 -44
- package/es/components/pages/ResourceDelete.js +0 -11
- package/es/components/pages/ResourceEdit.js +0 -28
- package/es/components/pages/ResourceForm.js +0 -343
- package/es/components/pages/ResourceIndex.js +0 -261
- package/es/components/pages/ResourceShow.js +0 -15
- package/es/components/partials/ResourceFormHeader.js +0 -111
- package/es/components/partials/ResourceIndexHeader.js +0 -71
- package/es/defaults/routes.json +0 -10
- package/es/lib/createStore.js +0 -30
- package/es/reducers/AuthReducer.js +0 -32
- package/es/reducers/index.js +0 -4
- package/lib/Panneau.js +0 -340
- package/lib/actions/AuthActions.js +0 -25
- package/lib/actions/LayoutActions.js +0 -25
- package/lib/components/App.js +0 -159
- package/lib/components/Layout.js +0 -87
- package/lib/components/Panneau.js +0 -103
- package/lib/components/index.js +0 -23
- package/lib/components/pages/Account.js +0 -54
- package/lib/components/pages/Home.js +0 -23
- package/lib/components/pages/ResourceCreate.js +0 -65
- package/lib/components/pages/ResourceDelete.js +0 -22
- package/lib/components/pages/ResourceEdit.js +0 -44
- package/lib/components/pages/ResourceForm.js +0 -376
- package/lib/components/pages/ResourceIndex.js +0 -289
- package/lib/components/pages/ResourceShow.js +0 -28
- package/lib/components/partials/ResourceFormHeader.js +0 -137
- package/lib/components/partials/ResourceIndexHeader.js +0 -87
- package/lib/defaults/routes.json +0 -10
- package/lib/lib/createStore.js +0 -46
- package/lib/reducers/AuthReducer.js +0 -43
- package/lib/reducers/index.js +0 -15
- package/src/Panneau.js +0 -274
- package/src/actions/AuthActions.js +0 -17
- package/src/actions/LayoutActions.js +0 -12
- package/src/components/App.jsx +0 -121
- package/src/components/Layout.jsx +0 -51
- package/src/components/Panneau.jsx +0 -95
- package/src/components/index.js +0 -7
- package/src/components/pages/Account.jsx +0 -34
- package/src/components/pages/Home.jsx +0 -19
- package/src/components/pages/ResourceCreate.jsx +0 -50
- package/src/components/pages/ResourceDelete.jsx +0 -18
- package/src/components/pages/ResourceEdit.jsx +0 -39
- package/src/components/pages/ResourceForm.jsx +0 -361
- package/src/components/pages/ResourceIndex.jsx +0 -256
- package/src/components/pages/ResourceShow.jsx +0 -23
- package/src/components/partials/ResourceFormHeader.jsx +0 -137
- package/src/components/partials/ResourceIndexHeader.jsx +0 -84
- package/src/defaults/routes.json +0 -10
- package/src/index.js +0 -9
- package/src/lib/createStore.js +0 -21
- package/src/reducers/AuthReducer.js +0 -23
- package/src/reducers/index.js +0 -5
- package/src/styles/layout.scss +0 -5
- package/src/styles/pages/resource-form.scss +0 -42
- package/src/styles/pages/resource-index.scss +0 -43
- package/src/styles/partials/resource-form-header.scss +0 -7
- package/src/styles/partials/resource-index-header.scss +0 -13
- package/src/styles/vendor.global.scss +0 -5
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/jsx-props-no-spreading */
|
|
2
|
-
import React, { useCallback, useState, useEffect, useMemo } from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import isObject from 'lodash/isObject';
|
|
5
|
-
import classNames from 'classnames';
|
|
6
|
-
import { defineMessages } from 'react-intl';
|
|
7
|
-
import { PropTypes as PanneauPropTypes, useResourceApi } from '@panneau/core';
|
|
8
|
-
import { getErrorsFromResponseError } from '@panneau/core/requests';
|
|
9
|
-
import { Loading, Errors } from '@panneau/core/components';
|
|
10
|
-
import { useComponent } from '@panneau/core/contexts';
|
|
11
|
-
|
|
12
|
-
import ResourceFormHeader from '../partials/ResourceFormHeader';
|
|
13
|
-
|
|
14
|
-
import styles from '../../styles/pages/resource-form.scss';
|
|
15
|
-
|
|
16
|
-
export const messages = defineMessages({
|
|
17
|
-
cancel: {
|
|
18
|
-
id: 'app.buttons.resources.cancel',
|
|
19
|
-
description: 'The label of the "cancel" button',
|
|
20
|
-
defaultMessage: 'Cancel',
|
|
21
|
-
},
|
|
22
|
-
save: {
|
|
23
|
-
id: 'app.buttons.resources.save',
|
|
24
|
-
description: 'The label of the "save" button',
|
|
25
|
-
defaultMessage: 'Save',
|
|
26
|
-
},
|
|
27
|
-
title: {
|
|
28
|
-
id: 'app.titles.resources.default',
|
|
29
|
-
description: 'The title of the resource form',
|
|
30
|
-
defaultMessage: '{name}',
|
|
31
|
-
},
|
|
32
|
-
titleTyped: {
|
|
33
|
-
id: 'app.titles.resources.typed',
|
|
34
|
-
description: 'The title of the typed resource form',
|
|
35
|
-
defaultMessage: '{name} <small class="text-muted">({type})</small>',
|
|
36
|
-
},
|
|
37
|
-
successNotice: {
|
|
38
|
-
id: 'app.notices.resources.success',
|
|
39
|
-
description: 'The text of the "success" form notice',
|
|
40
|
-
defaultMessage: 'Success!',
|
|
41
|
-
},
|
|
42
|
-
errorNotice: {
|
|
43
|
-
id: 'app.notices.resources.error',
|
|
44
|
-
description: 'The text of the "error" form notice',
|
|
45
|
-
defaultMessage: 'Failed. The form contains errors.',
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const propTypes = {
|
|
50
|
-
action: PropTypes.string,
|
|
51
|
-
resource: PanneauPropTypes.resource.isRequired,
|
|
52
|
-
resourceApi: PanneauPropTypes.resourceApi.isRequired,
|
|
53
|
-
itemId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
54
|
-
item: PropTypes.shape({
|
|
55
|
-
id: PropTypes.number,
|
|
56
|
-
type: PropTypes.string,
|
|
57
|
-
}),
|
|
58
|
-
query: PropTypes.shape({
|
|
59
|
-
type: PropTypes.string,
|
|
60
|
-
}),
|
|
61
|
-
successNoticeLabel: PanneauPropTypes.label,
|
|
62
|
-
errorNoticeLabel: PanneauPropTypes.label,
|
|
63
|
-
buttons: PanneauPropTypes.buttons,
|
|
64
|
-
saveButtonLabel: PanneauPropTypes.message,
|
|
65
|
-
confirmSwitchTypeMessage: PanneauPropTypes.message,
|
|
66
|
-
errors: PropTypes.arrayOf(PropTypes.string),
|
|
67
|
-
formValue: PropTypes.shape({}),
|
|
68
|
-
formErrors: PropTypes.objectOf(PropTypes.array),
|
|
69
|
-
readOnly: PropTypes.bool,
|
|
70
|
-
title: PanneauPropTypes.label,
|
|
71
|
-
titleTyped: PanneauPropTypes.label,
|
|
72
|
-
gotoResourceAction: PropTypes.func.isRequired,
|
|
73
|
-
onFormComplete: PropTypes.func,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const defaultProps = {
|
|
77
|
-
action: 'create',
|
|
78
|
-
title: messages.title,
|
|
79
|
-
titleTyped: messages.titleTyped,
|
|
80
|
-
query: null,
|
|
81
|
-
itemId: null,
|
|
82
|
-
item: null,
|
|
83
|
-
errors: null,
|
|
84
|
-
formValue: null,
|
|
85
|
-
formErrors: null,
|
|
86
|
-
readOnly: false,
|
|
87
|
-
successNoticeLabel: messages.successNotice,
|
|
88
|
-
errorNoticeLabel: messages.errorNotice,
|
|
89
|
-
confirmSwitchTypeMessage: messages.confirmSwitchType,
|
|
90
|
-
buttons: [
|
|
91
|
-
{
|
|
92
|
-
id: 'cancel',
|
|
93
|
-
type: 'button',
|
|
94
|
-
label: messages.cancel,
|
|
95
|
-
className: 'btn-link btn-lg',
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
id: 'submit',
|
|
99
|
-
type: 'submit',
|
|
100
|
-
label: messages.save,
|
|
101
|
-
className: 'btn-primary btn-lg',
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
saveButtonLabel: null,
|
|
105
|
-
onFormComplete: null,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const ResourceForm = ({
|
|
109
|
-
resource,
|
|
110
|
-
item: currentItem,
|
|
111
|
-
itemId,
|
|
112
|
-
query,
|
|
113
|
-
action,
|
|
114
|
-
readOnly,
|
|
115
|
-
errors: currentErrors,
|
|
116
|
-
formValue: initialFormValue,
|
|
117
|
-
formErrors: initialFormErrors,
|
|
118
|
-
title,
|
|
119
|
-
titleTyped,
|
|
120
|
-
buttons,
|
|
121
|
-
saveButtonLabel,
|
|
122
|
-
successNoticeLabel,
|
|
123
|
-
errorNoticeLabel,
|
|
124
|
-
onFormComplete: customOnFormComplete,
|
|
125
|
-
gotoResourceAction,
|
|
126
|
-
}) => {
|
|
127
|
-
const [item, setItem] = useState(currentItem);
|
|
128
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
129
|
-
const [errors, setErrors] = useState(currentErrors || item);
|
|
130
|
-
const [formValue, setFormValue] = useState(initialFormValue || item);
|
|
131
|
-
const [formErrors, setFormErrors] = useState(initialFormErrors || item);
|
|
132
|
-
const [formSuccess, setFormSuccess] = useState(initialFormErrors !== null ? false : null);
|
|
133
|
-
const resourceApi = useResourceApi(resource);
|
|
134
|
-
const isTyped = resource.type() === 'typed';
|
|
135
|
-
const waitingItem = action === 'edit' && item === null;
|
|
136
|
-
|
|
137
|
-
// Load item if needed
|
|
138
|
-
useEffect(() => {
|
|
139
|
-
if (isLoading) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const onItemLoaded = newItem => {
|
|
143
|
-
setItem(newItem);
|
|
144
|
-
};
|
|
145
|
-
const onItemLoadError = newErrors => {
|
|
146
|
-
setErrors(newErrors);
|
|
147
|
-
};
|
|
148
|
-
const itemChanged = item !== null && `${item.id}` !== `${itemId}`;
|
|
149
|
-
const itemShouldReload = item === null || itemChanged;
|
|
150
|
-
if ((action === 'edit' || action === 'show') && itemShouldReload) {
|
|
151
|
-
setIsLoading(true);
|
|
152
|
-
resourceApi
|
|
153
|
-
.show(itemId)
|
|
154
|
-
.then(onItemLoaded)
|
|
155
|
-
.catch(onItemLoadError)
|
|
156
|
-
.then(() => {
|
|
157
|
-
setIsLoading(false);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}, [action, item, itemId, isLoading]);
|
|
161
|
-
|
|
162
|
-
// Get current type
|
|
163
|
-
const currentType = useMemo(() => {
|
|
164
|
-
if (!isTyped || waitingItem) {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const types = resource.types();
|
|
169
|
-
const itemTypeId = item !== null ? item.type || null : null;
|
|
170
|
-
const { type: queryTypeId = null } = query || {};
|
|
171
|
-
const typeId = itemTypeId || queryTypeId;
|
|
172
|
-
const definedType = typeId !== null ? types.find(it => it.id === typeId) || null : null;
|
|
173
|
-
if (definedType !== null) {
|
|
174
|
-
return definedType;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return types.length > 0
|
|
178
|
-
? types.find(({ default: isDefault = false }) => isDefault) || types[0] || null
|
|
179
|
-
: null;
|
|
180
|
-
}, [item, query, resource]);
|
|
181
|
-
|
|
182
|
-
const onClickCancel = useCallback(
|
|
183
|
-
e => {
|
|
184
|
-
e.preventDefault();
|
|
185
|
-
gotoResourceAction('index');
|
|
186
|
-
},
|
|
187
|
-
[gotoResourceAction],
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
const formButtons = useMemo(
|
|
191
|
-
() =>
|
|
192
|
-
readOnly
|
|
193
|
-
? []
|
|
194
|
-
: buttons.map(button => {
|
|
195
|
-
if (button.id === 'save' && saveButtonLabel !== null) {
|
|
196
|
-
return {
|
|
197
|
-
...button,
|
|
198
|
-
label: saveButtonLabel,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
if (button.id === 'cancel' && typeof button.onClick === 'undefined') {
|
|
202
|
-
return {
|
|
203
|
-
...button,
|
|
204
|
-
onClick: onClickCancel,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
return button;
|
|
208
|
-
}),
|
|
209
|
-
[buttons, readOnly],
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
const submitForm = useCallback(() => {
|
|
213
|
-
const data = isTyped
|
|
214
|
-
? {
|
|
215
|
-
type: currentType !== null ? currentType.id : null,
|
|
216
|
-
...(formValue || item),
|
|
217
|
-
}
|
|
218
|
-
: formValue;
|
|
219
|
-
|
|
220
|
-
setFormSuccess(null);
|
|
221
|
-
|
|
222
|
-
return action === 'create'
|
|
223
|
-
? resourceApi.store(data)
|
|
224
|
-
: resourceApi.update(item.id, data || item);
|
|
225
|
-
}, [resourceApi, action, isTyped, currentType]);
|
|
226
|
-
|
|
227
|
-
const onFormChange = useCallback(value => {
|
|
228
|
-
setFormValue(value);
|
|
229
|
-
setFormSuccess(null);
|
|
230
|
-
}, []);
|
|
231
|
-
|
|
232
|
-
const onFormComplete = useCallback(
|
|
233
|
-
newItem => {
|
|
234
|
-
setItem(newItem);
|
|
235
|
-
setFormValue(null);
|
|
236
|
-
setFormErrors(null);
|
|
237
|
-
setFormSuccess(true);
|
|
238
|
-
if (customOnFormComplete !== null) {
|
|
239
|
-
customOnFormComplete(item);
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
[customOnFormComplete],
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
const onFormErrors = useCallback(error => {
|
|
246
|
-
const newErrors = getErrorsFromResponseError(error);
|
|
247
|
-
setFormErrors(newErrors);
|
|
248
|
-
setFormSuccess(false);
|
|
249
|
-
}, []);
|
|
250
|
-
|
|
251
|
-
// Get form definition
|
|
252
|
-
const { type: formType = null, fullscreen, className = null, ...formProps } = useMemo(() => {
|
|
253
|
-
const { fields = [], ...form } = resource.form(action);
|
|
254
|
-
let finalFields;
|
|
255
|
-
if (waitingItem) {
|
|
256
|
-
finalFields = null;
|
|
257
|
-
} else if (currentType !== null && isObject(fields)) {
|
|
258
|
-
finalFields = fields[currentType.id] || fields.default || fields;
|
|
259
|
-
} else {
|
|
260
|
-
finalFields = fields;
|
|
261
|
-
}
|
|
262
|
-
return {
|
|
263
|
-
type: 'normal',
|
|
264
|
-
fullscreen: false,
|
|
265
|
-
fields: finalFields,
|
|
266
|
-
...form,
|
|
267
|
-
};
|
|
268
|
-
}, [waitingItem, resource, currentType]);
|
|
269
|
-
|
|
270
|
-
const FormComponent = useComponent(formType, 'forms');
|
|
271
|
-
const form =
|
|
272
|
-
!waitingItem && FormComponent !== null ? (
|
|
273
|
-
<FormComponent
|
|
274
|
-
{...formProps}
|
|
275
|
-
className={classNames([
|
|
276
|
-
styles.form,
|
|
277
|
-
{
|
|
278
|
-
[className]: className !== null,
|
|
279
|
-
},
|
|
280
|
-
])}
|
|
281
|
-
readOnly={readOnly}
|
|
282
|
-
buttons={formButtons}
|
|
283
|
-
value={formValue || item}
|
|
284
|
-
errors={formErrors}
|
|
285
|
-
notice={
|
|
286
|
-
formSuccess !== null
|
|
287
|
-
? {
|
|
288
|
-
type: formSuccess ? 'success' : 'error',
|
|
289
|
-
label: formSuccess ? successNoticeLabel : errorNoticeLabel,
|
|
290
|
-
}
|
|
291
|
-
: null
|
|
292
|
-
}
|
|
293
|
-
submitForm={submitForm}
|
|
294
|
-
onChange={onFormChange}
|
|
295
|
-
onComplete={onFormComplete}
|
|
296
|
-
onErrors={onFormErrors}
|
|
297
|
-
/>
|
|
298
|
-
) : null;
|
|
299
|
-
|
|
300
|
-
const header = (
|
|
301
|
-
<ResourceFormHeader
|
|
302
|
-
resource={resource}
|
|
303
|
-
type={currentType}
|
|
304
|
-
action={action}
|
|
305
|
-
fullscreen={fullscreen}
|
|
306
|
-
valueHasChanged={formValue !== null}
|
|
307
|
-
title={title}
|
|
308
|
-
titleTyped={titleTyped}
|
|
309
|
-
/>
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
const errorsMessages =
|
|
313
|
-
errors !== null && errors.length > 0 ? (
|
|
314
|
-
<Errors errors={errors} className={styles.errors} />
|
|
315
|
-
) : null;
|
|
316
|
-
|
|
317
|
-
const content =
|
|
318
|
-
isLoading && item === null ? (
|
|
319
|
-
<div className={classNames(['py-4', styles.loading])}>
|
|
320
|
-
<Loading loading />
|
|
321
|
-
</div>
|
|
322
|
-
) : (
|
|
323
|
-
form
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
return (
|
|
327
|
-
<div
|
|
328
|
-
className={classNames([
|
|
329
|
-
styles.container,
|
|
330
|
-
{
|
|
331
|
-
[styles.isFullscreen]: fullscreen,
|
|
332
|
-
},
|
|
333
|
-
])}
|
|
334
|
-
>
|
|
335
|
-
{fullscreen ? (
|
|
336
|
-
<div className={classNames([styles.inner])}>
|
|
337
|
-
{header}
|
|
338
|
-
<div className={classNames([styles.content])}>
|
|
339
|
-
{errorsMessages}
|
|
340
|
-
{content}
|
|
341
|
-
</div>
|
|
342
|
-
</div>
|
|
343
|
-
) : (
|
|
344
|
-
<div className="container">
|
|
345
|
-
<div className="row justify-content-md-center">
|
|
346
|
-
<div className="col-lg-9">
|
|
347
|
-
{header}
|
|
348
|
-
{errorsMessages}
|
|
349
|
-
{content}
|
|
350
|
-
</div>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
)}
|
|
354
|
-
</div>
|
|
355
|
-
);
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
ResourceForm.propTypes = propTypes;
|
|
359
|
-
ResourceForm.defaultProps = defaultProps;
|
|
360
|
-
|
|
361
|
-
export default ResourceForm;
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jsx-a11y/anchor-is-valid, react/no-array-index-key, react/jsx-props-no-spreading */
|
|
2
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import get from 'lodash/get';
|
|
5
|
-
import classNames from 'classnames';
|
|
6
|
-
import { defineMessages, injectIntl } from 'react-intl';
|
|
7
|
-
import { PropTypes as PanneauPropTypes, useResourceApi } from '@panneau/core';
|
|
8
|
-
import { isMessage } from '@panneau/core/utils';
|
|
9
|
-
import { useComponent } from '@panneau/core/contexts';
|
|
10
|
-
import { Loading, Errors } from '@panneau/core/components';
|
|
11
|
-
|
|
12
|
-
import ResourceIndexHeader from '../partials/ResourceIndexHeader';
|
|
13
|
-
|
|
14
|
-
import styles from '../../styles/pages/resource-index.scss';
|
|
15
|
-
|
|
16
|
-
const messages = defineMessages({
|
|
17
|
-
add: {
|
|
18
|
-
id: 'core.buttons.resources.add',
|
|
19
|
-
description: 'The label of the "add" index button',
|
|
20
|
-
defaultMessage: 'Add {name}',
|
|
21
|
-
},
|
|
22
|
-
title: {
|
|
23
|
-
id: 'core.titles.resources.index',
|
|
24
|
-
description: 'The title of the resource index page',
|
|
25
|
-
defaultMessage: '{name}',
|
|
26
|
-
},
|
|
27
|
-
confirmDelete: {
|
|
28
|
-
id: 'core.resources.index.confirm_delete',
|
|
29
|
-
description: 'The confirm message when deleting on the resource index page',
|
|
30
|
-
defaultMessage: 'Are you sure you want to delete this item from {name}?',
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const propTypes = {
|
|
35
|
-
intl: PanneauPropTypes.intl.isRequired,
|
|
36
|
-
resource: PanneauPropTypes.resource.isRequired,
|
|
37
|
-
query: PropTypes.shape({
|
|
38
|
-
page: PropTypes.string,
|
|
39
|
-
}),
|
|
40
|
-
title: PanneauPropTypes.message,
|
|
41
|
-
showAddButton: PropTypes.bool,
|
|
42
|
-
addButtonLabel: PanneauPropTypes.message,
|
|
43
|
-
confirmDeleteMessage: PanneauPropTypes.message,
|
|
44
|
-
getResourceActionUrl: PropTypes.func.isRequired,
|
|
45
|
-
gotoResourceAction: PropTypes.func.isRequired,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const defaultProps = {
|
|
49
|
-
query: null,
|
|
50
|
-
title: messages.title,
|
|
51
|
-
showAddButton: true,
|
|
52
|
-
addButtonLabel: messages.add,
|
|
53
|
-
confirmDeleteMessage: messages.confirmDelete,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const ResourceIndex = ({
|
|
57
|
-
intl,
|
|
58
|
-
resource,
|
|
59
|
-
query,
|
|
60
|
-
title,
|
|
61
|
-
addButtonLabel,
|
|
62
|
-
confirmDeleteMessage,
|
|
63
|
-
getResourceActionUrl,
|
|
64
|
-
gotoResourceAction,
|
|
65
|
-
showAddButton,
|
|
66
|
-
}) => {
|
|
67
|
-
const [request, setRequest] = useState({
|
|
68
|
-
isLoading: false,
|
|
69
|
-
query: null,
|
|
70
|
-
items: null,
|
|
71
|
-
errors: null,
|
|
72
|
-
pagination: null,
|
|
73
|
-
});
|
|
74
|
-
const resourceApi = useResourceApi(resource);
|
|
75
|
-
const { isLoading, items, pagination, errors } = request;
|
|
76
|
-
const { type: listType, pagination: hasPagination = false, ...listProps } = resource.list(
|
|
77
|
-
'index',
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
useEffect(() => {
|
|
81
|
-
if (isLoading) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
let canceled = false;
|
|
85
|
-
const onItemsLoaded = data => {
|
|
86
|
-
if (canceled) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (hasPagination) {
|
|
90
|
-
const { data: newItems, ...newPagination } = data;
|
|
91
|
-
setRequest({
|
|
92
|
-
...request,
|
|
93
|
-
items: newItems,
|
|
94
|
-
pagination: newPagination,
|
|
95
|
-
isLoading: false,
|
|
96
|
-
});
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
setRequest({
|
|
100
|
-
...request,
|
|
101
|
-
items: data,
|
|
102
|
-
isLoading: false,
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const onItemsLoadError = newErrors => {
|
|
107
|
-
if (canceled) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
setRequest({
|
|
111
|
-
...request,
|
|
112
|
-
errors: newErrors,
|
|
113
|
-
isLoading: false,
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const { page = null } = query || {};
|
|
118
|
-
const params = {};
|
|
119
|
-
if (hasPagination && page !== null) {
|
|
120
|
-
params.page = page;
|
|
121
|
-
}
|
|
122
|
-
resourceApi
|
|
123
|
-
.index(params)
|
|
124
|
-
.then(onItemsLoaded)
|
|
125
|
-
.catch(onItemsLoadError);
|
|
126
|
-
|
|
127
|
-
setRequest({
|
|
128
|
-
...request,
|
|
129
|
-
isLoading: true,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
return () => {
|
|
133
|
-
canceled = true;
|
|
134
|
-
};
|
|
135
|
-
}, [query, hasPagination]);
|
|
136
|
-
|
|
137
|
-
const deleteItem = useCallback(
|
|
138
|
-
id => {
|
|
139
|
-
const onItemDeleted = ({ id: itemId }) => {
|
|
140
|
-
setRequest({
|
|
141
|
-
...request,
|
|
142
|
-
items: items.filter(it => it.id !== itemId),
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const { name } = resource;
|
|
147
|
-
const confirmMessage = resource.message('confirm_delete', confirmDeleteMessage);
|
|
148
|
-
const message = isMessage(confirmMessage)
|
|
149
|
-
? intl.formatMessage(confirmMessage, {
|
|
150
|
-
name,
|
|
151
|
-
id,
|
|
152
|
-
})
|
|
153
|
-
: confirmMessage;
|
|
154
|
-
// eslint-disable-next-line no-alert
|
|
155
|
-
if (window.confirm(message)) {
|
|
156
|
-
resourceApi.destroy(id).then(onItemDeleted);
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
[resource, request],
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const onClickAction = useCallback(
|
|
163
|
-
(e, action, it) => {
|
|
164
|
-
const useRouter = get(action, 'useRouter', true);
|
|
165
|
-
|
|
166
|
-
switch (action.id) {
|
|
167
|
-
case 'edit':
|
|
168
|
-
case 'show':
|
|
169
|
-
if (useRouter) {
|
|
170
|
-
gotoResourceAction(action.id, it.id);
|
|
171
|
-
} else {
|
|
172
|
-
window.location.href = getResourceActionUrl(action.id);
|
|
173
|
-
}
|
|
174
|
-
break;
|
|
175
|
-
case 'delete': {
|
|
176
|
-
const hasPage = get(action, 'hasPage', false);
|
|
177
|
-
if (!hasPage) {
|
|
178
|
-
deleteItem(it.id);
|
|
179
|
-
} else if (useRouter) {
|
|
180
|
-
gotoResourceAction(action.id, it.id);
|
|
181
|
-
} else {
|
|
182
|
-
window.location.href = getResourceActionUrl(action.id);
|
|
183
|
-
}
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
default:
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
[deleteItem, gotoResourceAction, getResourceActionUrl],
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
// Components
|
|
194
|
-
const ListComponent = useComponent(listType || 'table', 'lists');
|
|
195
|
-
const Pagination = useComponent('pagination', 'lists');
|
|
196
|
-
|
|
197
|
-
return (
|
|
198
|
-
<div className={classNames([styles.container])}>
|
|
199
|
-
<div className="container">
|
|
200
|
-
<div className="row justify-content-md-center">
|
|
201
|
-
<div className="col-lg-8">
|
|
202
|
-
<ResourceIndexHeader
|
|
203
|
-
resource={resource}
|
|
204
|
-
title={title}
|
|
205
|
-
addButtonLabel={addButtonLabel}
|
|
206
|
-
showAddButton={showAddButton}
|
|
207
|
-
getResourceActionUrl={getResourceActionUrl}
|
|
208
|
-
/>
|
|
209
|
-
<div className={styles.listContainer}>
|
|
210
|
-
<Errors errors={errors} />
|
|
211
|
-
<div className={styles.list}>
|
|
212
|
-
{items !== null && ListComponent !== null ? (
|
|
213
|
-
<div className={styles.list}>
|
|
214
|
-
<ListComponent
|
|
215
|
-
{...listProps}
|
|
216
|
-
items={items || []}
|
|
217
|
-
onClickAction={onClickAction}
|
|
218
|
-
/>
|
|
219
|
-
</div>
|
|
220
|
-
) : null}
|
|
221
|
-
</div>
|
|
222
|
-
{isLoading ? (
|
|
223
|
-
<div
|
|
224
|
-
className={classNames({
|
|
225
|
-
[styles.loading]: true,
|
|
226
|
-
[styles.alone]: items === null,
|
|
227
|
-
})}
|
|
228
|
-
>
|
|
229
|
-
<div className={styles.inner}>
|
|
230
|
-
<div className={styles.middle}>
|
|
231
|
-
<Loading loading />
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
) : null}
|
|
236
|
-
</div>
|
|
237
|
-
{pagination !== null && pagination.last_page > 1 ? (
|
|
238
|
-
<Pagination
|
|
239
|
-
total={pagination.total}
|
|
240
|
-
perPage={pagination.per_page}
|
|
241
|
-
currentPage={pagination.current_page}
|
|
242
|
-
lastPage={pagination.last_page}
|
|
243
|
-
url={getResourceActionUrl('index')}
|
|
244
|
-
/>
|
|
245
|
-
) : null}
|
|
246
|
-
</div>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
ResourceIndex.propTypes = propTypes;
|
|
254
|
-
ResourceIndex.defaultProps = defaultProps;
|
|
255
|
-
|
|
256
|
-
export default injectIntl(ResourceIndex);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import ResourceForm from './ResourceForm';
|
|
4
|
-
|
|
5
|
-
const propTypes = {
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const defaultProps = {
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const ResourceShow = props => (
|
|
14
|
-
<ResourceForm
|
|
15
|
-
readOnly
|
|
16
|
-
{...props}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
ResourceShow.propTypes = propTypes;
|
|
21
|
-
ResourceShow.defaultProps = defaultProps;
|
|
22
|
-
|
|
23
|
-
export default ResourceShow;
|