proje-react-panel 1.0.17-test7 → 1.1.0
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/dist/components/Counter.d.ts +9 -0
- package/dist/components/DetailsPage.d.ts +7 -0
- package/dist/components/ErrorBoundary.d.ts +16 -0
- package/dist/components/ErrorComponent.d.ts +4 -0
- package/dist/components/LoadingScreen.d.ts +2 -0
- package/dist/components/Login.d.ts +13 -0
- package/dist/components/Panel.d.ts +1 -3
- package/dist/components/components/Checkbox.d.ts +3 -2
- package/dist/components/components/Label.d.ts +3 -2
- package/dist/components/components/Uploader.d.ts +2 -1
- package/dist/components/form/Checkbox.d.ts +7 -0
- package/dist/components/form/FormField.d.ts +17 -0
- package/dist/components/form/FormPage.d.ts +6 -0
- package/dist/components/form/InnerForm.d.ts +10 -0
- package/dist/components/form/Label.d.ts +9 -0
- package/dist/components/form/Uploader.d.ts +8 -0
- package/dist/components/layout/Layout.d.ts +3 -4
- package/dist/components/layout/SideBar.d.ts +2 -3
- package/dist/components/list/CellField.d.ts +9 -0
- package/dist/components/list/Datagrid.d.ts +6 -8
- package/dist/components/list/FilterPopup.d.ts +7 -5
- package/dist/components/list/ListHeader.d.ts +11 -0
- package/dist/components/list/ListPage.d.ts +6 -0
- package/dist/decorators/details/Details.d.ts +11 -0
- package/dist/decorators/details/DetailsItem.d.ts +11 -0
- package/dist/decorators/details/getDetailsPageMeta.d.ts +8 -0
- package/dist/decorators/form/Form.d.ts +21 -5
- package/dist/decorators/form/Input.d.ts +6 -3
- package/dist/decorators/form/getFormPageMeta.d.ts +10 -0
- package/dist/decorators/list/Cell.d.ts +13 -1
- package/dist/decorators/list/List.d.ts +18 -1
- package/dist/decorators/list/cells/ImageCell.d.ts +9 -0
- package/dist/decorators/list/getListPageMeta.d.ts +8 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +12 -17
- package/dist/index.esm.js +1 -1
- package/dist/initPanel.d.ts +1 -1
- package/dist/store/store.d.ts +0 -3
- package/dist/types/AnyClass.d.ts +2 -1
- package/dist/types/getDetailsData.d.ts +1 -0
- package/dist/types/initPanelOptions.d.ts +0 -1
- package/package.json +1 -1
- package/src/assets/icons/svg/check.svg +4 -0
- package/src/assets/icons/svg/cross.svg +4 -0
- package/src/components/DetailsPage.tsx +55 -0
- package/src/components/{components/ErrorComponent.tsx → ErrorComponent.tsx} +1 -1
- package/src/components/{pages/Login.tsx → Login.tsx} +2 -2
- package/src/components/Panel.tsx +4 -5
- package/src/components/form/Checkbox.tsx +21 -0
- package/src/components/{components → form}/FormField.tsx +16 -17
- package/src/components/form/FormPage.tsx +32 -0
- package/src/components/form/InnerForm.tsx +85 -0
- package/src/components/form/Label.tsx +21 -0
- package/src/components/layout/Layout.tsx +29 -32
- package/src/components/layout/SideBar.tsx +4 -13
- package/src/components/list/CellField.tsx +63 -0
- package/src/components/list/Datagrid.tsx +106 -0
- package/src/components/{components/list → list}/FilterPopup.tsx +13 -9
- package/src/components/list/ListHeader.tsx +47 -0
- package/src/components/{components/list → list}/ListPage.tsx +20 -80
- package/src/decorators/details/Details.ts +31 -0
- package/src/decorators/details/DetailsItem.ts +40 -0
- package/src/decorators/details/getDetailsPageMeta.ts +15 -0
- package/src/decorators/form/Form.ts +37 -12
- package/src/decorators/form/Input.ts +9 -4
- package/src/decorators/form/getFormPageMeta.ts +21 -0
- package/src/decorators/list/Cell.ts +41 -1
- package/src/decorators/list/List.ts +30 -6
- package/src/decorators/list/cells/ImageCell.ts +17 -0
- package/src/decorators/list/getListPageMeta.ts +16 -0
- package/src/index.ts +32 -24
- package/src/initPanel.ts +1 -4
- package/src/store/store.ts +0 -5
- package/src/styles/components/checkbox.scss +42 -0
- package/src/styles/details.scss +62 -0
- package/src/styles/form.scss +7 -7
- package/src/styles/index.scss +16 -2
- package/src/types/AnyClass.ts +2 -3
- package/src/types/initPanelOptions.ts +1 -3
- package/src/components/components/Checkbox.tsx +0 -9
- package/src/components/components/InnerForm.tsx +0 -113
- package/src/components/components/Label.tsx +0 -15
- package/src/components/components/index.ts +0 -8
- package/src/components/components/list/Datagrid.tsx +0 -135
- package/src/components/pages/ControllerDetails.tsx +0 -37
- package/src/components/pages/FormPage.tsx +0 -41
- package/src/decorators/Crud.ts +0 -20
- package/src/decorators/form/FormOptions.ts +0 -8
- package/src/decorators/form/getFormFields.ts +0 -14
- package/src/decorators/list/GetCellFields.ts +0 -13
- package/src/decorators/list/ImageCell.ts +0 -13
- package/src/decorators/list/ListData.ts +0 -7
- package/src/decorators/list/getListFields.ts +0 -10
- package/src/styles/image-uploader.scss +0 -94
- package/src/types/Screen.ts +0 -4
- package/src/types/ScreenCreatorData.ts +0 -14
- package/src/utils/createScreens.ts +0 -5
- package/src/utils/getFields.ts +0 -22
- /package/src/components/{components/Counter.tsx → Counter.tsx} +0 -0
- /package/src/components/{components/ErrorBoundary.tsx → ErrorBoundary.tsx} +0 -0
- /package/src/components/{components/LoadingScreen.tsx → LoadingScreen.tsx} +0 -0
- /package/src/components/{components → form}/Uploader.tsx +0 -0
- /package/src/components/{components/list → list}/EmptyList.tsx +0 -0
- /package/src/components/{components/list → list}/Pagination.tsx +0 -0
- /package/src/components/{components/list → list}/index.ts +0 -0
- /package/src/styles/{uploader.scss → components/uploader.scss} +0 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
:root {
|
2
|
+
--background-color: #1a1a1a;
|
3
|
+
--text-color: #e0e0e0;
|
4
|
+
--label-color: #a0a0a0;
|
5
|
+
--empty-value-color: #666;
|
6
|
+
--error-color: #ff6b6b;
|
7
|
+
--shadow-color: rgba(0, 0, 0, 0.3);
|
8
|
+
}
|
9
|
+
|
10
|
+
.details-page {
|
11
|
+
padding: 2rem;
|
12
|
+
max-width: 1200px;
|
13
|
+
margin: 0 auto;
|
14
|
+
|
15
|
+
.details-item {
|
16
|
+
background: var(--background-color);
|
17
|
+
border-radius: 8px;
|
18
|
+
padding: 1.5rem;
|
19
|
+
margin-bottom: 1rem;
|
20
|
+
box-shadow: 0 2px 4px var(--shadow-color);
|
21
|
+
transition: transform 0.2s ease;
|
22
|
+
|
23
|
+
&:hover {
|
24
|
+
transform: translateY(-2px);
|
25
|
+
}
|
26
|
+
|
27
|
+
.item-label {
|
28
|
+
font-size: 0.875rem;
|
29
|
+
color: var(--label-color);
|
30
|
+
text-transform: uppercase;
|
31
|
+
letter-spacing: 0.5px;
|
32
|
+
margin-bottom: 0.5rem;
|
33
|
+
}
|
34
|
+
|
35
|
+
.item-value {
|
36
|
+
font-size: 1rem;
|
37
|
+
color: var(--text-color);
|
38
|
+
line-height: 1.5;
|
39
|
+
word-break: break-word;
|
40
|
+
|
41
|
+
&:empty {
|
42
|
+
&::after {
|
43
|
+
content: '—';
|
44
|
+
color: var(--empty-value-color);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
.loading-container {
|
52
|
+
display: flex;
|
53
|
+
justify-content: center;
|
54
|
+
align-items: center;
|
55
|
+
min-height: 400px;
|
56
|
+
}
|
57
|
+
|
58
|
+
.error-container {
|
59
|
+
padding: 2rem;
|
60
|
+
text-align: center;
|
61
|
+
color: var(--error-color);
|
62
|
+
}
|
package/src/styles/form.scss
CHANGED
@@ -12,13 +12,6 @@
|
|
12
12
|
.form-field {
|
13
13
|
margin-bottom: 16px;
|
14
14
|
|
15
|
-
label {
|
16
|
-
font-weight: bold;
|
17
|
-
margin-bottom: 6px;
|
18
|
-
display: block;
|
19
|
-
color: #f2f2f2;
|
20
|
-
}
|
21
|
-
|
22
15
|
input[type='text'],
|
23
16
|
input[type='password'],
|
24
17
|
input[type='email'],
|
@@ -86,3 +79,10 @@
|
|
86
79
|
}
|
87
80
|
}
|
88
81
|
}
|
82
|
+
|
83
|
+
.label {
|
84
|
+
font-weight: bold;
|
85
|
+
margin-bottom: 6px;
|
86
|
+
display: block;
|
87
|
+
color: #f2f2f2;
|
88
|
+
}
|
package/src/styles/index.scss
CHANGED
@@ -4,13 +4,15 @@
|
|
4
4
|
@import './list';
|
5
5
|
@import './login';
|
6
6
|
@import './error-boundary';
|
7
|
-
@import './image-uploader';
|
8
7
|
@import './counter';
|
9
8
|
@import './loading-screen';
|
10
9
|
@import './pagination';
|
11
10
|
@import './filter-popup';
|
12
|
-
@import './uploader';
|
11
|
+
@import './components/uploader.scss';
|
12
|
+
@import './components/checkbox';
|
13
|
+
@import './details';
|
13
14
|
|
15
|
+
//TODO: import deprecated
|
14
16
|
.layout {
|
15
17
|
display: flex;
|
16
18
|
max-height: 100vh;
|
@@ -39,4 +41,16 @@
|
|
39
41
|
height: 14px;
|
40
42
|
stroke: currentColor;
|
41
43
|
fill: currentColor;
|
44
|
+
&.icon-true {
|
45
|
+
width: 20px;
|
46
|
+
height: 20px;
|
47
|
+
stroke: #4caf50;
|
48
|
+
fill: none;
|
49
|
+
}
|
50
|
+
&.icon-false {
|
51
|
+
width: 20px;
|
52
|
+
height: 20px;
|
53
|
+
stroke: #ff0000;
|
54
|
+
fill: none;
|
55
|
+
}
|
42
56
|
}
|
package/src/types/AnyClass.ts
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
export type AnyClass = any;
|
1
|
+
export type AnyClass = Record<string, any>;
|
2
|
+
export type AnyClassConstructor<T extends AnyClass> = new (...args: any[]) => T;
|
@@ -1,9 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
|
3
|
-
interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
4
|
-
id: string;
|
5
|
-
}
|
6
|
-
|
7
|
-
export function Checkbox({ id, ...props }: CheckboxProps) {
|
8
|
-
return <input type="checkbox" id={id} className="checkbox" {...props} />;
|
9
|
-
}
|
@@ -1,113 +0,0 @@
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react';
|
2
|
-
import { FormProvider, useForm } from 'react-hook-form';
|
3
|
-
import { InputOptions } from '../../decorators/form/Input';
|
4
|
-
import { FormField } from './FormField';
|
5
|
-
import { FormOptions } from '../../decorators/form/FormOptions';
|
6
|
-
import { AnyClass } from '../../types/AnyClass';
|
7
|
-
import { OnSubmitFN, GetDetailsDataFN } from '../pages/FormPage';
|
8
|
-
import { useParams, useNavigate } from 'react-router';
|
9
|
-
|
10
|
-
interface InnerFormProps<T> {
|
11
|
-
formOptions: FormOptions;
|
12
|
-
onSubmit: OnSubmitFN<T>;
|
13
|
-
getDetailsData?: GetDetailsDataFN<T>;
|
14
|
-
redirectBackOnSuccess?: boolean;
|
15
|
-
onSelectPreloader?: (inputOptions: InputOptions) => Promise<{ label: string; value: string }[]>;
|
16
|
-
type?: 'json' | 'formData';
|
17
|
-
}
|
18
|
-
|
19
|
-
export function InnerForm<T>({
|
20
|
-
formOptions,
|
21
|
-
onSubmit,
|
22
|
-
getDetailsData,
|
23
|
-
redirectBackOnSuccess,
|
24
|
-
onSelectPreloader,
|
25
|
-
type,
|
26
|
-
}: InnerFormProps<T>) {
|
27
|
-
const params = useParams();
|
28
|
-
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
29
|
-
//TODO: any is not a good solution, we need to find a better way to do this
|
30
|
-
const form = useForm<any>({
|
31
|
-
resolver: formOptions.resolver,
|
32
|
-
});
|
33
|
-
const formRef = useRef<HTMLFormElement>(null);
|
34
|
-
const navigate = useNavigate();
|
35
|
-
const inputs = formOptions.inputs;
|
36
|
-
useEffect(() => {
|
37
|
-
if (getDetailsData) {
|
38
|
-
getDetailsData(params as Record<string, string>).then(data => {
|
39
|
-
form.reset({ ...data });
|
40
|
-
});
|
41
|
-
}
|
42
|
-
}, [params, form.reset]);
|
43
|
-
|
44
|
-
return (
|
45
|
-
<div className="form-wrapper">
|
46
|
-
<FormProvider {...form}>
|
47
|
-
<form
|
48
|
-
ref={formRef}
|
49
|
-
onSubmit={form.handleSubmit(
|
50
|
-
async dataForm => {
|
51
|
-
try {
|
52
|
-
console.log('dataForm', dataForm);
|
53
|
-
const data =
|
54
|
-
type === 'json'
|
55
|
-
? dataForm
|
56
|
-
: (() => {
|
57
|
-
const formData = new FormData(formRef.current!);
|
58
|
-
for (const key in dataForm) {
|
59
|
-
if (!formData.get(key)) {
|
60
|
-
formData.append(key, dataForm[key]);
|
61
|
-
}
|
62
|
-
}
|
63
|
-
console.log('formData', formData);
|
64
|
-
return formData;
|
65
|
-
})();
|
66
|
-
console.log('data', data);
|
67
|
-
await onSubmit(data);
|
68
|
-
setErrorMessage(null);
|
69
|
-
if (redirectBackOnSuccess) {
|
70
|
-
navigate(-1);
|
71
|
-
}
|
72
|
-
} catch (error: any) {
|
73
|
-
const message =
|
74
|
-
error?.response?.data?.message ||
|
75
|
-
(error instanceof Error ? error.message : 'An error occurred');
|
76
|
-
setErrorMessage(message);
|
77
|
-
console.error(error);
|
78
|
-
}
|
79
|
-
},
|
80
|
-
(errors, event) => {
|
81
|
-
//TOOD: put error if useer choose global error
|
82
|
-
console.log('error creating creation', errors, event);
|
83
|
-
}
|
84
|
-
)}
|
85
|
-
>
|
86
|
-
<div>
|
87
|
-
{errorMessage && (
|
88
|
-
<div className="error-message" style={{ color: 'red', marginBottom: '1rem' }}>
|
89
|
-
{errorMessage}
|
90
|
-
</div>
|
91
|
-
)}
|
92
|
-
{inputs?.map((input: InputOptions) => (
|
93
|
-
<FormField
|
94
|
-
key={input.name || ''}
|
95
|
-
input={input}
|
96
|
-
register={form.register}
|
97
|
-
onSelectPreloader={onSelectPreloader}
|
98
|
-
error={
|
99
|
-
input.name
|
100
|
-
? { message: (form.formState.errors[input.name as keyof T] as any)?.message }
|
101
|
-
: undefined
|
102
|
-
}
|
103
|
-
/>
|
104
|
-
))}
|
105
|
-
<button type="submit" className="submit-button">
|
106
|
-
Submit
|
107
|
-
</button>
|
108
|
-
</div>
|
109
|
-
</form>
|
110
|
-
</FormProvider>
|
111
|
-
</div>
|
112
|
-
);
|
113
|
-
}
|
@@ -1,15 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
|
3
|
-
interface LabelProps {
|
4
|
-
htmlFor: string;
|
5
|
-
label?: string;
|
6
|
-
fieldName: string;
|
7
|
-
}
|
8
|
-
|
9
|
-
export function Label({ htmlFor, label, fieldName }: LabelProps) {
|
10
|
-
return (
|
11
|
-
<label htmlFor={htmlFor}>
|
12
|
-
{label ?? fieldName.charAt(0).toUpperCase() + fieldName.slice(1)}
|
13
|
-
</label>
|
14
|
-
);
|
15
|
-
}
|
@@ -1,8 +0,0 @@
|
|
1
|
-
export { InnerForm } from './InnerForm';
|
2
|
-
export { FormField } from './FormField';
|
3
|
-
export { LoadingScreen } from './LoadingScreen';
|
4
|
-
export { Counter } from './Counter';
|
5
|
-
export { Uploader } from './Uploader';
|
6
|
-
export { ErrorComponent } from './ErrorComponent';
|
7
|
-
export { Label } from './Label';
|
8
|
-
export { ErrorBoundary } from './ErrorBoundary';
|
@@ -1,135 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { CellOptions } from '../../../decorators/list/Cell';
|
3
|
-
import { Link } from 'react-router';
|
4
|
-
import { useAppStore } from '../../../store/store';
|
5
|
-
import { ImageCellOptions } from '../../../decorators/list/ImageCell';
|
6
|
-
import { ListData } from '../../../decorators/list/ListData';
|
7
|
-
import { EmptyList } from './EmptyList';
|
8
|
-
import SearchIcon from '../../../assets/icons/svg/search.svg';
|
9
|
-
import PencilIcon from '../../../assets/icons/svg/pencil.svg';
|
10
|
-
import TrashIcon from '../../../assets/icons/svg/trash.svg';
|
11
|
-
|
12
|
-
interface DatagridProps<T> {
|
13
|
-
data: T[];
|
14
|
-
listData: ListData<T>;
|
15
|
-
onRemoveItem?: (item: T) => Promise<void>;
|
16
|
-
}
|
17
|
-
|
18
|
-
export function Datagrid<T>({ data, listData, onRemoveItem }: DatagridProps<T>) {
|
19
|
-
const cells = listData.cells;
|
20
|
-
const listGeneralCells = data?.[0]
|
21
|
-
? typeof listData.list?.cells === 'function'
|
22
|
-
? listData.list?.cells?.(data[0])
|
23
|
-
: listData.list?.cells
|
24
|
-
: null;
|
25
|
-
|
26
|
-
return (
|
27
|
-
<div className="datagrid">
|
28
|
-
{!data || data.length === 0 ? (
|
29
|
-
<EmptyList />
|
30
|
-
) : (
|
31
|
-
<table className="datagrid-table">
|
32
|
-
<thead>
|
33
|
-
<tr>
|
34
|
-
{cells.map(cellOptions => (
|
35
|
-
<th key={cellOptions.name}>{cellOptions.title ?? cellOptions.name}</th>
|
36
|
-
))}
|
37
|
-
{listGeneralCells?.details && <th>Details</th>}
|
38
|
-
{listGeneralCells?.edit && <th>Edit</th>}
|
39
|
-
{listGeneralCells?.delete && <th>Delete</th>}
|
40
|
-
</tr>
|
41
|
-
</thead>
|
42
|
-
<tbody>
|
43
|
-
{data.map((item, index) => {
|
44
|
-
const listCells = item
|
45
|
-
? typeof listData.list?.cells === 'function'
|
46
|
-
? listData.list?.cells?.(item)
|
47
|
-
: listData.list?.cells
|
48
|
-
: null;
|
49
|
-
return (
|
50
|
-
<tr key={index}>
|
51
|
-
{cells.map(cellOptions => {
|
52
|
-
// @ts-ignore
|
53
|
-
const value = item[cellOptions.name];
|
54
|
-
let render = value ?? '-'; // Default value if the field is undefined or null
|
55
|
-
|
56
|
-
switch (cellOptions.type) {
|
57
|
-
case 'date':
|
58
|
-
if (value) {
|
59
|
-
const date = new Date(value);
|
60
|
-
render = `${date.getDate().toString().padStart(2, '0')}/${(
|
61
|
-
date.getMonth() + 1
|
62
|
-
)
|
63
|
-
.toString()
|
64
|
-
.padStart(
|
65
|
-
2,
|
66
|
-
'0'
|
67
|
-
)}/${date.getFullYear()} ${date.getHours().toString().padStart(2, '0')}:${date
|
68
|
-
.getMinutes()
|
69
|
-
.toString()
|
70
|
-
.padStart(2, '0')}`;
|
71
|
-
}
|
72
|
-
break;
|
73
|
-
|
74
|
-
case 'image': {
|
75
|
-
const imageCellOptions = cellOptions as ImageCellOptions;
|
76
|
-
render = (
|
77
|
-
<img
|
78
|
-
width={100}
|
79
|
-
height={100}
|
80
|
-
src={imageCellOptions.baseUrl + value}
|
81
|
-
style={{ objectFit: 'contain' }}
|
82
|
-
/>
|
83
|
-
);
|
84
|
-
break;
|
85
|
-
}
|
86
|
-
case 'string':
|
87
|
-
default:
|
88
|
-
render = value ? value.toString() : (cellOptions?.placeHolder ?? '-'); // Handles string type or default fallback
|
89
|
-
break;
|
90
|
-
}
|
91
|
-
/*
|
92
|
-
if (cellOptions.linkTo) {
|
93
|
-
render = <Link to={cellOptions.linkTo(item)}>{formattedValue}</Link>;
|
94
|
-
}
|
95
|
-
*/
|
96
|
-
return <td key={cellOptions.name}>{render}</td>;
|
97
|
-
})}
|
98
|
-
{listCells?.details && (
|
99
|
-
<td>
|
100
|
-
<Link to={listCells.details.path} className="util-cell-link">
|
101
|
-
<SearchIcon className="icon icon-search" />
|
102
|
-
<span className="util-cell-label">{listCells.details.label}</span>
|
103
|
-
</Link>
|
104
|
-
</td>
|
105
|
-
)}
|
106
|
-
{listCells?.edit && (
|
107
|
-
<td>
|
108
|
-
<Link to={listCells.edit.path} className="util-cell-link">
|
109
|
-
<PencilIcon className="icon icon-pencil" />
|
110
|
-
<span className="util-cell-label">{listCells.edit.label}</span>
|
111
|
-
</Link>
|
112
|
-
</td>
|
113
|
-
)}
|
114
|
-
{listCells?.delete && (
|
115
|
-
<td>
|
116
|
-
<a
|
117
|
-
onClick={() => {
|
118
|
-
onRemoveItem?.(item);
|
119
|
-
}}
|
120
|
-
className="util-cell-link util-cell-link-remove"
|
121
|
-
>
|
122
|
-
<TrashIcon className="icon icon-trash" />
|
123
|
-
<span className="util-cell-label">{listCells.delete.label}</span>
|
124
|
-
</a>
|
125
|
-
</td>
|
126
|
-
)}
|
127
|
-
</tr>
|
128
|
-
);
|
129
|
-
})}
|
130
|
-
</tbody>
|
131
|
-
</table>
|
132
|
-
)}
|
133
|
-
</div>
|
134
|
-
);
|
135
|
-
}
|
@@ -1,37 +0,0 @@
|
|
1
|
-
import { useParams } from 'react-router';
|
2
|
-
import React, { useEffect, useState } from 'react';
|
3
|
-
import { Screen } from '../../types/Screen';
|
4
|
-
import { ErrorComponent } from '../components/ErrorComponent';
|
5
|
-
|
6
|
-
export function ControllerDetails({ screen }: { screen: Screen }) {
|
7
|
-
const { id } = useParams();
|
8
|
-
const [data, setData] = useState<any>(null);
|
9
|
-
const [error, setError] = useState(null);
|
10
|
-
|
11
|
-
useEffect(() => {
|
12
|
-
if (screen.controller && id) {
|
13
|
-
/*
|
14
|
-
CrudApi.details({ ...fetchSettings, token }, screen.controller, id)
|
15
|
-
.then(res => {
|
16
|
-
setData(res);
|
17
|
-
})
|
18
|
-
.catch((e: any) => {
|
19
|
-
setError(e);
|
20
|
-
console.error(e);
|
21
|
-
});
|
22
|
-
*/
|
23
|
-
}
|
24
|
-
}, [id, screen]);
|
25
|
-
|
26
|
-
if (error) {
|
27
|
-
return <ErrorComponent error={error} />;
|
28
|
-
}
|
29
|
-
|
30
|
-
return (
|
31
|
-
<p
|
32
|
-
dangerouslySetInnerHTML={{
|
33
|
-
__html: JSON.stringify(data, null, ' ' + '<br/>'),
|
34
|
-
}}
|
35
|
-
/>
|
36
|
-
);
|
37
|
-
}
|
@@ -1,41 +0,0 @@
|
|
1
|
-
import React, { useMemo } from 'react';
|
2
|
-
import { InnerForm } from '../components';
|
3
|
-
import { AnyClass } from '../../types/AnyClass';
|
4
|
-
import { getFormFields } from '../../decorators/form/getFormFields';
|
5
|
-
import { InputOptions } from '../../decorators/form/Input';
|
6
|
-
|
7
|
-
export type GetDetailsDataFN<T> = (param: Record<string, string>) => Promise<T>;
|
8
|
-
export type OnSubmitFN<T> = (data: T) => Promise<T>;
|
9
|
-
|
10
|
-
export interface FormPageProps<T extends AnyClass> {
|
11
|
-
model: any; //TODO: use T not typeof T
|
12
|
-
getDetailsData?: GetDetailsDataFN<T>;
|
13
|
-
redirect?: string;
|
14
|
-
onSubmit: OnSubmitFN<T>;
|
15
|
-
onSelectPreloader?: (inputOptions: InputOptions) => Promise<{ label: string; value: string }[]>;
|
16
|
-
redirectBackOnSuccess?: boolean;
|
17
|
-
type?: 'json' | 'formData';
|
18
|
-
}
|
19
|
-
|
20
|
-
export function FormPage<T extends AnyClass>({
|
21
|
-
model,
|
22
|
-
getDetailsData,
|
23
|
-
onSubmit,
|
24
|
-
redirect,
|
25
|
-
onSelectPreloader,
|
26
|
-
redirectBackOnSuccess = true,
|
27
|
-
type = 'json',
|
28
|
-
...rest
|
29
|
-
}: FormPageProps<T>) {
|
30
|
-
const formOptions = useMemo(() => getFormFields(model), [model]);
|
31
|
-
return (
|
32
|
-
<InnerForm
|
33
|
-
getDetailsData={getDetailsData}
|
34
|
-
onSubmit={onSubmit}
|
35
|
-
formOptions={formOptions}
|
36
|
-
redirectBackOnSuccess={redirectBackOnSuccess}
|
37
|
-
onSelectPreloader={onSelectPreloader}
|
38
|
-
type={type}
|
39
|
-
/>
|
40
|
-
);
|
41
|
-
}
|
package/src/decorators/Crud.ts
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
import 'reflect-metadata';
|
2
|
-
|
3
|
-
const CRUD_KEY = 'Crud'; // Changed from Symbol to string
|
4
|
-
|
5
|
-
export interface CrudOptions {
|
6
|
-
controller: string;
|
7
|
-
}
|
8
|
-
|
9
|
-
export function Crud(options?: CrudOptions): ClassDecorator {
|
10
|
-
return (target: Function) => {
|
11
|
-
if (options) {
|
12
|
-
Reflect.defineMetadata(CRUD_KEY, options, target);
|
13
|
-
}
|
14
|
-
};
|
15
|
-
}
|
16
|
-
|
17
|
-
|
18
|
-
export function getClassCrudData(entityClass: any): CrudOptions | undefined {
|
19
|
-
return Reflect.getMetadata(CRUD_KEY, entityClass);
|
20
|
-
}
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import { AnyClass } from "../../types/AnyClass";
|
2
|
-
import { FormOptions } from "./FormOptions";
|
3
|
-
import { getInputFields } from "./Input";
|
4
|
-
import { getFormConfiguration } from "./Form";
|
5
|
-
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
|
6
|
-
|
7
|
-
export function getFormFields<T extends AnyClass>(entityClass: T): FormOptions {
|
8
|
-
console.log(entityClass);
|
9
|
-
return {
|
10
|
-
resolver: classValidatorResolver(entityClass as any),
|
11
|
-
form: getFormConfiguration(entityClass),
|
12
|
-
inputs: getInputFields<T>(entityClass),
|
13
|
-
};
|
14
|
-
}
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import { CELL_KEY, CellOptions } from "./Cell";
|
2
|
-
|
3
|
-
export function getCellFields(entityClass: any): CellOptions[] {
|
4
|
-
const prototype = entityClass.prototype;
|
5
|
-
const cellFields: string[] = Reflect.getMetadata(CELL_KEY, prototype) || [];
|
6
|
-
return cellFields.map((field) => {
|
7
|
-
const fields = Reflect.getMetadata(`${CELL_KEY.toString()}:${field}:options`, prototype) || {};
|
8
|
-
return {
|
9
|
-
...fields,
|
10
|
-
name: fields?.name ?? field,
|
11
|
-
};
|
12
|
-
});
|
13
|
-
}
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import "reflect-metadata";
|
2
|
-
import { Cell, CellOptions } from "./Cell";
|
3
|
-
|
4
|
-
export interface ImageCellOptions extends CellOptions {
|
5
|
-
baseUrl: string;
|
6
|
-
}
|
7
|
-
|
8
|
-
export function ImageCell(options?: ImageCellOptions): PropertyDecorator {
|
9
|
-
return Cell({
|
10
|
-
...options,
|
11
|
-
type: "image",
|
12
|
-
});
|
13
|
-
}
|
@@ -1,10 +0,0 @@
|
|
1
|
-
import { getClassListData } from './List';
|
2
|
-
import { getCellFields } from './GetCellFields';
|
3
|
-
import { ListData } from './ListData';
|
4
|
-
|
5
|
-
export function getListFields<T>(entityClass: T): ListData<T> {
|
6
|
-
return {
|
7
|
-
list: getClassListData(entityClass),
|
8
|
-
cells: getCellFields(entityClass),
|
9
|
-
};
|
10
|
-
}
|