@etsoo/react 1.4.57 → 1.4.61
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/app/ReactApp.d.ts +4 -0
- package/lib/app/ReactApp.js +4 -2
- package/lib/app/ServiceApp.js +3 -2
- package/lib/mu/pages/ViewPage.d.ts +31 -3
- package/lib/mu/pages/ViewPage.js +60 -2
- package/package.json +2 -2
- package/src/app/ReactApp.ts +4 -2
- package/src/app/ServiceApp.ts +4 -3
- package/src/mu/pages/ViewPage.tsx +140 -4
package/lib/app/ReactApp.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ import { IStateProps } from '../states/IState';
|
|
|
8
8
|
import { IPageData, PageAction, PageState } from '../states/PageState';
|
|
9
9
|
import { UserAction, UserState } from '../states/UserState';
|
|
10
10
|
import { InputDialogProps } from './InputDialogProps';
|
|
11
|
+
/**
|
|
12
|
+
* Global application
|
|
13
|
+
*/
|
|
14
|
+
export declare let globalApp: IReactApp<IAppSettings, any, IPageData>;
|
|
11
15
|
/**
|
|
12
16
|
* React app state detector
|
|
13
17
|
* Case 1: undefined, when refresh the whole page
|
package/lib/app/ReactApp.js
CHANGED
|
@@ -7,8 +7,10 @@ import { CultureState } from '../states/CultureState';
|
|
|
7
7
|
import { PageActionType, PageState } from '../states/PageState';
|
|
8
8
|
import { UserActionType, UserState } from '../states/UserState';
|
|
9
9
|
import { Labels } from './Labels';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Global application
|
|
12
|
+
*/
|
|
13
|
+
export let globalApp;
|
|
12
14
|
/**
|
|
13
15
|
* React app state detector
|
|
14
16
|
* Case 1: undefined, when refresh the whole page
|
package/lib/app/ServiceApp.js
CHANGED
|
@@ -234,11 +234,12 @@ export class ServiceApp extends ReactApp {
|
|
|
234
234
|
// Service user login
|
|
235
235
|
this.servicePassphrase =
|
|
236
236
|
(_a = this.decrypt(serviceUser.serviceDeviceId, this.settings.serviceId.toString())) !== null && _a !== void 0 ? _a : '';
|
|
237
|
-
// Keep = true, means service could hold the refresh token for long access
|
|
238
|
-
super.userLogin(user, refreshToken, true);
|
|
239
237
|
// Service user
|
|
240
238
|
this.serviceUser = serviceUser;
|
|
241
239
|
// Service API token
|
|
242
240
|
this.serviceApi.authorize(this.settings.authScheme, serviceUser.token);
|
|
241
|
+
// Keep = true, means service could hold the refresh token for long access
|
|
242
|
+
// Trigger Context change and serviceUser is ready then
|
|
243
|
+
super.userLogin(user, refreshToken, true);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
@@ -1,12 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
import { GridProps } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { CommonPageProps } from './CommonPageProps';
|
|
4
|
+
/**
|
|
5
|
+
* View page display field
|
|
6
|
+
*/
|
|
7
|
+
export interface ViewPageField<T extends {}> extends GridProps {
|
|
8
|
+
/**
|
|
9
|
+
* Data field
|
|
10
|
+
*/
|
|
11
|
+
data: keyof T | ((item: T) => React.ReactNode);
|
|
12
|
+
/**
|
|
13
|
+
* Label field
|
|
14
|
+
*/
|
|
15
|
+
label: string | (() => React.ReactNode);
|
|
16
|
+
}
|
|
17
|
+
declare type ViewPageFieldType<T> = (string & keyof T) | ViewPageField<T>;
|
|
3
18
|
/**
|
|
4
19
|
* View page props
|
|
5
20
|
*/
|
|
6
|
-
export interface ViewPageProps extends CommonPageProps {
|
|
21
|
+
export interface ViewPageProps<T extends {}> extends CommonPageProps {
|
|
22
|
+
/**
|
|
23
|
+
* Fields to display
|
|
24
|
+
*/
|
|
25
|
+
fields: ViewPageFieldType<T>[];
|
|
26
|
+
/**
|
|
27
|
+
* Load data
|
|
28
|
+
*/
|
|
29
|
+
loadData: () => PromiseLike<T | undefined>;
|
|
30
|
+
/**
|
|
31
|
+
* Support refresh
|
|
32
|
+
*/
|
|
33
|
+
supportRefresh?: boolean;
|
|
7
34
|
}
|
|
8
35
|
/**
|
|
9
36
|
* View page
|
|
10
37
|
* @param props Props
|
|
11
38
|
*/
|
|
12
|
-
export declare function ViewPage(props: ViewPageProps): JSX.Element;
|
|
39
|
+
export declare function ViewPage<T extends {}>(props: ViewPageProps<T>): JSX.Element;
|
|
40
|
+
export {};
|
package/lib/mu/pages/ViewPage.js
CHANGED
|
@@ -1,11 +1,69 @@
|
|
|
1
|
+
import { Grid, LinearProgress, Typography } from '@mui/material';
|
|
1
2
|
import React from 'react';
|
|
3
|
+
import { globalApp } from '../../app/ReactApp';
|
|
4
|
+
import { MUGlobal } from '../MUGlobal';
|
|
2
5
|
import { CommonPage } from './CommonPage';
|
|
6
|
+
function formatItemData(fieldData) {
|
|
7
|
+
if (fieldData instanceof Date)
|
|
8
|
+
return globalApp.formatDate(fieldData, 'd');
|
|
9
|
+
return new String(fieldData);
|
|
10
|
+
}
|
|
11
|
+
function getItemField(field, data) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
// Item data and label
|
|
14
|
+
let itemData, itemLabel, gridProps;
|
|
15
|
+
if (typeof field === 'object') {
|
|
16
|
+
// Destruct
|
|
17
|
+
const { data: fieldData, label: fieldLabel, ...rest } = field;
|
|
18
|
+
gridProps = rest;
|
|
19
|
+
// Field data
|
|
20
|
+
if (typeof fieldData === 'function')
|
|
21
|
+
itemData = fieldData(data);
|
|
22
|
+
else
|
|
23
|
+
itemData = formatItemData(formatItemData);
|
|
24
|
+
// Field label
|
|
25
|
+
itemLabel =
|
|
26
|
+
typeof fieldLabel === 'function'
|
|
27
|
+
? fieldLabel()
|
|
28
|
+
: (_a = globalApp.get(fieldLabel)) !== null && _a !== void 0 ? _a : fieldLabel;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
itemData = formatItemData(data[field]);
|
|
32
|
+
itemLabel = (_b = globalApp.get(field)) !== null && _b !== void 0 ? _b : field;
|
|
33
|
+
gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
|
|
34
|
+
}
|
|
35
|
+
return [itemData, itemLabel, gridProps];
|
|
36
|
+
}
|
|
3
37
|
/**
|
|
4
38
|
* View page
|
|
5
39
|
* @param props Props
|
|
6
40
|
*/
|
|
7
41
|
export function ViewPage(props) {
|
|
8
42
|
// Destruct
|
|
9
|
-
const { ...rest } = props;
|
|
10
|
-
|
|
43
|
+
const { children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, ...rest } = props;
|
|
44
|
+
// Data
|
|
45
|
+
const [data, setData] = React.useState();
|
|
46
|
+
// Load data
|
|
47
|
+
const onRefresh = async () => {
|
|
48
|
+
const result = await loadData();
|
|
49
|
+
if (result == null)
|
|
50
|
+
return;
|
|
51
|
+
setData(result);
|
|
52
|
+
};
|
|
53
|
+
return (React.createElement(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? onRefresh : undefined, onUpdate: supportRefresh ? undefined : onRefresh, ...rest, scrollContainer: global }, data == null ? (React.createElement(LinearProgress, null)) : (React.createElement(React.Fragment, null,
|
|
54
|
+
React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, sx: {
|
|
55
|
+
'.MuiTypography-subtitle2': { fontWeight: 'bold' }
|
|
56
|
+
} }, fields.map((field, index) => {
|
|
57
|
+
// Get data
|
|
58
|
+
const [itemData, itemLabel, gridProps] = getItemField(field, data);
|
|
59
|
+
if (itemData == null)
|
|
60
|
+
return undefined;
|
|
61
|
+
// Layout
|
|
62
|
+
return (React.createElement(Grid, { item: true, ...gridProps, key: index },
|
|
63
|
+
React.createElement(Typography, { variant: "caption", component: "div" },
|
|
64
|
+
itemLabel,
|
|
65
|
+
":"),
|
|
66
|
+
React.createElement(Typography, { variant: "subtitle2" }, itemData)));
|
|
67
|
+
})),
|
|
68
|
+
children))));
|
|
11
69
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.61",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@babel/cli": "^7.16.8",
|
|
80
|
-
"@babel/core": "^7.16.
|
|
80
|
+
"@babel/core": "^7.16.12",
|
|
81
81
|
"@babel/plugin-transform-runtime": "^7.16.10",
|
|
82
82
|
"@babel/preset-env": "^7.16.11",
|
|
83
83
|
"@babel/runtime-corejs3": "^7.16.8",
|
package/src/app/ReactApp.ts
CHANGED
|
@@ -34,8 +34,10 @@ import {
|
|
|
34
34
|
import { InputDialogProps } from './InputDialogProps';
|
|
35
35
|
import { Labels } from './Labels';
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Global application
|
|
39
|
+
*/
|
|
40
|
+
export let globalApp: IReactApp<IAppSettings, any, IPageData>;
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* React app state detector
|
package/src/app/ServiceApp.ts
CHANGED
|
@@ -333,13 +333,14 @@ export class ServiceApp<
|
|
|
333
333
|
this.settings.serviceId.toString()
|
|
334
334
|
) ?? '';
|
|
335
335
|
|
|
336
|
-
// Keep = true, means service could hold the refresh token for long access
|
|
337
|
-
super.userLogin(user, refreshToken, true);
|
|
338
|
-
|
|
339
336
|
// Service user
|
|
340
337
|
this.serviceUser = serviceUser;
|
|
341
338
|
|
|
342
339
|
// Service API token
|
|
343
340
|
this.serviceApi.authorize(this.settings.authScheme, serviceUser.token);
|
|
341
|
+
|
|
342
|
+
// Keep = true, means service could hold the refresh token for long access
|
|
343
|
+
// Trigger Context change and serviceUser is ready then
|
|
344
|
+
super.userLogin(user, refreshToken, true);
|
|
344
345
|
}
|
|
345
346
|
}
|
|
@@ -1,19 +1,155 @@
|
|
|
1
|
+
import { Grid, GridProps, LinearProgress, Typography } from '@mui/material';
|
|
1
2
|
import React from 'react';
|
|
3
|
+
import { globalApp } from '../../app/ReactApp';
|
|
4
|
+
import { MUGlobal } from '../MUGlobal';
|
|
2
5
|
import { CommonPage } from './CommonPage';
|
|
3
6
|
import { CommonPageProps } from './CommonPageProps';
|
|
4
7
|
|
|
8
|
+
/**
|
|
9
|
+
* View page display field
|
|
10
|
+
*/
|
|
11
|
+
export interface ViewPageField<T extends {}> extends GridProps {
|
|
12
|
+
/**
|
|
13
|
+
* Data field
|
|
14
|
+
*/
|
|
15
|
+
data: keyof T | ((item: T) => React.ReactNode);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Label field
|
|
19
|
+
*/
|
|
20
|
+
label: string | (() => React.ReactNode);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type ViewPageFieldType<T> = (string & keyof T) | ViewPageField<T>;
|
|
24
|
+
|
|
5
25
|
/**
|
|
6
26
|
* View page props
|
|
7
27
|
*/
|
|
8
|
-
export interface ViewPageProps extends CommonPageProps {
|
|
28
|
+
export interface ViewPageProps<T extends {}> extends CommonPageProps {
|
|
29
|
+
/**
|
|
30
|
+
* Fields to display
|
|
31
|
+
*/
|
|
32
|
+
fields: ViewPageFieldType<T>[];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Load data
|
|
36
|
+
*/
|
|
37
|
+
loadData: () => PromiseLike<T | undefined>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Support refresh
|
|
41
|
+
*/
|
|
42
|
+
supportRefresh?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function formatItemData(fieldData: unknown) {
|
|
46
|
+
if (fieldData instanceof Date) return globalApp.formatDate(fieldData, 'd');
|
|
47
|
+
return new String(fieldData);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getItemField<T>(
|
|
51
|
+
field: ViewPageFieldType<T>,
|
|
52
|
+
data: T
|
|
53
|
+
): [React.ReactNode, React.ReactNode, GridProps] {
|
|
54
|
+
// Item data and label
|
|
55
|
+
let itemData: React.ReactNode,
|
|
56
|
+
itemLabel: React.ReactNode,
|
|
57
|
+
gridProps: GridProps;
|
|
58
|
+
|
|
59
|
+
if (typeof field === 'object') {
|
|
60
|
+
// Destruct
|
|
61
|
+
const { data: fieldData, label: fieldLabel, ...rest } = field;
|
|
62
|
+
gridProps = rest;
|
|
63
|
+
|
|
64
|
+
// Field data
|
|
65
|
+
if (typeof fieldData === 'function') itemData = fieldData(data);
|
|
66
|
+
else itemData = formatItemData(formatItemData);
|
|
67
|
+
|
|
68
|
+
// Field label
|
|
69
|
+
itemLabel =
|
|
70
|
+
typeof fieldLabel === 'function'
|
|
71
|
+
? fieldLabel()
|
|
72
|
+
: globalApp.get<string>(fieldLabel) ?? fieldLabel;
|
|
73
|
+
} else {
|
|
74
|
+
itemData = formatItemData(data[field]);
|
|
75
|
+
itemLabel = globalApp.get<string>(field) ?? field;
|
|
76
|
+
gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return [itemData, itemLabel, gridProps];
|
|
80
|
+
}
|
|
9
81
|
|
|
10
82
|
/**
|
|
11
83
|
* View page
|
|
12
84
|
* @param props Props
|
|
13
85
|
*/
|
|
14
|
-
export function ViewPage(props: ViewPageProps) {
|
|
86
|
+
export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
15
87
|
// Destruct
|
|
16
|
-
const {
|
|
88
|
+
const {
|
|
89
|
+
children,
|
|
90
|
+
fields,
|
|
91
|
+
loadData,
|
|
92
|
+
paddings = MUGlobal.pagePaddings,
|
|
93
|
+
supportRefresh = true,
|
|
94
|
+
...rest
|
|
95
|
+
} = props;
|
|
96
|
+
|
|
97
|
+
// Data
|
|
98
|
+
const [data, setData] = React.useState<T>();
|
|
99
|
+
|
|
100
|
+
// Load data
|
|
101
|
+
const onRefresh = async () => {
|
|
102
|
+
const result = await loadData();
|
|
103
|
+
if (result == null) return;
|
|
104
|
+
setData(result);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<CommonPage
|
|
109
|
+
paddings={paddings}
|
|
110
|
+
onRefresh={supportRefresh ? onRefresh : undefined}
|
|
111
|
+
onUpdate={supportRefresh ? undefined : onRefresh}
|
|
112
|
+
{...rest}
|
|
113
|
+
scrollContainer={global}
|
|
114
|
+
>
|
|
115
|
+
{data == null ? (
|
|
116
|
+
<LinearProgress />
|
|
117
|
+
) : (
|
|
118
|
+
<React.Fragment>
|
|
119
|
+
<Grid
|
|
120
|
+
container
|
|
121
|
+
justifyContent="left"
|
|
122
|
+
spacing={paddings}
|
|
123
|
+
sx={{
|
|
124
|
+
'.MuiTypography-subtitle2': { fontWeight: 'bold' }
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
{fields.map((field, index) => {
|
|
128
|
+
// Get data
|
|
129
|
+
const [itemData, itemLabel, gridProps] =
|
|
130
|
+
getItemField(field, data);
|
|
131
|
+
|
|
132
|
+
if (itemData == null) return undefined;
|
|
17
133
|
|
|
18
|
-
|
|
134
|
+
// Layout
|
|
135
|
+
return (
|
|
136
|
+
<Grid item {...gridProps} key={index}>
|
|
137
|
+
<Typography
|
|
138
|
+
variant="caption"
|
|
139
|
+
component="div"
|
|
140
|
+
>
|
|
141
|
+
{itemLabel}:
|
|
142
|
+
</Typography>
|
|
143
|
+
<Typography variant="subtitle2">
|
|
144
|
+
{itemData}
|
|
145
|
+
</Typography>
|
|
146
|
+
</Grid>
|
|
147
|
+
);
|
|
148
|
+
})}
|
|
149
|
+
</Grid>
|
|
150
|
+
{children}
|
|
151
|
+
</React.Fragment>
|
|
152
|
+
)}
|
|
153
|
+
</CommonPage>
|
|
154
|
+
);
|
|
19
155
|
}
|