@etsoo/react 1.5.11 → 1.5.15
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/Labels.d.ts +1 -0
- package/lib/app/Labels.js +1 -0
- package/lib/app/ReactApp.d.ts +0 -13
- package/lib/app/ReactApp.js +5 -28
- package/lib/app/ServiceApp.d.ts +6 -5
- package/lib/app/ServiceApp.js +14 -7
- package/lib/app/Utils.d.ts +1 -1
- package/lib/app/Utils.js +2 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/mu/BackButton.d.ts +13 -0
- package/lib/mu/BackButton.js +32 -0
- package/lib/mu/BridgeCloseButton.d.ts +5 -1
- package/lib/mu/BridgeCloseButton.js +5 -9
- package/lib/mu/pages/CommonPage.js +4 -2
- package/lib/mu/pages/CommonPageProps.d.ts +5 -1
- package/lib/mu/pages/EditPage.d.ts +5 -0
- package/lib/mu/pages/EditPage.js +4 -2
- package/lib/mu/pages/ViewPage.d.ts +4 -0
- package/lib/mu/pages/ViewPage.js +13 -3
- package/package.json +2 -2
- package/src/app/Labels.ts +1 -0
- package/src/app/ReactApp.ts +8 -33
- package/src/app/ServiceApp.ts +16 -7
- package/src/app/Utils.ts +4 -2
- package/src/index.ts +1 -0
- package/src/mu/BackButton.tsx +53 -0
- package/src/mu/BridgeCloseButton.tsx +17 -16
- package/src/mu/pages/CommonPage.tsx +5 -0
- package/src/mu/pages/CommonPageProps.ts +6 -1
- package/src/mu/pages/EditPage.tsx +9 -0
- package/src/mu/pages/ViewPage.tsx +36 -1
package/lib/app/Labels.d.ts
CHANGED
package/lib/app/Labels.js
CHANGED
package/lib/app/ReactApp.d.ts
CHANGED
|
@@ -108,19 +108,6 @@ export declare class ReactApp<S extends IAppSettings, D extends IUser, P extends
|
|
|
108
108
|
* @param name Application name
|
|
109
109
|
*/
|
|
110
110
|
constructor(settings: S, name: string);
|
|
111
|
-
/**
|
|
112
|
-
* Get parsed Url under bridge host
|
|
113
|
-
* @param url Url
|
|
114
|
-
* @returns Parsed Url
|
|
115
|
-
*/
|
|
116
|
-
protected getHostUrl(url: string): string;
|
|
117
|
-
/**
|
|
118
|
-
* Get parsed Url under bridge host
|
|
119
|
-
* @param url Url
|
|
120
|
-
* @param name App name in the host environment
|
|
121
|
-
* @returns Parsed Url
|
|
122
|
-
*/
|
|
123
|
-
protected getHostUrlBase(url: string, name: string): string;
|
|
124
111
|
/**
|
|
125
112
|
* Override alert action result
|
|
126
113
|
* @param result Action result
|
package/lib/app/ReactApp.js
CHANGED
|
@@ -26,8 +26,8 @@ export function ReactAppStateDetector(props) {
|
|
|
26
26
|
// Destruct
|
|
27
27
|
const { targetFields, update } = props;
|
|
28
28
|
// Context
|
|
29
|
-
const { state } = globalApp == null
|
|
30
|
-
? {
|
|
29
|
+
const { state = {} } = globalApp == null
|
|
30
|
+
? {}
|
|
31
31
|
: React.useContext(globalApp.userState.context);
|
|
32
32
|
// Ready
|
|
33
33
|
React.useEffect(() => {
|
|
@@ -66,9 +66,9 @@ export class ReactApp extends CoreApp {
|
|
|
66
66
|
*/
|
|
67
67
|
this.userState = new UserState();
|
|
68
68
|
this.history =
|
|
69
|
-
|
|
70
|
-
?
|
|
71
|
-
:
|
|
69
|
+
BridgeUtils.host == null
|
|
70
|
+
? undefined
|
|
71
|
+
: Utils.getMemoryHistory(BridgeUtils.host.getStartUrl());
|
|
72
72
|
this.cultureState = new CultureState(settings.currentCulture);
|
|
73
73
|
this.pageState = new PageState();
|
|
74
74
|
globalApp = this;
|
|
@@ -91,29 +91,6 @@ export class ReactApp extends CoreApp {
|
|
|
91
91
|
ReactApp._notifierProvider = NotifierMU.setup();
|
|
92
92
|
return NotifierMU.instance;
|
|
93
93
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Get parsed Url under bridge host
|
|
96
|
-
* @param url Url
|
|
97
|
-
* @returns Parsed Url
|
|
98
|
-
*/
|
|
99
|
-
getHostUrl(url) {
|
|
100
|
-
return this.getHostUrlBase(url, 'core');
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Get parsed Url under bridge host
|
|
104
|
-
* @param url Url
|
|
105
|
-
* @param name App name in the host environment
|
|
106
|
-
* @returns Parsed Url
|
|
107
|
-
*/
|
|
108
|
-
getHostUrlBase(url, name) {
|
|
109
|
-
if (url.startsWith('/'))
|
|
110
|
-
return url;
|
|
111
|
-
const identifier = `/${name}/`;
|
|
112
|
-
const pos = url.indexOf(identifier);
|
|
113
|
-
if (pos === -1)
|
|
114
|
-
return '/';
|
|
115
|
-
return url.substring(pos + identifier.length - 1);
|
|
116
|
-
}
|
|
117
94
|
/**
|
|
118
95
|
* Override alert action result
|
|
119
96
|
* @param result Action result
|
package/lib/app/ServiceApp.d.ts
CHANGED
|
@@ -33,11 +33,9 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
|
|
|
33
33
|
*/
|
|
34
34
|
constructor(settings: S, name: string);
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @param url Url
|
|
38
|
-
* @returns Parsed Url
|
|
36
|
+
* Load SmartERP core
|
|
39
37
|
*/
|
|
40
|
-
|
|
38
|
+
loadSmartERP(): void;
|
|
41
39
|
/**
|
|
42
40
|
* Go to the login page
|
|
43
41
|
* @param tryLogin Try to login again
|
|
@@ -66,8 +64,11 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
|
|
|
66
64
|
serviceEncrypt(message: string, passphrase?: string, iterations?: number): string;
|
|
67
65
|
/**
|
|
68
66
|
* Try login
|
|
67
|
+
* @param data Additional data
|
|
68
|
+
* @param showLoading Show loading bar or not
|
|
69
|
+
* @returns Result
|
|
69
70
|
*/
|
|
70
|
-
tryLogin<D extends {} = {}>(data?: D): Promise<boolean>;
|
|
71
|
+
tryLogin<D extends {} = {}>(data?: D, showLoading?: boolean): Promise<boolean>;
|
|
71
72
|
/**
|
|
72
73
|
* User login extended
|
|
73
74
|
* @param user Core system user
|
package/lib/app/ServiceApp.js
CHANGED
|
@@ -40,12 +40,15 @@ export class ServiceApp extends ReactApp {
|
|
|
40
40
|
this._serviceUser = value;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
* @param url Url
|
|
45
|
-
* @returns Parsed Url
|
|
43
|
+
* Load SmartERP core
|
|
46
44
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
loadSmartERP() {
|
|
46
|
+
if (BridgeUtils.host == null) {
|
|
47
|
+
window.location.href = this.settings.webUrl;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
BridgeUtils.host.loadApp('core');
|
|
51
|
+
}
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
51
54
|
* Go to the login page
|
|
@@ -206,10 +209,13 @@ export class ServiceApp extends ReactApp {
|
|
|
206
209
|
}
|
|
207
210
|
/**
|
|
208
211
|
* Try login
|
|
212
|
+
* @param data Additional data
|
|
213
|
+
* @param showLoading Show loading bar or not
|
|
214
|
+
* @returns Result
|
|
209
215
|
*/
|
|
210
|
-
async tryLogin(data) {
|
|
216
|
+
async tryLogin(data, showLoading) {
|
|
211
217
|
// Reset user state
|
|
212
|
-
const result = await super.tryLogin(data);
|
|
218
|
+
const result = await super.tryLogin(data, showLoading);
|
|
213
219
|
if (!result)
|
|
214
220
|
return false;
|
|
215
221
|
// Refresh token
|
|
@@ -228,6 +234,7 @@ export class ServiceApp extends ReactApp {
|
|
|
228
234
|
});
|
|
229
235
|
},
|
|
230
236
|
data,
|
|
237
|
+
showLoading,
|
|
231
238
|
relogin: true
|
|
232
239
|
});
|
|
233
240
|
}
|
package/lib/app/Utils.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare namespace Utils {
|
|
|
15
15
|
* @param initialPath Initial path
|
|
16
16
|
* @returns History
|
|
17
17
|
*/
|
|
18
|
-
function getMemoryHistory(initialPath?: string): History;
|
|
18
|
+
function getMemoryHistory(initialPath?: string | null): History;
|
|
19
19
|
/**
|
|
20
20
|
* Is safe click
|
|
21
21
|
* @param event Mouse event
|
package/lib/app/Utils.js
CHANGED
|
@@ -29,9 +29,9 @@ export var Utils;
|
|
|
29
29
|
* @param initialPath Initial path
|
|
30
30
|
* @returns History
|
|
31
31
|
*/
|
|
32
|
-
function getMemoryHistory(initialPath
|
|
32
|
+
function getMemoryHistory(initialPath) {
|
|
33
33
|
if (memoryHistory == null) {
|
|
34
|
-
memoryHistory = createHistory(createMemorySource(initialPath));
|
|
34
|
+
memoryHistory = createHistory(createMemorySource(initialPath !== null && initialPath !== void 0 ? initialPath : '/'));
|
|
35
35
|
}
|
|
36
36
|
return memoryHistory;
|
|
37
37
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export * from './mu/texts/DateText';
|
|
|
31
31
|
export * from './mu/texts/MoneyText';
|
|
32
32
|
export * from './mu/texts/NumberText';
|
|
33
33
|
export * from './mu/AuditDisplay';
|
|
34
|
+
export * from './mu/BackButton';
|
|
34
35
|
export * from './mu/BridgeCloseButton';
|
|
35
36
|
export * from './mu/ButtonLink';
|
|
36
37
|
export * from './mu/ComboBox';
|
package/lib/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export * from './mu/texts/DateText';
|
|
|
34
34
|
export * from './mu/texts/MoneyText';
|
|
35
35
|
export * from './mu/texts/NumberText';
|
|
36
36
|
export * from './mu/AuditDisplay';
|
|
37
|
+
export * from './mu/BackButton';
|
|
37
38
|
export * from './mu/BridgeCloseButton';
|
|
38
39
|
export * from './mu/ButtonLink';
|
|
39
40
|
export * from './mu/ComboBox';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { IconButtonProps } from '@mui/material';
|
|
3
|
+
/**
|
|
4
|
+
* BackButton props
|
|
5
|
+
*/
|
|
6
|
+
export interface BackButtonProps extends IconButtonProps {
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* BackButton
|
|
10
|
+
* @param props Props
|
|
11
|
+
* @returns Component
|
|
12
|
+
*/
|
|
13
|
+
export declare function BackButton(props: BackButtonProps): JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IconButton, useTheme } from '@mui/material';
|
|
2
|
+
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useNavigate } from '@reach/router';
|
|
5
|
+
/**
|
|
6
|
+
* BackButton
|
|
7
|
+
* @param props Props
|
|
8
|
+
* @returns Component
|
|
9
|
+
*/
|
|
10
|
+
export function BackButton(props) {
|
|
11
|
+
// Destruct
|
|
12
|
+
const { color = 'primary', size = 'small', onClick, ...rest } = props;
|
|
13
|
+
// Navigate
|
|
14
|
+
const navigate = useNavigate();
|
|
15
|
+
// Theme
|
|
16
|
+
const theme = useTheme();
|
|
17
|
+
// Color
|
|
18
|
+
const pColor = color != 'inherit' && color != 'default' && color in theme.palette
|
|
19
|
+
? theme.palette[color]
|
|
20
|
+
: theme.palette.primary;
|
|
21
|
+
// Click handler
|
|
22
|
+
const onClickLocal = (event) => {
|
|
23
|
+
if (onClick)
|
|
24
|
+
onClick(event);
|
|
25
|
+
navigate(-1);
|
|
26
|
+
};
|
|
27
|
+
return (React.createElement(IconButton, { "aria-label": "Back", color: color, size: size, onClick: onClickLocal, sx: {
|
|
28
|
+
backgroundColor: pColor.contrastText,
|
|
29
|
+
border: `1px solid ${pColor.light}`
|
|
30
|
+
}, ...rest },
|
|
31
|
+
React.createElement(ArrowBackIcon, null)));
|
|
32
|
+
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { IBridgeHost } from '@etsoo/appscript';
|
|
3
|
-
import { IconButtonProps } from '@mui/material';
|
|
3
|
+
import { BoxProps, IconButtonProps } from '@mui/material';
|
|
4
4
|
/**
|
|
5
5
|
* Bridge close button props
|
|
6
6
|
*/
|
|
7
7
|
export interface BridgeCloseButtonProps extends IconButtonProps {
|
|
8
|
+
/**
|
|
9
|
+
* Box props
|
|
10
|
+
*/
|
|
11
|
+
boxProps?: BoxProps;
|
|
8
12
|
/**
|
|
9
13
|
* Validate the host
|
|
10
14
|
* @param host Host
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BridgeUtils } from '@etsoo/appscript';
|
|
2
2
|
import CloseIcon from '@mui/icons-material/Close';
|
|
3
|
-
import { IconButton } from '@mui/material';
|
|
3
|
+
import { Box, IconButton } from '@mui/material';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { globalApp } from '../app/ReactApp';
|
|
6
6
|
/**
|
|
@@ -10,7 +10,7 @@ import { globalApp } from '../app/ReactApp';
|
|
|
10
10
|
*/
|
|
11
11
|
export function BridgeCloseButton(props) {
|
|
12
12
|
// Destruct
|
|
13
|
-
const { onClick, title = typeof globalApp === 'undefined'
|
|
13
|
+
const { boxProps, onClick, title = typeof globalApp === 'undefined'
|
|
14
14
|
? 'Close'
|
|
15
15
|
: globalApp.get('close'), validate, ...rest } = props;
|
|
16
16
|
// Host
|
|
@@ -24,11 +24,7 @@ export function BridgeCloseButton(props) {
|
|
|
24
24
|
onClick(event);
|
|
25
25
|
host.exit();
|
|
26
26
|
};
|
|
27
|
-
return (React.createElement(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
top: (theme) => theme.spacing(0.5),
|
|
31
|
-
right: (theme) => theme.spacing(0.5)
|
|
32
|
-
}, ...rest },
|
|
33
|
-
React.createElement(CloseIcon, null)));
|
|
27
|
+
return (React.createElement(Box, { ...boxProps },
|
|
28
|
+
React.createElement(IconButton, { "aria-label": "close", onClick: onClickLocal, title: title, ...rest },
|
|
29
|
+
React.createElement(CloseIcon, null))));
|
|
34
30
|
}
|
|
@@ -7,6 +7,7 @@ import { MoreFab } from '../MoreFab';
|
|
|
7
7
|
import { ReactAppStateDetector } from '../../app/ReactApp';
|
|
8
8
|
import { Container, Fab } from '@mui/material';
|
|
9
9
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
10
|
+
import { BackButton } from '../BackButton';
|
|
10
11
|
/**
|
|
11
12
|
* Default scroll container
|
|
12
13
|
*/
|
|
@@ -17,7 +18,7 @@ export const CommonPageScrollContainer = global;
|
|
|
17
18
|
*/
|
|
18
19
|
export function CommonPage(props) {
|
|
19
20
|
// Destruct
|
|
20
|
-
const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, targetFields, sx = {}, ...rest } = props;
|
|
21
|
+
const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, supportBack = false, targetFields, sx = {}, ...rest } = props;
|
|
21
22
|
// Merge style
|
|
22
23
|
Object.assign(sx, {
|
|
23
24
|
padding: paddings
|
|
@@ -53,6 +54,7 @@ export function CommonPage(props) {
|
|
|
53
54
|
fabButtons,
|
|
54
55
|
onRefresh != null && (React.createElement(Fab, { title: labels.refresh, size: fabSize, onClick: onRefresh, sx: { display: { xs: 'none', md: 'inherit' } } },
|
|
55
56
|
React.createElement(RefreshIcon, null))),
|
|
56
|
-
React.createElement(MoreFab, { size: fabSize, title: labels.more, actions: moreActions })
|
|
57
|
+
React.createElement(MoreFab, { size: fabSize, title: labels.more, actions: moreActions }),
|
|
58
|
+
supportBack && (React.createElement(BackButton, { title: labels.back, size: fabSize }))),
|
|
57
59
|
children)));
|
|
58
60
|
}
|
|
@@ -18,7 +18,7 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
|
|
|
18
18
|
*/
|
|
19
19
|
fabSize?: CustomFabSize;
|
|
20
20
|
/**
|
|
21
|
-
* Fab flex column direction
|
|
21
|
+
* Fab flex column direction, undefined to hide it
|
|
22
22
|
*/
|
|
23
23
|
fabColumnDirection?: boolean;
|
|
24
24
|
/**
|
|
@@ -49,6 +49,10 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
|
|
|
49
49
|
* Scroll container
|
|
50
50
|
*/
|
|
51
51
|
scrollContainer?: HTMLElement | object;
|
|
52
|
+
/**
|
|
53
|
+
* Support back click
|
|
54
|
+
*/
|
|
55
|
+
supportBack?: boolean;
|
|
52
56
|
/**
|
|
53
57
|
* State last changed fields
|
|
54
58
|
*/
|
|
@@ -16,6 +16,11 @@ export interface EditPageProps extends Omit<CommonPageProps, 'onSubmit'> {
|
|
|
16
16
|
* On delete callback
|
|
17
17
|
*/
|
|
18
18
|
onDelete?: () => Promise<void> | void;
|
|
19
|
+
/**
|
|
20
|
+
* Support back click
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
supportBack?: boolean;
|
|
19
24
|
}
|
|
20
25
|
/**
|
|
21
26
|
* Add / Edit page
|
package/lib/mu/pages/EditPage.js
CHANGED
|
@@ -5,13 +5,14 @@ import { MUGlobal } from '../MUGlobal';
|
|
|
5
5
|
import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
6
6
|
import SaveIcon from '@mui/icons-material/Save';
|
|
7
7
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
8
|
+
import { BackButton } from '../BackButton';
|
|
8
9
|
/**
|
|
9
10
|
* Add / Edit page
|
|
10
11
|
* @param props Props
|
|
11
12
|
*/
|
|
12
13
|
export function EditPage(props) {
|
|
13
14
|
// Destruct
|
|
14
|
-
const { children, isEditing, onDelete, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, ...rest } = props;
|
|
15
|
+
const { children, isEditing, onDelete, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, supportBack = true, ...rest } = props;
|
|
15
16
|
// Labels
|
|
16
17
|
const labels = Labels.CommonPage;
|
|
17
18
|
return (React.createElement(CommonPage, { paddings: paddings, scrollContainer: scrollContainer, ...rest },
|
|
@@ -23,5 +24,6 @@ export function EditPage(props) {
|
|
|
23
24
|
paddingTop: paddings
|
|
24
25
|
} },
|
|
25
26
|
isEditing && onDelete && (React.createElement(Button, { color: "primary", variant: "outlined", onClick: () => onDelete(), startIcon: React.createElement(DeleteIcon, { color: "warning" }) }, labels.delete)),
|
|
26
|
-
React.createElement(Button, { variant: "contained", type: "submit", startIcon: React.createElement(SaveIcon, null), sx: { flexGrow: 1 } }, labels.save)
|
|
27
|
+
React.createElement(Button, { variant: "contained", type: "submit", startIcon: React.createElement(SaveIcon, null), sx: { flexGrow: 1 } }, labels.save),
|
|
28
|
+
supportBack && React.createElement(BackButton, { title: labels.back })))));
|
|
27
29
|
}
|
package/lib/mu/pages/ViewPage.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Utils } from '@etsoo/shared';
|
|
2
2
|
import { Grid, LinearProgress, Stack, Typography } from '@mui/material';
|
|
3
3
|
import React from 'react';
|
|
4
|
+
import { Labels } from '../../app/Labels';
|
|
4
5
|
import { globalApp } from '../../app/ReactApp';
|
|
5
6
|
import { GridDataFormat } from '../GridDataFormat';
|
|
6
7
|
import { MUGlobal } from '../MUGlobal';
|
|
8
|
+
import { PullToRefreshUI } from '../PullToRefreshUI';
|
|
7
9
|
import { CommonPage } from './CommonPage';
|
|
8
10
|
function formatItemData(fieldData) {
|
|
9
11
|
if (fieldData == null)
|
|
@@ -62,9 +64,13 @@ function getItemField(field, data) {
|
|
|
62
64
|
*/
|
|
63
65
|
export function ViewPage(props) {
|
|
64
66
|
// Destruct
|
|
65
|
-
const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, ...rest } = props;
|
|
67
|
+
const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, fabColumnDirection = true, supportBack = true, pullToRefresh = true, ...rest } = props;
|
|
66
68
|
// Data
|
|
67
69
|
const [data, setData] = React.useState();
|
|
70
|
+
// Labels
|
|
71
|
+
const labels = Labels.CommonPage;
|
|
72
|
+
// Container
|
|
73
|
+
const pullContainer = '#page-container';
|
|
68
74
|
// Load data
|
|
69
75
|
const refresh = async () => {
|
|
70
76
|
const result = await loadData();
|
|
@@ -72,7 +78,7 @@ export function ViewPage(props) {
|
|
|
72
78
|
return;
|
|
73
79
|
setData(result);
|
|
74
80
|
};
|
|
75
|
-
return (React.createElement(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? refresh : undefined, onUpdate: supportRefresh ? undefined : refresh, ...rest, scrollContainer:
|
|
81
|
+
return (React.createElement(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? refresh : undefined, onUpdate: supportRefresh ? undefined : refresh, ...rest, scrollContainer: globalThis, fabColumnDirection: fabColumnDirection, supportBack: supportBack }, data == null ? (React.createElement(LinearProgress, null)) : (React.createElement(React.Fragment, null,
|
|
76
82
|
React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, className: "ET-ViewPage", sx: {
|
|
77
83
|
'.MuiTypography-subtitle2': {
|
|
78
84
|
fontWeight: 'bold'
|
|
@@ -91,5 +97,9 @@ export function ViewPage(props) {
|
|
|
91
97
|
React.createElement(Typography, { variant: "subtitle2" }, itemData)));
|
|
92
98
|
})),
|
|
93
99
|
actions != null && (React.createElement(Stack, { className: "ET-ViewPage-Actions", direction: "row", width: "100%", flexWrap: "wrap", justifyContent: "flex-end", paddingTop: paddings, paddingBottom: paddings, gap: paddings }, Utils.getResult(actions, data, refresh))),
|
|
94
|
-
Utils.getResult(children, data, refresh)
|
|
100
|
+
Utils.getResult(children, data, refresh),
|
|
101
|
+
pullToRefresh && (React.createElement(PullToRefreshUI, { mainElement: pullContainer, triggerElement: pullContainer, instructionsPullToRefresh: labels.pullToRefresh, instructionsReleaseToRefresh: labels.releaseToRefresh, instructionsRefreshing: labels.refreshing, onRefresh: refresh, shouldPullToRefresh: () => {
|
|
102
|
+
const container = document.querySelector(pullContainer);
|
|
103
|
+
return !(container === null || container === void 0 ? void 0 : container.scrollTop);
|
|
104
|
+
} }))))));
|
|
95
105
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.15",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@emotion/react": "^11.7.1",
|
|
51
51
|
"@emotion/style": "^0.8.0",
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
|
-
"@etsoo/appscript": "^1.2.
|
|
53
|
+
"@etsoo/appscript": "^1.2.50",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.1",
|
|
55
55
|
"@etsoo/shared": "^1.1.11",
|
|
56
56
|
"@mui/icons-material": "^5.4.1",
|
package/src/app/Labels.ts
CHANGED
package/src/app/ReactApp.ts
CHANGED
|
@@ -56,12 +56,10 @@ export function ReactAppStateDetector(props: IStateProps) {
|
|
|
56
56
|
const { targetFields, update } = props;
|
|
57
57
|
|
|
58
58
|
// Context
|
|
59
|
-
const { state } =
|
|
59
|
+
const { state = {} } =
|
|
60
60
|
globalApp == null
|
|
61
|
-
? ({
|
|
62
|
-
: React.useContext(
|
|
63
|
-
(globalApp.userState as UserState<IUser>).context
|
|
64
|
-
);
|
|
61
|
+
? ({} as UserCalls<IUser>)
|
|
62
|
+
: React.useContext(globalApp.userState.context);
|
|
65
63
|
|
|
66
64
|
// Ready
|
|
67
65
|
React.useEffect(() => {
|
|
@@ -221,41 +219,18 @@ export class ReactApp<
|
|
|
221
219
|
new WindowStorage(),
|
|
222
220
|
name
|
|
223
221
|
);
|
|
222
|
+
|
|
224
223
|
this.history =
|
|
225
|
-
|
|
226
|
-
?
|
|
227
|
-
:
|
|
224
|
+
BridgeUtils.host == null
|
|
225
|
+
? undefined
|
|
226
|
+
: Utils.getMemoryHistory(BridgeUtils.host.getStartUrl());
|
|
227
|
+
|
|
228
228
|
this.cultureState = new CultureState(settings.currentCulture);
|
|
229
229
|
this.pageState = new PageState<P>();
|
|
230
230
|
|
|
231
231
|
globalApp = this;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
/**
|
|
235
|
-
* Get parsed Url under bridge host
|
|
236
|
-
* @param url Url
|
|
237
|
-
* @returns Parsed Url
|
|
238
|
-
*/
|
|
239
|
-
protected getHostUrl(url: string) {
|
|
240
|
-
return this.getHostUrlBase(url, 'core');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Get parsed Url under bridge host
|
|
245
|
-
* @param url Url
|
|
246
|
-
* @param name App name in the host environment
|
|
247
|
-
* @returns Parsed Url
|
|
248
|
-
*/
|
|
249
|
-
protected getHostUrlBase(url: string, name: string) {
|
|
250
|
-
if (url.startsWith('/')) return url;
|
|
251
|
-
|
|
252
|
-
const identifier = `/${name}/`;
|
|
253
|
-
const pos = url.indexOf(identifier);
|
|
254
|
-
if (pos === -1) return '/';
|
|
255
|
-
|
|
256
|
-
return url.substring(pos + identifier.length - 1);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
234
|
/**
|
|
260
235
|
* Override alert action result
|
|
261
236
|
* @param result Action result
|
package/src/app/ServiceApp.ts
CHANGED
|
@@ -69,12 +69,14 @@ export class ServiceApp<
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
* @param url Url
|
|
74
|
-
* @returns Parsed Url
|
|
72
|
+
* Load SmartERP core
|
|
75
73
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
loadSmartERP() {
|
|
75
|
+
if (BridgeUtils.host == null) {
|
|
76
|
+
window.location.href = this.settings.webUrl;
|
|
77
|
+
} else {
|
|
78
|
+
BridgeUtils.host.loadApp('core');
|
|
79
|
+
}
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
/**
|
|
@@ -300,10 +302,16 @@ export class ServiceApp<
|
|
|
300
302
|
|
|
301
303
|
/**
|
|
302
304
|
* Try login
|
|
305
|
+
* @param data Additional data
|
|
306
|
+
* @param showLoading Show loading bar or not
|
|
307
|
+
* @returns Result
|
|
303
308
|
*/
|
|
304
|
-
override async tryLogin<D extends {} = {}>(
|
|
309
|
+
override async tryLogin<D extends {} = {}>(
|
|
310
|
+
data?: D,
|
|
311
|
+
showLoading?: boolean
|
|
312
|
+
) {
|
|
305
313
|
// Reset user state
|
|
306
|
-
const result = await super.tryLogin(data);
|
|
314
|
+
const result = await super.tryLogin(data, showLoading);
|
|
307
315
|
if (!result) return false;
|
|
308
316
|
|
|
309
317
|
// Refresh token
|
|
@@ -323,6 +331,7 @@ export class ServiceApp<
|
|
|
323
331
|
});
|
|
324
332
|
},
|
|
325
333
|
data,
|
|
334
|
+
showLoading,
|
|
326
335
|
relogin: true
|
|
327
336
|
});
|
|
328
337
|
}
|
package/src/app/Utils.ts
CHANGED
|
@@ -31,9 +31,11 @@ export namespace Utils {
|
|
|
31
31
|
* @param initialPath Initial path
|
|
32
32
|
* @returns History
|
|
33
33
|
*/
|
|
34
|
-
export function getMemoryHistory(initialPath
|
|
34
|
+
export function getMemoryHistory(initialPath?: string | null) {
|
|
35
35
|
if (memoryHistory == null) {
|
|
36
|
-
memoryHistory = createHistory(
|
|
36
|
+
memoryHistory = createHistory(
|
|
37
|
+
createMemorySource(initialPath ?? '/')
|
|
38
|
+
);
|
|
37
39
|
}
|
|
38
40
|
return memoryHistory;
|
|
39
41
|
}
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ export * from './mu/texts/MoneyText';
|
|
|
38
38
|
export * from './mu/texts/NumberText';
|
|
39
39
|
|
|
40
40
|
export * from './mu/AuditDisplay';
|
|
41
|
+
export * from './mu/BackButton';
|
|
41
42
|
export * from './mu/BridgeCloseButton';
|
|
42
43
|
export * from './mu/ButtonLink';
|
|
43
44
|
export * from './mu/ComboBox';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { IconButton, IconButtonProps, useTheme } from '@mui/material';
|
|
2
|
+
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useNavigate } from '@reach/router';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* BackButton props
|
|
8
|
+
*/
|
|
9
|
+
export interface BackButtonProps extends IconButtonProps {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* BackButton
|
|
13
|
+
* @param props Props
|
|
14
|
+
* @returns Component
|
|
15
|
+
*/
|
|
16
|
+
export function BackButton(props: BackButtonProps) {
|
|
17
|
+
// Destruct
|
|
18
|
+
const { color = 'primary', size = 'small', onClick, ...rest } = props;
|
|
19
|
+
|
|
20
|
+
// Navigate
|
|
21
|
+
const navigate = useNavigate();
|
|
22
|
+
|
|
23
|
+
// Theme
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
|
|
26
|
+
// Color
|
|
27
|
+
const pColor =
|
|
28
|
+
color != 'inherit' && color != 'default' && color in theme.palette
|
|
29
|
+
? theme.palette[color]
|
|
30
|
+
: theme.palette.primary;
|
|
31
|
+
|
|
32
|
+
// Click handler
|
|
33
|
+
const onClickLocal = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
34
|
+
if (onClick) onClick(event);
|
|
35
|
+
navigate(-1);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<IconButton
|
|
40
|
+
aria-label="Back"
|
|
41
|
+
color={color}
|
|
42
|
+
size={size}
|
|
43
|
+
onClick={onClickLocal}
|
|
44
|
+
sx={{
|
|
45
|
+
backgroundColor: pColor.contrastText,
|
|
46
|
+
border: `1px solid ${pColor.light}`
|
|
47
|
+
}}
|
|
48
|
+
{...rest}
|
|
49
|
+
>
|
|
50
|
+
<ArrowBackIcon />
|
|
51
|
+
</IconButton>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BridgeUtils, IBridgeHost } from '@etsoo/appscript';
|
|
2
2
|
import CloseIcon from '@mui/icons-material/Close';
|
|
3
|
-
import { IconButton, IconButtonProps } from '@mui/material';
|
|
3
|
+
import { Box, BoxProps, IconButton, IconButtonProps } from '@mui/material';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { globalApp } from '../app/ReactApp';
|
|
6
6
|
|
|
@@ -8,6 +8,11 @@ import { globalApp } from '../app/ReactApp';
|
|
|
8
8
|
* Bridge close button props
|
|
9
9
|
*/
|
|
10
10
|
export interface BridgeCloseButtonProps extends IconButtonProps {
|
|
11
|
+
/**
|
|
12
|
+
* Box props
|
|
13
|
+
*/
|
|
14
|
+
boxProps?: BoxProps;
|
|
15
|
+
|
|
11
16
|
/**
|
|
12
17
|
* Validate the host
|
|
13
18
|
* @param host Host
|
|
@@ -23,6 +28,7 @@ export interface BridgeCloseButtonProps extends IconButtonProps {
|
|
|
23
28
|
export function BridgeCloseButton(props: BridgeCloseButtonProps) {
|
|
24
29
|
// Destruct
|
|
25
30
|
const {
|
|
31
|
+
boxProps,
|
|
26
32
|
onClick,
|
|
27
33
|
title = typeof globalApp === 'undefined'
|
|
28
34
|
? 'Close'
|
|
@@ -45,20 +51,15 @@ export function BridgeCloseButton(props: BridgeCloseButtonProps) {
|
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
return (
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}}
|
|
59
|
-
{...rest}
|
|
60
|
-
>
|
|
61
|
-
<CloseIcon />
|
|
62
|
-
</IconButton>
|
|
54
|
+
<Box {...boxProps}>
|
|
55
|
+
<IconButton
|
|
56
|
+
aria-label="close"
|
|
57
|
+
onClick={onClickLocal}
|
|
58
|
+
title={title}
|
|
59
|
+
{...rest}
|
|
60
|
+
>
|
|
61
|
+
<CloseIcon />
|
|
62
|
+
</IconButton>
|
|
63
|
+
</Box>
|
|
63
64
|
);
|
|
64
65
|
}
|
|
@@ -8,6 +8,7 @@ import { MoreFab } from '../MoreFab';
|
|
|
8
8
|
import { ReactAppStateDetector } from '../../app/ReactApp';
|
|
9
9
|
import { Container, Fab } from '@mui/material';
|
|
10
10
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
11
|
+
import { BackButton } from '../BackButton';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Default scroll container
|
|
@@ -34,6 +35,7 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
34
35
|
onUpdateAll,
|
|
35
36
|
paddings = MUGlobal.pagePaddings,
|
|
36
37
|
scrollContainer,
|
|
38
|
+
supportBack = false,
|
|
37
39
|
targetFields,
|
|
38
40
|
sx = {},
|
|
39
41
|
...rest
|
|
@@ -115,6 +117,9 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
115
117
|
title={labels.more}
|
|
116
118
|
actions={moreActions}
|
|
117
119
|
/>
|
|
120
|
+
{supportBack && (
|
|
121
|
+
<BackButton title={labels.back} size={fabSize} />
|
|
122
|
+
)}
|
|
118
123
|
</FabBox>
|
|
119
124
|
{children}
|
|
120
125
|
</Container>
|
|
@@ -20,7 +20,7 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
|
|
|
20
20
|
fabSize?: CustomFabSize;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Fab flex column direction
|
|
23
|
+
* Fab flex column direction, undefined to hide it
|
|
24
24
|
*/
|
|
25
25
|
fabColumnDirection?: boolean;
|
|
26
26
|
|
|
@@ -59,6 +59,11 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
|
|
|
59
59
|
*/
|
|
60
60
|
scrollContainer?: HTMLElement | object;
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Support back click
|
|
64
|
+
*/
|
|
65
|
+
supportBack?: boolean;
|
|
66
|
+
|
|
62
67
|
/**
|
|
63
68
|
* State last changed fields
|
|
64
69
|
*/
|
|
@@ -6,6 +6,7 @@ import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
|
6
6
|
import { CommonPageProps } from './CommonPageProps';
|
|
7
7
|
import SaveIcon from '@mui/icons-material/Save';
|
|
8
8
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
9
|
+
import { BackButton } from '../BackButton';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Add / Edit page props
|
|
@@ -25,6 +26,12 @@ export interface EditPageProps extends Omit<CommonPageProps, 'onSubmit'> {
|
|
|
25
26
|
* On delete callback
|
|
26
27
|
*/
|
|
27
28
|
onDelete?: () => Promise<void> | void;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Support back click
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
supportBack?: boolean;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
/**
|
|
@@ -40,6 +47,7 @@ export function EditPage(props: EditPageProps) {
|
|
|
40
47
|
onSubmit,
|
|
41
48
|
paddings = MUGlobal.pagePaddings,
|
|
42
49
|
scrollContainer = CommonPageScrollContainer,
|
|
50
|
+
supportBack = true,
|
|
43
51
|
...rest
|
|
44
52
|
} = props;
|
|
45
53
|
|
|
@@ -91,6 +99,7 @@ export function EditPage(props: EditPageProps) {
|
|
|
91
99
|
>
|
|
92
100
|
{labels.save}
|
|
93
101
|
</Button>
|
|
102
|
+
{supportBack && <BackButton title={labels.back} />}
|
|
94
103
|
</Grid>
|
|
95
104
|
</form>
|
|
96
105
|
</CommonPage>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
Typography
|
|
8
8
|
} from '@mui/material';
|
|
9
9
|
import React from 'react';
|
|
10
|
+
import { Labels } from '../../app/Labels';
|
|
10
11
|
import { globalApp } from '../../app/ReactApp';
|
|
11
12
|
import {
|
|
12
13
|
GridColumnRenderProps,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
} from '../../components/GridColumn';
|
|
15
16
|
import { GridDataFormat } from '../GridDataFormat';
|
|
16
17
|
import { MUGlobal } from '../MUGlobal';
|
|
18
|
+
import { PullToRefreshUI } from '../PullToRefreshUI';
|
|
17
19
|
import { CommonPage } from './CommonPage';
|
|
18
20
|
import { CommonPageProps } from './CommonPageProps';
|
|
19
21
|
|
|
@@ -81,6 +83,11 @@ export interface ViewPageProps<T extends {}>
|
|
|
81
83
|
*/
|
|
82
84
|
loadData: () => PromiseLike<T | undefined>;
|
|
83
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Pull to refresh data
|
|
88
|
+
*/
|
|
89
|
+
pullToRefresh?: boolean;
|
|
90
|
+
|
|
84
91
|
/**
|
|
85
92
|
* Support refresh
|
|
86
93
|
*/
|
|
@@ -165,12 +172,21 @@ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
|
165
172
|
loadData,
|
|
166
173
|
paddings = MUGlobal.pagePaddings,
|
|
167
174
|
supportRefresh = true,
|
|
175
|
+
fabColumnDirection = true,
|
|
176
|
+
supportBack = true,
|
|
177
|
+
pullToRefresh = true,
|
|
168
178
|
...rest
|
|
169
179
|
} = props;
|
|
170
180
|
|
|
171
181
|
// Data
|
|
172
182
|
const [data, setData] = React.useState<T>();
|
|
173
183
|
|
|
184
|
+
// Labels
|
|
185
|
+
const labels = Labels.CommonPage;
|
|
186
|
+
|
|
187
|
+
// Container
|
|
188
|
+
const pullContainer = '#page-container';
|
|
189
|
+
|
|
174
190
|
// Load data
|
|
175
191
|
const refresh = async () => {
|
|
176
192
|
const result = await loadData();
|
|
@@ -184,7 +200,9 @@ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
|
184
200
|
onRefresh={supportRefresh ? refresh : undefined}
|
|
185
201
|
onUpdate={supportRefresh ? undefined : refresh}
|
|
186
202
|
{...rest}
|
|
187
|
-
scrollContainer={
|
|
203
|
+
scrollContainer={globalThis}
|
|
204
|
+
fabColumnDirection={fabColumnDirection}
|
|
205
|
+
supportBack={supportBack}
|
|
188
206
|
>
|
|
189
207
|
{data == null ? (
|
|
190
208
|
<LinearProgress />
|
|
@@ -241,6 +259,23 @@ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
|
241
259
|
</Stack>
|
|
242
260
|
)}
|
|
243
261
|
{Utils.getResult(children, data, refresh)}
|
|
262
|
+
{pullToRefresh && (
|
|
263
|
+
<PullToRefreshUI
|
|
264
|
+
mainElement={pullContainer}
|
|
265
|
+
triggerElement={pullContainer}
|
|
266
|
+
instructionsPullToRefresh={labels.pullToRefresh}
|
|
267
|
+
instructionsReleaseToRefresh={
|
|
268
|
+
labels.releaseToRefresh
|
|
269
|
+
}
|
|
270
|
+
instructionsRefreshing={labels.refreshing}
|
|
271
|
+
onRefresh={refresh}
|
|
272
|
+
shouldPullToRefresh={() => {
|
|
273
|
+
const container =
|
|
274
|
+
document.querySelector(pullContainer);
|
|
275
|
+
return !container?.scrollTop;
|
|
276
|
+
}}
|
|
277
|
+
/>
|
|
278
|
+
)}
|
|
244
279
|
</React.Fragment>
|
|
245
280
|
)}
|
|
246
281
|
</CommonPage>
|