@etsoo/react 1.5.10 → 1.5.14
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 +13 -0
- package/lib/app/ReactApp.js +28 -3
- package/lib/app/ServiceApp.d.ts +10 -1
- package/lib/app/ServiceApp.js +14 -2
- package/lib/app/Utils.js +0 -1
- 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 +29 -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.js +2 -2
- package/package.json +2 -2
- package/src/app/Labels.ts +1 -0
- package/src/app/ReactApp.ts +31 -6
- package/src/app/ServiceApp.ts +18 -2
- package/src/app/Utils.ts +0 -1
- package/src/index.ts +1 -0
- package/src/mu/BackButton.tsx +51 -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 +5 -1
package/lib/app/Labels.d.ts
CHANGED
package/lib/app/Labels.js
CHANGED
package/lib/app/ReactApp.d.ts
CHANGED
|
@@ -108,6 +108,19 @@ 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;
|
|
111
124
|
/**
|
|
112
125
|
* Override alert action result
|
|
113
126
|
* @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(() => {
|
|
@@ -67,7 +67,7 @@ export class ReactApp extends CoreApp {
|
|
|
67
67
|
this.userState = new UserState();
|
|
68
68
|
this.history =
|
|
69
69
|
window.location.hostname === ''
|
|
70
|
-
? Utils.getMemoryHistory(window.location.href)
|
|
70
|
+
? Utils.getMemoryHistory(this.getHostUrl(window.location.href))
|
|
71
71
|
: undefined;
|
|
72
72
|
this.cultureState = new CultureState(settings.currentCulture);
|
|
73
73
|
this.pageState = new PageState();
|
|
@@ -91,6 +91,31 @@ 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
|
|
116
|
+
.substring(pos + identifier.length - 1)
|
|
117
|
+
.replace('/index.html', '/'); // Router take / as start
|
|
118
|
+
}
|
|
94
119
|
/**
|
|
95
120
|
* Override alert action result
|
|
96
121
|
* @param result Action result
|
package/lib/app/ServiceApp.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
|
|
|
32
32
|
* @param name Application name
|
|
33
33
|
*/
|
|
34
34
|
constructor(settings: S, name: string);
|
|
35
|
+
/**
|
|
36
|
+
* Get parsed Url under bridge host
|
|
37
|
+
* @param url Url
|
|
38
|
+
* @returns Parsed Url
|
|
39
|
+
*/
|
|
40
|
+
protected getHostUrl(url: string): string;
|
|
35
41
|
/**
|
|
36
42
|
* Go to the login page
|
|
37
43
|
* @param tryLogin Try to login again
|
|
@@ -60,8 +66,11 @@ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends
|
|
|
60
66
|
serviceEncrypt(message: string, passphrase?: string, iterations?: number): string;
|
|
61
67
|
/**
|
|
62
68
|
* Try login
|
|
69
|
+
* @param data Additional data
|
|
70
|
+
* @param showLoading Show loading bar or not
|
|
71
|
+
* @returns Result
|
|
63
72
|
*/
|
|
64
|
-
tryLogin<D extends {} = {}>(data?: D): Promise<boolean>;
|
|
73
|
+
tryLogin<D extends {} = {}>(data?: D, showLoading?: boolean): Promise<boolean>;
|
|
65
74
|
/**
|
|
66
75
|
* User login extended
|
|
67
76
|
* @param user Core system user
|
package/lib/app/ServiceApp.js
CHANGED
|
@@ -39,6 +39,14 @@ export class ServiceApp extends ReactApp {
|
|
|
39
39
|
set serviceUser(value) {
|
|
40
40
|
this._serviceUser = value;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Get parsed Url under bridge host
|
|
44
|
+
* @param url Url
|
|
45
|
+
* @returns Parsed Url
|
|
46
|
+
*/
|
|
47
|
+
getHostUrl(url) {
|
|
48
|
+
return this.getHostUrlBase(url, 's' + this.settings.serviceId);
|
|
49
|
+
}
|
|
42
50
|
/**
|
|
43
51
|
* Go to the login page
|
|
44
52
|
* @param tryLogin Try to login again
|
|
@@ -198,10 +206,13 @@ export class ServiceApp extends ReactApp {
|
|
|
198
206
|
}
|
|
199
207
|
/**
|
|
200
208
|
* Try login
|
|
209
|
+
* @param data Additional data
|
|
210
|
+
* @param showLoading Show loading bar or not
|
|
211
|
+
* @returns Result
|
|
201
212
|
*/
|
|
202
|
-
async tryLogin(data) {
|
|
213
|
+
async tryLogin(data, showLoading) {
|
|
203
214
|
// Reset user state
|
|
204
|
-
const result = await super.tryLogin(data);
|
|
215
|
+
const result = await super.tryLogin(data, showLoading);
|
|
205
216
|
if (!result)
|
|
206
217
|
return false;
|
|
207
218
|
// Refresh token
|
|
@@ -220,6 +231,7 @@ export class ServiceApp extends ReactApp {
|
|
|
220
231
|
});
|
|
221
232
|
},
|
|
222
233
|
data,
|
|
234
|
+
showLoading,
|
|
223
235
|
relogin: true
|
|
224
236
|
});
|
|
225
237
|
}
|
package/lib/app/Utils.js
CHANGED
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,29 @@
|
|
|
1
|
+
import { IconButton } 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
|
+
// Click handler
|
|
16
|
+
const onClickLocal = (event) => {
|
|
17
|
+
if (onClick)
|
|
18
|
+
onClick(event);
|
|
19
|
+
navigate(-1);
|
|
20
|
+
};
|
|
21
|
+
return (React.createElement(IconButton, { "aria-label": "Back", color: color, size: size, onClick: onClickLocal, sx: {
|
|
22
|
+
border: (theme) => `1px solid ${(() => color != 'inherit' &&
|
|
23
|
+
color != 'default' &&
|
|
24
|
+
color in theme.palette
|
|
25
|
+
? theme.palette[color]
|
|
26
|
+
: theme.palette.primary)().light}`
|
|
27
|
+
}, ...rest },
|
|
28
|
+
React.createElement(ArrowBackIcon, null)));
|
|
29
|
+
}
|
|
@@ -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
|
@@ -62,7 +62,7 @@ function getItemField(field, data) {
|
|
|
62
62
|
*/
|
|
63
63
|
export function ViewPage(props) {
|
|
64
64
|
// Destruct
|
|
65
|
-
const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, ...rest } = props;
|
|
65
|
+
const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, fabColumnDirection = true, supportBack = true, ...rest } = props;
|
|
66
66
|
// Data
|
|
67
67
|
const [data, setData] = React.useState();
|
|
68
68
|
// Load data
|
|
@@ -72,7 +72,7 @@ export function ViewPage(props) {
|
|
|
72
72
|
return;
|
|
73
73
|
setData(result);
|
|
74
74
|
};
|
|
75
|
-
return (React.createElement(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? refresh : undefined, onUpdate: supportRefresh ? undefined : refresh, ...rest, scrollContainer:
|
|
75
|
+
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
76
|
React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, className: "ET-ViewPage", sx: {
|
|
77
77
|
'.MuiTypography-subtitle2': {
|
|
78
78
|
fontWeight: 'bold'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.14",
|
|
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.49",
|
|
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(() => {
|
|
@@ -223,7 +221,7 @@ export class ReactApp<
|
|
|
223
221
|
);
|
|
224
222
|
this.history =
|
|
225
223
|
window.location.hostname === ''
|
|
226
|
-
? Utils.getMemoryHistory(window.location.href)
|
|
224
|
+
? Utils.getMemoryHistory(this.getHostUrl(window.location.href))
|
|
227
225
|
: undefined;
|
|
228
226
|
this.cultureState = new CultureState(settings.currentCulture);
|
|
229
227
|
this.pageState = new PageState<P>();
|
|
@@ -231,6 +229,33 @@ export class ReactApp<
|
|
|
231
229
|
globalApp = this;
|
|
232
230
|
}
|
|
233
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Get parsed Url under bridge host
|
|
234
|
+
* @param url Url
|
|
235
|
+
* @returns Parsed Url
|
|
236
|
+
*/
|
|
237
|
+
protected getHostUrl(url: string) {
|
|
238
|
+
return this.getHostUrlBase(url, 'core');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get parsed Url under bridge host
|
|
243
|
+
* @param url Url
|
|
244
|
+
* @param name App name in the host environment
|
|
245
|
+
* @returns Parsed Url
|
|
246
|
+
*/
|
|
247
|
+
protected getHostUrlBase(url: string, name: string) {
|
|
248
|
+
if (url.startsWith('/')) return url;
|
|
249
|
+
|
|
250
|
+
const identifier = `/${name}/`;
|
|
251
|
+
const pos = url.indexOf(identifier);
|
|
252
|
+
if (pos === -1) return '/';
|
|
253
|
+
|
|
254
|
+
return url
|
|
255
|
+
.substring(pos + identifier.length - 1)
|
|
256
|
+
.replace('/index.html', '/'); // Router take / as start
|
|
257
|
+
}
|
|
258
|
+
|
|
234
259
|
/**
|
|
235
260
|
* Override alert action result
|
|
236
261
|
* @param result Action result
|
package/src/app/ServiceApp.ts
CHANGED
|
@@ -68,6 +68,15 @@ export class ServiceApp<
|
|
|
68
68
|
this.serviceApi = api;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Get parsed Url under bridge host
|
|
73
|
+
* @param url Url
|
|
74
|
+
* @returns Parsed Url
|
|
75
|
+
*/
|
|
76
|
+
protected override getHostUrl(url: string) {
|
|
77
|
+
return this.getHostUrlBase(url, 's' + this.settings.serviceId);
|
|
78
|
+
}
|
|
79
|
+
|
|
71
80
|
/**
|
|
72
81
|
* Go to the login page
|
|
73
82
|
* @param tryLogin Try to login again
|
|
@@ -291,10 +300,16 @@ export class ServiceApp<
|
|
|
291
300
|
|
|
292
301
|
/**
|
|
293
302
|
* Try login
|
|
303
|
+
* @param data Additional data
|
|
304
|
+
* @param showLoading Show loading bar or not
|
|
305
|
+
* @returns Result
|
|
294
306
|
*/
|
|
295
|
-
override async tryLogin<D extends {} = {}>(
|
|
307
|
+
override async tryLogin<D extends {} = {}>(
|
|
308
|
+
data?: D,
|
|
309
|
+
showLoading?: boolean
|
|
310
|
+
) {
|
|
296
311
|
// Reset user state
|
|
297
|
-
const result = await super.tryLogin(data);
|
|
312
|
+
const result = await super.tryLogin(data, showLoading);
|
|
298
313
|
if (!result) return false;
|
|
299
314
|
|
|
300
315
|
// Refresh token
|
|
@@ -314,6 +329,7 @@ export class ServiceApp<
|
|
|
314
329
|
});
|
|
315
330
|
},
|
|
316
331
|
data,
|
|
332
|
+
showLoading,
|
|
317
333
|
relogin: true
|
|
318
334
|
});
|
|
319
335
|
}
|
package/src/app/Utils.ts
CHANGED
|
@@ -32,7 +32,6 @@ export namespace Utils {
|
|
|
32
32
|
* @returns History
|
|
33
33
|
*/
|
|
34
34
|
export function getMemoryHistory(initialPath: string = '/') {
|
|
35
|
-
console.log('getMemoryHistory', initialPath);
|
|
36
35
|
if (memoryHistory == null) {
|
|
37
36
|
memoryHistory = createHistory(createMemorySource(initialPath));
|
|
38
37
|
}
|
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,51 @@
|
|
|
1
|
+
import { IconButton, IconButtonProps } 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
|
+
// Click handler
|
|
24
|
+
const onClickLocal = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
25
|
+
if (onClick) onClick(event);
|
|
26
|
+
navigate(-1);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<IconButton
|
|
31
|
+
aria-label="Back"
|
|
32
|
+
color={color}
|
|
33
|
+
size={size}
|
|
34
|
+
onClick={onClickLocal}
|
|
35
|
+
sx={{
|
|
36
|
+
border: (theme) =>
|
|
37
|
+
`1px solid ${
|
|
38
|
+
(() =>
|
|
39
|
+
color != 'inherit' &&
|
|
40
|
+
color != 'default' &&
|
|
41
|
+
color in theme.palette
|
|
42
|
+
? theme.palette[color]
|
|
43
|
+
: theme.palette.primary)().light
|
|
44
|
+
}`
|
|
45
|
+
}}
|
|
46
|
+
{...rest}
|
|
47
|
+
>
|
|
48
|
+
<ArrowBackIcon />
|
|
49
|
+
</IconButton>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -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>
|
|
@@ -165,6 +165,8 @@ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
|
165
165
|
loadData,
|
|
166
166
|
paddings = MUGlobal.pagePaddings,
|
|
167
167
|
supportRefresh = true,
|
|
168
|
+
fabColumnDirection = true,
|
|
169
|
+
supportBack = true,
|
|
168
170
|
...rest
|
|
169
171
|
} = props;
|
|
170
172
|
|
|
@@ -184,7 +186,9 @@ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
|
|
|
184
186
|
onRefresh={supportRefresh ? refresh : undefined}
|
|
185
187
|
onUpdate={supportRefresh ? undefined : refresh}
|
|
186
188
|
{...rest}
|
|
187
|
-
scrollContainer={
|
|
189
|
+
scrollContainer={globalThis}
|
|
190
|
+
fabColumnDirection={fabColumnDirection}
|
|
191
|
+
supportBack={supportBack}
|
|
188
192
|
>
|
|
189
193
|
{data == null ? (
|
|
190
194
|
<LinearProgress />
|