@pautena/react-design-system 0.1.2 → 0.2.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/README.md +4 -0
- package/dist/cjs/index.js +4 -259
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/generators/model-router/screens/add-screen.d.ts +1 -1
- package/dist/cjs/types/generators/model-router/screens/list-screen.d.ts +1 -1
- package/dist/cjs/types/generators/model-router/screens/screens.types.d.ts +20 -0
- package/dist/cjs/types/generators/model-router/screens/update-screen.d.ts +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/esm/index.js +4 -259
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/generators/model-router/screens/add-screen.d.ts +1 -1
- package/dist/esm/types/generators/model-router/screens/list-screen.d.ts +1 -1
- package/dist/esm/types/generators/model-router/screens/screens.types.d.ts +20 -0
- package/dist/esm/types/generators/model-router/screens/update-screen.d.ts +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/index.d.ts +52 -3
- package/package.json +13 -2
- package/src/components/app-bar/app-bar.stories.tsx +54 -0
- package/src/components/app-bar/app-bar.test.tsx +142 -0
- package/src/components/app-bar/app-bar.tsx +150 -0
- package/src/components/app-bar/app-bar.types.ts +17 -0
- package/src/components/app-bar/index.ts +3 -0
- package/src/components/app-bar/mini-app-bar/index.ts +1 -0
- package/src/components/app-bar/mini-app-bar/mini-app-bar.tsx +31 -0
- package/src/components/bullet/bullet.stories.tsx +43 -0
- package/src/components/bullet/bullet.test.tsx +24 -0
- package/src/components/bullet/bullet.tsx +30 -0
- package/src/components/bullet/index.ts +1 -0
- package/src/components/center-container/center-container.stories.tsx +50 -0
- package/src/components/center-container/center-container.test.tsx +16 -0
- package/src/components/center-container/center-container.tsx +32 -0
- package/src/components/center-container/index.ts +1 -0
- package/src/components/content/content.stories.tsx +23 -0
- package/src/components/content/content.test.tsx +26 -0
- package/src/components/content/content.tsx +11 -0
- package/src/components/content/content.types.ts +5 -0
- package/src/components/content/index.ts +2 -0
- package/src/components/drawer/__snapshots__/drawer.test.tsx.snap +20 -0
- package/src/components/drawer/drawer.context.ts +20 -0
- package/src/components/drawer/drawer.mixins.ts +24 -0
- package/src/components/drawer/drawer.mock.tsx +100 -0
- package/src/components/drawer/drawer.provider.tsx +23 -0
- package/src/components/drawer/drawer.test.tsx +97 -0
- package/src/components/drawer/drawer.tsx +30 -0
- package/src/components/drawer/drawer.types.ts +53 -0
- package/src/components/drawer/index.ts +5 -0
- package/src/components/drawer/mini-drawer/index.ts +1 -0
- package/src/components/drawer/mini-drawer/mini-drawer.stories.tsx +34 -0
- package/src/components/drawer/mini-drawer/mini-drawer.tsx +67 -0
- package/src/components/drawer-content/drawer-content.stories.tsx +29 -0
- package/src/components/drawer-content/drawer-content.test.tsx +34 -0
- package/src/components/drawer-content/drawer-content.tsx +18 -0
- package/src/components/drawer-content/index.ts +1 -0
- package/src/components/drawer-item/drawer-item.stories.tsx +62 -0
- package/src/components/drawer-item/drawer-item.test.tsx +119 -0
- package/src/components/drawer-item/drawer-item.tsx +71 -0
- package/src/components/drawer-item/index.ts +1 -0
- package/src/components/drawer-section/drawer-section.mock.tsx +39 -0
- package/src/components/drawer-section/drawer-section.stories.tsx +28 -0
- package/src/components/drawer-section/drawer-section.test.tsx +44 -0
- package/src/components/drawer-section/drawer-section.tsx +40 -0
- package/src/components/drawer-section/index.ts +1 -0
- package/src/components/header/header.dummy.ts +55 -0
- package/src/components/header/header.stories.tsx +116 -0
- package/src/components/header/header.test.tsx +159 -0
- package/src/components/header/header.tsx +121 -0
- package/src/components/header/header.types.ts +61 -0
- package/src/components/header/index.ts +2 -0
- package/src/components/index.ts +18 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/label/label.stories.tsx +49 -0
- package/src/components/label/label.test.tsx +30 -0
- package/src/components/label/label.tsx +60 -0
- package/src/components/link/index.ts +1 -0
- package/src/components/link/link.tsx +17 -0
- package/src/components/loading-area/index.ts +1 -0
- package/src/components/loading-area/loading-area.stories.tsx +17 -0
- package/src/components/loading-area/loading-area.test.tsx +11 -0
- package/src/components/loading-area/loading-area.tsx +13 -0
- package/src/components/placeholder/index.ts +1 -0
- package/src/components/placeholder/placeholder.mock.ts +15 -0
- package/src/components/placeholder/placeholder.stories.tsx +44 -0
- package/src/components/placeholder/placeholder.test.tsx +76 -0
- package/src/components/placeholder/placeholder.tsx +75 -0
- package/src/components/query-container/index.ts +1 -0
- package/src/components/query-container/query-container.stories.tsx +68 -0
- package/src/components/query-container/query-container.test.tsx +95 -0
- package/src/components/query-container/query-container.tsx +71 -0
- package/src/components/sign-in/index.ts +1 -0
- package/src/components/sign-in/sign-in.stories.tsx +36 -0
- package/src/components/sign-in/sign-in.test.tsx +95 -0
- package/src/components/sign-in/sign-in.tsx +97 -0
- package/src/components/tab/index.ts +2 -0
- package/src/components/tab/tab-card/index.ts +1 -0
- package/src/components/tab/tab-card/tab-card.dummy.tsx +30 -0
- package/src/components/tab/tab-card/tab-card.stories.tsx +22 -0
- package/src/components/tab/tab-card/tab-card.test.tsx +53 -0
- package/src/components/tab/tab-card/tab-card.tsx +27 -0
- package/src/components/tab/tab-panel/index.ts +1 -0
- package/src/components/tab/tab-panel/tab-panel.test.tsx +26 -0
- package/src/components/tab/tab-panel/tab-panel.tsx +27 -0
- package/src/components/table/enhanced-remote-table/enhanced-remote-table.mock.tsx +27 -0
- package/src/components/table/enhanced-remote-table/enhanced-remote-table.stories.tsx +24 -0
- package/src/components/table/enhanced-remote-table/enhanced-remote-table.test.tsx +77 -0
- package/src/components/table/enhanced-remote-table/enhanced-remote-table.tsx +74 -0
- package/src/components/table/enhanced-remote-table/index.ts +1 -0
- package/src/components/table/enhanced-table/enhanced-table-head.tsx +58 -0
- package/src/components/table/enhanced-table/enhanced-table.mock.tsx +93 -0
- package/src/components/table/enhanced-table/enhanced-table.stories.tsx +21 -0
- package/src/components/table/enhanced-table/enhanced-table.test.tsx +107 -0
- package/src/components/table/enhanced-table/enhanced-table.tsx +136 -0
- package/src/components/table/enhanced-table/index.ts +2 -0
- package/src/components/table/index.ts +2 -0
- package/src/components/table-list/index.ts +1 -0
- package/src/components/table-list/table-list.stories.tsx +75 -0
- package/src/components/table-list/table-list.test.tsx +291 -0
- package/src/components/table-list/table-list.tsx +127 -0
- package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +35 -0
- package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +26 -0
- package/src/components/value-displays/group-value-card/group-value-card.test.tsx +58 -0
- package/src/components/value-displays/group-value-card/group-value-card.tsx +63 -0
- package/src/components/value-displays/group-value-card/index.ts +1 -0
- package/src/components/value-displays/index.ts +4 -0
- package/src/components/value-displays/value-boolean/index.ts +1 -0
- package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +25 -0
- package/src/components/value-displays/value-boolean/value-boolean.test.tsx +27 -0
- package/src/components/value-displays/value-boolean/value-boolean.tsx +33 -0
- package/src/components/value-displays/value-card/index.ts +1 -0
- package/src/components/value-displays/value-card/value-card.stories.tsx +22 -0
- package/src/components/value-displays/value-card/value-card.test.tsx +18 -0
- package/src/components/value-displays/value-card/value-card.tsx +12 -0
- package/src/components/value-displays/value-text/index.ts +1 -0
- package/src/components/value-displays/value-text/value-test.test.tsx +21 -0
- package/src/components/value-displays/value-text/value-text.stories.tsx +26 -0
- package/src/components/value-displays/value-text/value-text.tsx +32 -0
- package/src/generators/generators.mock.ts +238 -0
- package/src/generators/generators.model.ts +46 -0
- package/src/generators/index.ts +4 -0
- package/src/generators/model-form/index.ts +1 -0
- package/src/generators/model-form/model-form.stories.tsx +30 -0
- package/src/generators/model-form/model-form.test.tsx +100 -0
- package/src/generators/model-form/model-form.tsx +97 -0
- package/src/generators/model-router/index.ts +1 -0
- package/src/generators/model-router/model-router.test.tsx +831 -0
- package/src/generators/model-router/model-router.tsx +30 -0
- package/src/generators/model-router/model-router.types.ts +14 -0
- package/src/generators/model-router/screens/add-screen.tsx +70 -0
- package/src/generators/model-router/screens/details-screen.tsx +62 -0
- package/src/generators/model-router/screens/index.ts +4 -0
- package/src/generators/model-router/screens/list-screen.tsx +125 -0
- package/src/generators/model-router/screens/screens.types.ts +38 -0
- package/src/generators/model-router/screens/update-screen.tsx +97 -0
- package/src/generators/model-router/stories/details-screen.stories.tsx +38 -0
- package/src/generators/model-router/stories/list-screen.stories.tsx +96 -0
- package/src/generators/model-router/stories/model-router.stories.tsx +176 -0
- package/src/generators/model-router/stories/templates.tsx +39 -0
- package/src/generators/object-details/index.ts +1 -0
- package/src/generators/object-details/object-details.stories.tsx +20 -0
- package/src/generators/object-details/object-details.test.tsx +21 -0
- package/src/generators/object-details/object-details.tsx +76 -0
- package/src/index.ts +5 -0
- package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.stories.tsx +28 -0
- package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.test.tsx +30 -0
- package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.tsx +37 -0
- package/src/layouts/app-bar-with-drawer-layout/index.ts +1 -0
- package/src/layouts/header-layout/header-layout.stories.tsx +204 -0
- package/src/layouts/header-layout/header-layout.test.tsx +37 -0
- package/src/layouts/header-layout/header-layout.tsx +23 -0
- package/src/layouts/header-layout/index.ts +1 -0
- package/src/layouts/index.ts +2 -0
- package/src/providers/index.ts +2 -0
- package/src/providers/notification-center/index.ts +2 -0
- package/src/providers/notification-center/notification-center.context.ts +37 -0
- package/src/providers/notification-center/notification-center.provider.tsx +51 -0
- package/src/providers/notification-center/notification-center.stories.tsx +52 -0
- package/src/providers/notification-center/notification-center.test.tsx +112 -0
- package/src/providers/tab-provider/index.ts +2 -0
- package/src/providers/tab-provider/tab-provider.context.ts +8 -0
- package/src/providers/tab-provider/tab-provider.provider.tsx +13 -0
- package/src/storybook.tsx +90 -0
- package/src/tests/assertions.ts +76 -0
- package/src/tests/components.tsx +60 -0
- package/src/tests/content-placeholder.stories.tsx +16 -0
- package/src/tests/index.ts +3 -0
- package/src/tests/skeleton-card.stories.tsx +18 -0
- package/src/tests/testing-library.tsx +65 -0
- package/src/utils/arrays.test.ts +9 -0
- package/src/utils/arrays.ts +7 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/theme.ts +11 -0
- package/.prettierrc.js +0 -5
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Routes, Route } from "react-router-dom";
|
|
3
|
+
import { BasicModelInstance } from "../generators.model";
|
|
4
|
+
import {
|
|
5
|
+
AddScreen,
|
|
6
|
+
AddScreenProps,
|
|
7
|
+
DetailsScreen,
|
|
8
|
+
DetailsScreenProps,
|
|
9
|
+
ListScreen,
|
|
10
|
+
ListScreenProps,
|
|
11
|
+
UpdateScreen,
|
|
12
|
+
UpdateScreenProps,
|
|
13
|
+
} from "./screens";
|
|
14
|
+
|
|
15
|
+
export type ModelRouterProps<T extends BasicModelInstance> = DetailsScreenProps<T> &
|
|
16
|
+
ListScreenProps<T> &
|
|
17
|
+
AddScreenProps<T> &
|
|
18
|
+
UpdateScreenProps<T>;
|
|
19
|
+
|
|
20
|
+
export const ModelRouter = <T extends BasicModelInstance>(props: ModelRouterProps<T>) => {
|
|
21
|
+
const { updateFeature, addFeature, detailsFeature } = props;
|
|
22
|
+
return (
|
|
23
|
+
<Routes>
|
|
24
|
+
<Route path="" element={<ListScreen {...props} />} />
|
|
25
|
+
{detailsFeature && <Route path=":id" element={<DetailsScreen {...props} />} />}
|
|
26
|
+
{addFeature && <Route path="add" element={<AddScreen {...props} />} />}
|
|
27
|
+
{updateFeature && <Route path=":id/update" element={<UpdateScreen {...props} />} />}
|
|
28
|
+
</Routes>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RequestState {
|
|
2
|
+
idle?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
error?: string;
|
|
5
|
+
success?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const IdleRequest: RequestState = {
|
|
9
|
+
idle: true,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const LoadingRequest: RequestState = {
|
|
13
|
+
loading: true,
|
|
14
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useNavigate } from "react-router-dom";
|
|
3
|
+
import { Header, Content } from "~/components";
|
|
4
|
+
import { BasicModelInstance, ModelForm } from "~/generators";
|
|
5
|
+
import { HeaderLayout } from "../../../layouts";
|
|
6
|
+
import { useNotificationCenter } from "../../../providers";
|
|
7
|
+
import { RequestState } from "../model-router.types";
|
|
8
|
+
import { BaseScreenProps } from "./screens.types";
|
|
9
|
+
|
|
10
|
+
export interface AddScreenProps<T extends BasicModelInstance> extends BaseScreenProps {
|
|
11
|
+
/**
|
|
12
|
+
* Callback executed when the user wants to
|
|
13
|
+
* add a new item
|
|
14
|
+
*/
|
|
15
|
+
onSubmitNewItem: (obj: T) => void;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Current status of the request to retrieve
|
|
19
|
+
* add a new item
|
|
20
|
+
*/
|
|
21
|
+
newItemRequest: RequestState;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const AddScreen = <T extends BasicModelInstance>({
|
|
25
|
+
model,
|
|
26
|
+
modelName,
|
|
27
|
+
basePath = "",
|
|
28
|
+
onSubmitNewItem,
|
|
29
|
+
newItemRequest,
|
|
30
|
+
}: AddScreenProps<T>) => {
|
|
31
|
+
const navigate = useNavigate();
|
|
32
|
+
const { show } = useNotificationCenter();
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (newItemRequest.success) {
|
|
36
|
+
show({ message: "Item added successfully", severity: "success" });
|
|
37
|
+
navigate(`${basePath}/`);
|
|
38
|
+
}
|
|
39
|
+
}, [newItemRequest.success]);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (newItemRequest.error) {
|
|
43
|
+
show({ title: "We had an error", message: newItemRequest.error, severity: "error" });
|
|
44
|
+
}
|
|
45
|
+
}, [newItemRequest.error]);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<HeaderLayout loading={newItemRequest.loading}>
|
|
49
|
+
<Header
|
|
50
|
+
title={`Add ${modelName}`}
|
|
51
|
+
preset="default"
|
|
52
|
+
breadcrumbs={[
|
|
53
|
+
{
|
|
54
|
+
id: "list",
|
|
55
|
+
text: modelName,
|
|
56
|
+
link: "/",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "add",
|
|
60
|
+
text: `Add new ${modelName}`,
|
|
61
|
+
link: "/add",
|
|
62
|
+
},
|
|
63
|
+
]}
|
|
64
|
+
/>
|
|
65
|
+
<Content>
|
|
66
|
+
<ModelForm model={model} saveButtonText="Save" onSubmit={onSubmitNewItem} />
|
|
67
|
+
</Content>
|
|
68
|
+
</HeaderLayout>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useParams } from "react-router-dom";
|
|
3
|
+
import { RequestState } from "../model-router.types";
|
|
4
|
+
import { Content, Header } from "~/components";
|
|
5
|
+
import { HeaderLayout } from "~/layouts";
|
|
6
|
+
import { BaseScreenProps } from "./screens.types";
|
|
7
|
+
import { BasicModelInstance, ObjectDetails } from "~/generators";
|
|
8
|
+
|
|
9
|
+
export interface DetailsScreenProps<T extends BasicModelInstance> extends BaseScreenProps {
|
|
10
|
+
/**
|
|
11
|
+
* Callback executed each time we want
|
|
12
|
+
* the details information of an item
|
|
13
|
+
*/
|
|
14
|
+
onRequestItem: (id: string) => void;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Current status of the request to retrieve
|
|
18
|
+
* an item
|
|
19
|
+
*/
|
|
20
|
+
itemRequest: RequestState;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Item to be displayed
|
|
24
|
+
*/
|
|
25
|
+
detailsItem?: T;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const DetailsScreen = <T extends BasicModelInstance>({
|
|
29
|
+
model,
|
|
30
|
+
modelName,
|
|
31
|
+
onRequestItem,
|
|
32
|
+
itemRequest,
|
|
33
|
+
detailsItem,
|
|
34
|
+
}: DetailsScreenProps<T>) => {
|
|
35
|
+
const { id = "" } = useParams();
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
onRequestItem(id);
|
|
39
|
+
}, [id]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<HeaderLayout loading={itemRequest.loading}>
|
|
43
|
+
<Header
|
|
44
|
+
title={id}
|
|
45
|
+
preset="default"
|
|
46
|
+
breadcrumbs={[
|
|
47
|
+
{
|
|
48
|
+
id: "list",
|
|
49
|
+
text: modelName,
|
|
50
|
+
link: "/",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "detail",
|
|
54
|
+
text: id,
|
|
55
|
+
link: `/${id}`,
|
|
56
|
+
},
|
|
57
|
+
]}
|
|
58
|
+
/>
|
|
59
|
+
<Content>{detailsItem && <ObjectDetails model={model} instance={detailsItem} />}</Content>
|
|
60
|
+
</HeaderLayout>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useNavigate } from "react-router-dom";
|
|
3
|
+
import { Content, Header, HeaderAction, TableList, TableRowOption } from "~/components";
|
|
4
|
+
import { BasicModelInstance } from "~/generators";
|
|
5
|
+
import { HeaderLayout } from "../../../layouts";
|
|
6
|
+
import { RequestState } from "../model-router.types";
|
|
7
|
+
import { BaseScreenProps } from "./screens.types";
|
|
8
|
+
|
|
9
|
+
export interface ListScreenProps<T extends BasicModelInstance> extends BaseScreenProps {
|
|
10
|
+
/**
|
|
11
|
+
* Callback executed each time the list screen
|
|
12
|
+
* requests for a data update
|
|
13
|
+
*/
|
|
14
|
+
onRequestList: () => void;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List of items to be displayed in the list screen
|
|
18
|
+
*/
|
|
19
|
+
listData: T[];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Callback executed when the user clicks an option
|
|
23
|
+
* to delete an item
|
|
24
|
+
*/
|
|
25
|
+
onClickDeleteItem: (item: T) => void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Current status of the request to retrieve
|
|
29
|
+
* the list items
|
|
30
|
+
*/
|
|
31
|
+
listRequest: RequestState;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Current status of the request to delete
|
|
35
|
+
* an item
|
|
36
|
+
*/
|
|
37
|
+
deleteRequest: RequestState;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const ListScreen = <T extends BasicModelInstance>({
|
|
41
|
+
model,
|
|
42
|
+
modelName,
|
|
43
|
+
listData,
|
|
44
|
+
listRequest,
|
|
45
|
+
deleteRequest,
|
|
46
|
+
basePath = "",
|
|
47
|
+
deleteFeature = true,
|
|
48
|
+
updateFeature = true,
|
|
49
|
+
addFeature = true,
|
|
50
|
+
detailsFeature = true,
|
|
51
|
+
onRequestList,
|
|
52
|
+
onClickDeleteItem,
|
|
53
|
+
}: ListScreenProps<T>) => {
|
|
54
|
+
const navigate = useNavigate();
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
onRequestList();
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
const handleClickListItem = detailsFeature
|
|
61
|
+
? (item: T) => {
|
|
62
|
+
navigate(`${basePath}/${item.id}`);
|
|
63
|
+
}
|
|
64
|
+
: undefined;
|
|
65
|
+
|
|
66
|
+
const handleClickListOption = (optionId: "edit" | "remove", item: T) => {
|
|
67
|
+
if (optionId === "edit") {
|
|
68
|
+
navigate(`${basePath}/${item.id}/update`);
|
|
69
|
+
} else {
|
|
70
|
+
onClickDeleteItem(item);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const options: TableRowOption<T>[] = [];
|
|
75
|
+
|
|
76
|
+
updateFeature &&
|
|
77
|
+
options.push({
|
|
78
|
+
id: "edit",
|
|
79
|
+
label: "Edit",
|
|
80
|
+
onClick: (item: T) => handleClickListOption("edit", item),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
deleteFeature &&
|
|
84
|
+
options.push({
|
|
85
|
+
id: "remove",
|
|
86
|
+
label: "Remove",
|
|
87
|
+
onClick: (item: T) => handleClickListOption("remove", item),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const actions: HeaderAction[] = [];
|
|
91
|
+
|
|
92
|
+
addFeature &&
|
|
93
|
+
actions.push({
|
|
94
|
+
id: "add",
|
|
95
|
+
text: "Add",
|
|
96
|
+
href: `${basePath}/add`,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<HeaderLayout loading={listRequest.loading || deleteRequest.loading}>
|
|
101
|
+
<Header
|
|
102
|
+
title={modelName}
|
|
103
|
+
preset="default"
|
|
104
|
+
actions={actions.length > 0 ? actions : undefined}
|
|
105
|
+
/>
|
|
106
|
+
<Content>
|
|
107
|
+
<TableList
|
|
108
|
+
columns={model.fields
|
|
109
|
+
.filter(({ listable }) => listable)
|
|
110
|
+
.map(({ id, name, type }) => ({
|
|
111
|
+
disablePadding: false,
|
|
112
|
+
id,
|
|
113
|
+
label: name,
|
|
114
|
+
numeric: type === "number",
|
|
115
|
+
sort: false,
|
|
116
|
+
}))}
|
|
117
|
+
data={listData}
|
|
118
|
+
defaultSort={model.fields[0].id}
|
|
119
|
+
onClick={handleClickListItem}
|
|
120
|
+
options={options.length > 0 ? options : undefined}
|
|
121
|
+
/>
|
|
122
|
+
</Content>
|
|
123
|
+
</HeaderLayout>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Model } from "../../generators.model";
|
|
2
|
+
|
|
3
|
+
export interface BaseScreenProps {
|
|
4
|
+
/**
|
|
5
|
+
* UI-friendly string that represents the model
|
|
6
|
+
*/
|
|
7
|
+
modelName: string;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Structure that represents the fields of the model
|
|
11
|
+
*/
|
|
12
|
+
model: Model;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Path to attach before each internal ModelRouter path
|
|
16
|
+
*/
|
|
17
|
+
basePath?: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* If true delete features are enabled
|
|
21
|
+
*/
|
|
22
|
+
deleteFeature?: boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* If true update features are enabled
|
|
26
|
+
*/
|
|
27
|
+
updateFeature?: boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* If true add features are enabled
|
|
31
|
+
*/
|
|
32
|
+
addFeature?: boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* If true details features are enabled
|
|
36
|
+
*/
|
|
37
|
+
detailsFeature?: boolean;
|
|
38
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useNavigate, useParams } from "react-router-dom";
|
|
3
|
+
import { Content, Header } from "~/components";
|
|
4
|
+
import { BasicModelInstance, ModelForm } from "~/generators";
|
|
5
|
+
import { HeaderLayout } from "../../../layouts";
|
|
6
|
+
import { useNotificationCenter } from "../../../providers";
|
|
7
|
+
import { RequestState } from "../model-router.types";
|
|
8
|
+
import { BaseScreenProps } from "./screens.types";
|
|
9
|
+
|
|
10
|
+
export interface UpdateScreenProps<T extends BasicModelInstance> extends BaseScreenProps {
|
|
11
|
+
/**
|
|
12
|
+
* Callback executed when the user wants to update
|
|
13
|
+
* an item
|
|
14
|
+
*/
|
|
15
|
+
onSubmitUpdateItem: (obj: T) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Current status of the request to update an item
|
|
18
|
+
*/
|
|
19
|
+
submitUpdateItemRequest: RequestState;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Current status of the request to retrieve
|
|
23
|
+
* the item to be updated
|
|
24
|
+
*/
|
|
25
|
+
updateItemRequest: RequestState;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Callback executed to retrive the item that
|
|
29
|
+
* has to going tobe updated
|
|
30
|
+
*/
|
|
31
|
+
onRequestUpdateItem: (id: string) => void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Item that is going to be updated
|
|
35
|
+
*/
|
|
36
|
+
updateItem?: T;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const UpdateScreen = <T extends BasicModelInstance>({
|
|
40
|
+
model,
|
|
41
|
+
modelName,
|
|
42
|
+
basePath = "",
|
|
43
|
+
submitUpdateItemRequest,
|
|
44
|
+
updateItemRequest,
|
|
45
|
+
updateItem,
|
|
46
|
+
onSubmitUpdateItem,
|
|
47
|
+
onRequestUpdateItem,
|
|
48
|
+
}: UpdateScreenProps<T>) => {
|
|
49
|
+
const { id = "" } = useParams();
|
|
50
|
+
const navigate = useNavigate();
|
|
51
|
+
const { show } = useNotificationCenter();
|
|
52
|
+
const loading = updateItemRequest.loading || submitUpdateItemRequest.loading;
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
onRequestUpdateItem(id);
|
|
56
|
+
}, [id]);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (submitUpdateItemRequest.success) {
|
|
60
|
+
show({
|
|
61
|
+
title: "Item updated",
|
|
62
|
+
message: `The item ${id} has been updated successfully`,
|
|
63
|
+
severity: "success",
|
|
64
|
+
});
|
|
65
|
+
navigate(`${basePath}/`);
|
|
66
|
+
}
|
|
67
|
+
}, [submitUpdateItemRequest.success]);
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<HeaderLayout loading={loading}>
|
|
71
|
+
<Header
|
|
72
|
+
title={`Edit ${id}`}
|
|
73
|
+
preset="default"
|
|
74
|
+
breadcrumbs={[
|
|
75
|
+
{
|
|
76
|
+
id: "list",
|
|
77
|
+
text: modelName,
|
|
78
|
+
link: "/",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "update",
|
|
82
|
+
text: `Edit ${id}`,
|
|
83
|
+
link: `/${id}/update`,
|
|
84
|
+
},
|
|
85
|
+
]}
|
|
86
|
+
/>
|
|
87
|
+
<Content>
|
|
88
|
+
<ModelForm
|
|
89
|
+
model={model}
|
|
90
|
+
initialValues={updateItem}
|
|
91
|
+
saveButtonText="Save"
|
|
92
|
+
onSubmit={onSubmitUpdateItem}
|
|
93
|
+
/>
|
|
94
|
+
</Content>
|
|
95
|
+
</HeaderLayout>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ComponentMeta } from "@storybook/react";
|
|
2
|
+
import { withNotificationCenter, createTemplate, withActionRouter } from "../../../storybook";
|
|
3
|
+
import { item1 } from "./templates";
|
|
4
|
+
import { DetailsScreen } from "../screens";
|
|
5
|
+
import { mockModel } from "../../generators.mock";
|
|
6
|
+
import { IdleRequest, LoadingRequest } from "../model-router.types";
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: "Generators/ModelRouter/DetailsScreen",
|
|
10
|
+
component: DetailsScreen,
|
|
11
|
+
decorators: [
|
|
12
|
+
withActionRouter({
|
|
13
|
+
location: `/${item1.id}`,
|
|
14
|
+
path: "/:id",
|
|
15
|
+
}),
|
|
16
|
+
withNotificationCenter,
|
|
17
|
+
],
|
|
18
|
+
parameters: {
|
|
19
|
+
layout: "fullscreen",
|
|
20
|
+
},
|
|
21
|
+
} as ComponentMeta<typeof DetailsScreen>;
|
|
22
|
+
|
|
23
|
+
const Template = createTemplate(DetailsScreen);
|
|
24
|
+
|
|
25
|
+
export const Loading = Template.bind({});
|
|
26
|
+
Loading.args = {
|
|
27
|
+
modelName: "Items",
|
|
28
|
+
model: mockModel,
|
|
29
|
+
itemRequest: LoadingRequest,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Details = Template.bind({});
|
|
33
|
+
Details.args = {
|
|
34
|
+
modelName: "Items",
|
|
35
|
+
model: mockModel,
|
|
36
|
+
itemRequest: IdleRequest,
|
|
37
|
+
detailsItem: item1,
|
|
38
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ComponentMeta } from "@storybook/react";
|
|
2
|
+
import { withActionRouter, withNotificationCenter } from "../../../storybook";
|
|
3
|
+
import { IdleRequest, LoadingRequest } from "../model-router.types";
|
|
4
|
+
import { data } from "./templates";
|
|
5
|
+
import { createTemplate } from "../../../storybook";
|
|
6
|
+
import { ListScreen } from "../screens";
|
|
7
|
+
import { mockModel } from "../../generators.mock";
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: "Generators/ModelRouter/ListScreen",
|
|
11
|
+
component: ListScreen,
|
|
12
|
+
decorators: [withActionRouter(), withNotificationCenter],
|
|
13
|
+
parameters: {
|
|
14
|
+
layout: "fullscreen",
|
|
15
|
+
},
|
|
16
|
+
} as ComponentMeta<typeof ListScreen>;
|
|
17
|
+
|
|
18
|
+
const Template = createTemplate(ListScreen);
|
|
19
|
+
|
|
20
|
+
export const ListLoading = Template.bind({});
|
|
21
|
+
ListLoading.args = {
|
|
22
|
+
modelName: "Items",
|
|
23
|
+
model: mockModel,
|
|
24
|
+
listData: data,
|
|
25
|
+
listRequest: LoadingRequest,
|
|
26
|
+
deleteRequest: IdleRequest,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const DeleteLoading = Template.bind({});
|
|
30
|
+
DeleteLoading.args = {
|
|
31
|
+
modelName: "Items",
|
|
32
|
+
model: mockModel,
|
|
33
|
+
listData: data,
|
|
34
|
+
listRequest: IdleRequest,
|
|
35
|
+
deleteRequest: LoadingRequest,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const List = Template.bind({});
|
|
39
|
+
List.args = {
|
|
40
|
+
modelName: "Items",
|
|
41
|
+
model: mockModel,
|
|
42
|
+
listData: data,
|
|
43
|
+
listRequest: IdleRequest,
|
|
44
|
+
deleteRequest: IdleRequest,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const WithoutDeleteFeature = Template.bind({});
|
|
48
|
+
WithoutDeleteFeature.args = {
|
|
49
|
+
modelName: "Items",
|
|
50
|
+
model: mockModel,
|
|
51
|
+
listData: data,
|
|
52
|
+
listRequest: IdleRequest,
|
|
53
|
+
deleteRequest: IdleRequest,
|
|
54
|
+
deleteFeature: false,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const WithoutUpdateFeature = Template.bind({});
|
|
58
|
+
WithoutUpdateFeature.args = {
|
|
59
|
+
modelName: "Items",
|
|
60
|
+
model: mockModel,
|
|
61
|
+
listData: data,
|
|
62
|
+
listRequest: IdleRequest,
|
|
63
|
+
deleteRequest: IdleRequest,
|
|
64
|
+
updateFeature: false,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const WithoutDeleteAndUpdateFeature = Template.bind({});
|
|
68
|
+
WithoutDeleteAndUpdateFeature.args = {
|
|
69
|
+
modelName: "Items",
|
|
70
|
+
model: mockModel,
|
|
71
|
+
listData: data,
|
|
72
|
+
listRequest: IdleRequest,
|
|
73
|
+
deleteRequest: IdleRequest,
|
|
74
|
+
deleteFeature: false,
|
|
75
|
+
updateFeature: false,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const WithoutAddFeature = Template.bind({});
|
|
79
|
+
WithoutAddFeature.args = {
|
|
80
|
+
modelName: "Items",
|
|
81
|
+
model: mockModel,
|
|
82
|
+
listData: data,
|
|
83
|
+
listRequest: IdleRequest,
|
|
84
|
+
deleteRequest: IdleRequest,
|
|
85
|
+
addFeature: false,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const WithoutDetailsFeature = Template.bind({});
|
|
89
|
+
WithoutDetailsFeature.args = {
|
|
90
|
+
modelName: "Items",
|
|
91
|
+
model: mockModel,
|
|
92
|
+
listData: data,
|
|
93
|
+
listRequest: IdleRequest,
|
|
94
|
+
deleteRequest: IdleRequest,
|
|
95
|
+
detailsFeature: false,
|
|
96
|
+
};
|