proje-react-panel 1.0.17-test3 → 1.0.17-test6
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/components/FormField.d.ts +5 -1
- package/dist/components/components/InnerForm.d.ts +7 -3
- package/dist/components/components/list/ListPage.d.ts +1 -1
- package/dist/components/pages/FormPage.d.ts +7 -2
- package/dist/decorators/form/Input.d.ts +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/types/AnyClass.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/components/FormField.tsx +13 -4
- package/src/components/components/InnerForm.tsx +26 -6
- package/src/components/components/list/Datagrid.tsx +80 -73
- package/src/components/components/list/ListPage.tsx +11 -13
- package/src/components/pages/FormPage.tsx +5 -1
- package/src/decorators/form/Input.ts +3 -1
- package/src/decorators/form/getFormFields.ts +1 -0
- package/src/styles/list.scss +3 -1
- package/src/types/AnyClass.ts +3 -1
@@ -40,86 +40,93 @@ export function Datagrid<T>({ data, listData, onRemoveItem }: DatagridProps<T>)
|
|
40
40
|
</tr>
|
41
41
|
</thead>
|
42
42
|
<tbody>
|
43
|
-
{data.map((item, index) =>
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
49
55
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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;
|
67
73
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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;
|
79
90
|
}
|
80
|
-
|
81
|
-
default:
|
82
|
-
render = value ? value.toString() : (cellOptions?.placeHolder ?? '-'); // Handles string type or default fallback
|
83
|
-
break;
|
84
|
-
}
|
85
|
-
/*
|
91
|
+
/*
|
86
92
|
if (cellOptions.linkTo) {
|
87
93
|
render = <Link to={cellOptions.linkTo(item)}>{formattedValue}</Link>;
|
88
94
|
}
|
89
95
|
*/
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
+
})}
|
123
130
|
</tbody>
|
124
131
|
</table>
|
125
132
|
)}
|
@@ -26,7 +26,7 @@ export interface PaginatedResponse<T> {
|
|
26
26
|
|
27
27
|
export type GetDataForList<T> = (params: GetDataParams) => Promise<PaginatedResponse<T>>;
|
28
28
|
|
29
|
-
|
29
|
+
function ListHeader<T extends AnyClass>({
|
30
30
|
listData,
|
31
31
|
filtered,
|
32
32
|
onFilterClick,
|
@@ -36,7 +36,7 @@ const ListHeader = <T extends AnyClass>({
|
|
36
36
|
filtered: boolean;
|
37
37
|
onFilterClick: () => void;
|
38
38
|
customHeader?: React.ReactNode;
|
39
|
-
})
|
39
|
+
}) {
|
40
40
|
const fields = useMemo(() => listData.cells.filter(cell => !!cell.filter), [listData.cells]);
|
41
41
|
|
42
42
|
const header = listData.list?.headers;
|
@@ -60,7 +60,7 @@ const ListHeader = <T extends AnyClass>({
|
|
60
60
|
</div>
|
61
61
|
</div>
|
62
62
|
);
|
63
|
-
}
|
63
|
+
}
|
64
64
|
|
65
65
|
export function ListPage<T extends AnyClass>({
|
66
66
|
model,
|
@@ -68,7 +68,7 @@ export function ListPage<T extends AnyClass>({
|
|
68
68
|
onRemoveItem,
|
69
69
|
customHeader,
|
70
70
|
}: {
|
71
|
-
model:
|
71
|
+
model: any;
|
72
72
|
getData: GetDataForList<T>;
|
73
73
|
customHeader?: React.ReactNode;
|
74
74
|
onRemoveItem?: (item: T) => Promise<void>;
|
@@ -151,15 +151,13 @@ export function ListPage<T extends AnyClass>({
|
|
151
151
|
data={data}
|
152
152
|
onRemoveItem={async (item: T) => {
|
153
153
|
if (onRemoveItem) {
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
},
|
162
|
-
});
|
154
|
+
if (
|
155
|
+
confirm('Are you sure you want to delete this item? This action cannot be undone.')
|
156
|
+
) {
|
157
|
+
await onRemoveItem(item);
|
158
|
+
//setData(data.filter((d: T) => d.id !== item.id));
|
159
|
+
await fetchData(pagination.page);
|
160
|
+
}
|
163
161
|
}
|
164
162
|
}}
|
165
163
|
/>
|
@@ -2,15 +2,17 @@ import React, { useMemo } from 'react';
|
|
2
2
|
import { InnerForm } from '../components';
|
3
3
|
import { AnyClass } from '../../types/AnyClass';
|
4
4
|
import { getFormFields } from '../../decorators/form/getFormFields';
|
5
|
+
import { InputOptions } from '../../decorators/form/Input';
|
5
6
|
|
6
7
|
export type GetDetailsDataFN<T> = (param: Record<string, string>) => Promise<T>;
|
7
8
|
export type OnSubmitFN<T> = (data: T) => Promise<T>;
|
8
9
|
|
9
10
|
export interface FormPageProps<T extends AnyClass> {
|
10
|
-
model: T
|
11
|
+
model: any; //TODO: use T not typeof T
|
11
12
|
getDetailsData?: GetDetailsDataFN<T>;
|
12
13
|
redirect?: string;
|
13
14
|
onSubmit: OnSubmitFN<T>;
|
15
|
+
onSelectPreloader?: (inputOptions: InputOptions) => Promise<{ label: string; value: string }[]>;
|
14
16
|
redirectBackOnSuccess?: boolean;
|
15
17
|
}
|
16
18
|
|
@@ -19,6 +21,7 @@ export function FormPage<T extends AnyClass>({
|
|
19
21
|
getDetailsData,
|
20
22
|
onSubmit,
|
21
23
|
redirect,
|
24
|
+
onSelectPreloader,
|
22
25
|
redirectBackOnSuccess = true,
|
23
26
|
...rest
|
24
27
|
}: FormPageProps<T>) {
|
@@ -29,6 +32,7 @@ export function FormPage<T extends AnyClass>({
|
|
29
32
|
onSubmit={onSubmit}
|
30
33
|
formOptions={formOptions}
|
31
34
|
redirectBackOnSuccess={redirectBackOnSuccess}
|
35
|
+
onSelectPreloader={onSelectPreloader}
|
32
36
|
/>
|
33
37
|
);
|
34
38
|
}
|
@@ -15,6 +15,7 @@ export interface InputOptions {
|
|
15
15
|
placeholder?: string;
|
16
16
|
cancelPasswordValidationOnEdit?: boolean;
|
17
17
|
options?: { value: string; label: string }[];
|
18
|
+
optionsPreload?: boolean;
|
18
19
|
nestedFields?: InputOptions[];
|
19
20
|
}
|
20
21
|
|
@@ -31,7 +32,8 @@ export function Input(options?: InputOptions): PropertyDecorator {
|
|
31
32
|
}
|
32
33
|
|
33
34
|
export function getInputFields<T extends AnyClass>(entityClass: T): InputOptions[] {
|
34
|
-
|
35
|
+
//TODO2: ANY IS NOT A GOOD SOLUTION, WE NEED TO FIND A BETTER WAY TO DO THIS
|
36
|
+
const prototype = (entityClass as any).prototype;
|
35
37
|
const inputFields: string[] = Reflect.getMetadata(INPUT_KEY, prototype) || [];
|
36
38
|
return inputFields.map(field => {
|
37
39
|
const fields = Reflect.getMetadata(`${INPUT_KEY.toString()}:${field}:options`, prototype) || {};
|
@@ -5,6 +5,7 @@ import { getFormConfiguration } from "./Form";
|
|
5
5
|
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
|
6
6
|
|
7
7
|
export function getFormFields<T extends AnyClass>(entityClass: T): FormOptions {
|
8
|
+
console.log(entityClass);
|
8
9
|
return {
|
9
10
|
resolver: classValidatorResolver(entityClass as any),
|
10
11
|
form: getFormConfiguration(entityClass),
|
package/src/styles/list.scss
CHANGED
package/src/types/AnyClass.ts
CHANGED