@asaleh37/ui-base 25.9.16 → 25.9.17-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +111 -111
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +112 -112
- package/dist/index.mjs.map +1 -1
- package/index.html +7 -0
- package/package.json +1 -1
- package/public/manifest.json +21 -0
- package/src/components/App.tsx +11 -7
- package/src/components/ExampleTrial.tsx +24 -0
- package/src/components/common/MobileLogin.tsx +229 -0
- package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/ComboBox.tsx +3 -1
- package/src/layout/Layout.tsx +4 -1
- package/src/main.tsx +2 -2
- package/src/navigationItems/index.tsx +1 -1
- package/src/routes/index.ts +1 -1
- package/vite.config.ts +1 -1
package/index.html
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="manifest" href="/manifest.json" />
|
|
6
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
7
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
8
|
+
<meta
|
|
9
|
+
name="apple-mobile-web-app-status-bar-style"
|
|
10
|
+
content="black-translucent"
|
|
11
|
+
/>
|
|
5
12
|
<link rel="icon" type="image/svg+xml" href="/logo.png" />
|
|
6
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
14
|
<title>Loading...</title>
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "MyApp",
|
|
3
|
+
"name": "My React App",
|
|
4
|
+
"start_url": ".",
|
|
5
|
+
"display": "standalone",
|
|
6
|
+
"background_color": "#ffffff",
|
|
7
|
+
"theme_color": "#ffffff",
|
|
8
|
+
"orientation": "portrait",
|
|
9
|
+
"icons": [
|
|
10
|
+
{
|
|
11
|
+
"src": "icon-192x192.png",
|
|
12
|
+
"sizes": "192x192",
|
|
13
|
+
"type": "image/png"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"src": "icon-512x512.png",
|
|
17
|
+
"sizes": "512x512",
|
|
18
|
+
"type": "image/png"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
package/src/components/App.tsx
CHANGED
|
@@ -18,13 +18,17 @@ import { MsalProvider } from "@azure/msal-react";
|
|
|
18
18
|
|
|
19
19
|
const App: React.FC<AppInfo> = (props: AppInfo) => {
|
|
20
20
|
const dispatch = useDispatch();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
let msalInstance;
|
|
22
|
+
if (props?.authenticationMethod === "AZURE") {
|
|
23
|
+
msalInstance = new PublicClientApplication({
|
|
24
|
+
auth: {
|
|
25
|
+
clientId: props?.azureConfiguration?.frontEndClientId,
|
|
26
|
+
authority: `https://login.microsoftonline.com/${props?.azureConfiguration?.tenantId}`,
|
|
27
|
+
redirectUri: props?.azureConfiguration?.redirectURL,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
LicenseInfo.setLicenseKey(props.muiPremiumKey);
|
|
29
33
|
const LightThemeOptions: ThemeOptions = {
|
|
30
34
|
components: {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useApiActions } from "../hooks";
|
|
2
|
+
import { FormElementProps, TemplateForm } from "./templates";
|
|
3
|
+
|
|
4
|
+
const ExampleTrial: React.FC = () => {
|
|
5
|
+
const formElements: FormElementProps[] = [
|
|
6
|
+
{
|
|
7
|
+
mode: "props",
|
|
8
|
+
type: "field",
|
|
9
|
+
props: {
|
|
10
|
+
fieldLabel: "test",
|
|
11
|
+
fieldName: "test",
|
|
12
|
+
fieldType: "combobox",
|
|
13
|
+
commonStoreKey: "SystemParameterTypes",
|
|
14
|
+
optionValueField: "value",
|
|
15
|
+
optionDisplayField: "value",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
const apiActions = useApiActions({});
|
|
20
|
+
|
|
21
|
+
return <TemplateForm apiActions={apiActions} elements={formElements} />;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ExampleTrial;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
Button,
|
|
4
|
+
CircularProgress,
|
|
5
|
+
createTheme,
|
|
6
|
+
Paper,
|
|
7
|
+
TextField,
|
|
8
|
+
Typography,
|
|
9
|
+
} from "@mui/material";
|
|
10
|
+
import { useDispatch, useSelector } from "react-redux";
|
|
11
|
+
import { ThemeProvider } from "@emotion/react";
|
|
12
|
+
import { useEffect, useState } from "react";
|
|
13
|
+
import axios from "axios";
|
|
14
|
+
import { toast } from "react-toastify";
|
|
15
|
+
import { UserSessionActions } from "../../redux/features/common/UserSessionSlice";
|
|
16
|
+
import {
|
|
17
|
+
DARK_THEME_INITIAL_MAIN_COLOR,
|
|
18
|
+
DARK_THEME_INITIAL_SECANDARY_COLOR,
|
|
19
|
+
LIGHT_THEME_INITIAL_MAIN_COLOR,
|
|
20
|
+
LIGHT_THEME_INITIAL_SECANDARY_COLOR,
|
|
21
|
+
} from "../../util";
|
|
22
|
+
import { AppInfo } from "../../redux/features/common/AppInfoSlice";
|
|
23
|
+
const MobileLogin: React.FC = () => {
|
|
24
|
+
const appInfo: AppInfo = useSelector((state: any) => state.AppInfo.value);
|
|
25
|
+
const [username, setUsername] = useState("");
|
|
26
|
+
const [password, setPassword] = useState("");
|
|
27
|
+
const [isLoginInProcess, setIsLoginInProcess] = useState(false);
|
|
28
|
+
const UserSessionState = useSelector((state: any) => state.UserSession.value);
|
|
29
|
+
const dispatch = useDispatch();
|
|
30
|
+
const handleLogin = async () => {
|
|
31
|
+
if (username == null || username == "") {
|
|
32
|
+
toast.error("username is required to proceed");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (password == null || password == "") {
|
|
36
|
+
toast.error("password is required to proceed");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
setIsLoginInProcess(true);
|
|
40
|
+
let response: any = null;
|
|
41
|
+
try {
|
|
42
|
+
response = await axios.post(
|
|
43
|
+
`${appInfo.apiBaseUrl}/api/auth/login`,
|
|
44
|
+
{
|
|
45
|
+
username,
|
|
46
|
+
password,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
withCredentials: true,
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
if (response.data != null && response.data !== "") {
|
|
53
|
+
setIsLoginInProcess(false);
|
|
54
|
+
const UserSession = {
|
|
55
|
+
...response.data,
|
|
56
|
+
isAuthenticated: true,
|
|
57
|
+
};
|
|
58
|
+
if (response?.data?.token) {
|
|
59
|
+
localStorage.setItem("TOKEN", response.data.token);
|
|
60
|
+
}
|
|
61
|
+
dispatch(UserSessionActions.setAuthenticated(UserSession));
|
|
62
|
+
}
|
|
63
|
+
} catch (e: any) {
|
|
64
|
+
setIsLoginInProcess(false);
|
|
65
|
+
toast.error(
|
|
66
|
+
e?.response?.data ||
|
|
67
|
+
"failed to authenticate, contact your administrator"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const userSession = useSelector((state: any) => state.UserSession.value);
|
|
72
|
+
const loginTheme = createTheme({
|
|
73
|
+
components: {
|
|
74
|
+
MuiCssBaseline: {
|
|
75
|
+
styleOverrides: `
|
|
76
|
+
/* Custom Scrollbar */
|
|
77
|
+
* {
|
|
78
|
+
scrollbar-width: thin;
|
|
79
|
+
scrollbar-color: ${
|
|
80
|
+
appInfo.appTheme?.dark?.primaryColor ||
|
|
81
|
+
DARK_THEME_INITIAL_MAIN_COLOR
|
|
82
|
+
} #121212;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Webkit Browsers */
|
|
86
|
+
*::-webkit-scrollbar {
|
|
87
|
+
width: 12px;
|
|
88
|
+
height: 10px;
|
|
89
|
+
}
|
|
90
|
+
`,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
palette: {
|
|
94
|
+
mode: appInfo?.loginScreenStyle?.themeMode || "dark",
|
|
95
|
+
primary: {
|
|
96
|
+
main:
|
|
97
|
+
appInfo?.loginScreenStyle?.themeMode === "light"
|
|
98
|
+
? appInfo.appTheme?.light?.primaryColor ||
|
|
99
|
+
LIGHT_THEME_INITIAL_MAIN_COLOR
|
|
100
|
+
: appInfo.appTheme?.dark?.primaryColor ||
|
|
101
|
+
DARK_THEME_INITIAL_MAIN_COLOR,
|
|
102
|
+
},
|
|
103
|
+
secondary: {
|
|
104
|
+
main:
|
|
105
|
+
appInfo?.loginScreenStyle?.themeMode === "light"
|
|
106
|
+
? appInfo.appTheme?.light?.secondaryColor ||
|
|
107
|
+
LIGHT_THEME_INITIAL_SECANDARY_COLOR
|
|
108
|
+
: appInfo.appTheme?.dark?.secondaryColor ||
|
|
109
|
+
DARK_THEME_INITIAL_SECANDARY_COLOR,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const checkUserSession = async () => {
|
|
114
|
+
if (appInfo?.apiBaseUrl) {
|
|
115
|
+
if (userSession.isAuthenticated == null) {
|
|
116
|
+
const token = localStorage.getItem("TOKEN");
|
|
117
|
+
try {
|
|
118
|
+
let response = await axios.get(
|
|
119
|
+
`${appInfo.apiBaseUrl}/api/auth/userInfo`,
|
|
120
|
+
{
|
|
121
|
+
withCredentials: true,
|
|
122
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
if (response != null && response.data != null) {
|
|
126
|
+
const UserSession = {
|
|
127
|
+
...response.data,
|
|
128
|
+
isAuthenticated: true,
|
|
129
|
+
};
|
|
130
|
+
dispatch(UserSessionActions.setAuthenticated(UserSession));
|
|
131
|
+
} else {
|
|
132
|
+
dispatch(UserSessionActions.setUnAuthenticated());
|
|
133
|
+
localStorage.removeItem("TOKEN");
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
dispatch(UserSessionActions.setUnAuthenticated());
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
checkUserSession();
|
|
143
|
+
}, [appInfo, userSession.isAuthenticated]);
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<ThemeProvider theme={loginTheme}>
|
|
147
|
+
{UserSessionState.isAuthenticated == false ? (
|
|
148
|
+
<Paper
|
|
149
|
+
sx={{
|
|
150
|
+
display: "flex",
|
|
151
|
+
flexDirection: "column",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
justifyContent: "center",
|
|
154
|
+
height: "100vh",
|
|
155
|
+
width: "100%",
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
<img src={appInfo?.appLogo} width={70} height={70} />
|
|
159
|
+
<Typography sx={{ m: 1 }} variant="caption" color="textSecondary">
|
|
160
|
+
{appInfo?.appName}
|
|
161
|
+
</Typography>
|
|
162
|
+
<Typography
|
|
163
|
+
sx={{
|
|
164
|
+
paddingRight: 1,
|
|
165
|
+
width: 200,
|
|
166
|
+
textAlign: "right",
|
|
167
|
+
fontSize: 10,
|
|
168
|
+
}}
|
|
169
|
+
variant="caption"
|
|
170
|
+
color="textSecondary"
|
|
171
|
+
>
|
|
172
|
+
V.{appInfo.appVersion}
|
|
173
|
+
</Typography>
|
|
174
|
+
<TextField
|
|
175
|
+
label="username"
|
|
176
|
+
sx={{ width: 200, m: 1 }}
|
|
177
|
+
value={username}
|
|
178
|
+
onChange={(event) => {
|
|
179
|
+
setUsername(event.target.value);
|
|
180
|
+
}}
|
|
181
|
+
onKeyDown={(event) => {
|
|
182
|
+
if (event.key === "Enter") {
|
|
183
|
+
handleLogin();
|
|
184
|
+
}
|
|
185
|
+
}}
|
|
186
|
+
/>
|
|
187
|
+
<TextField
|
|
188
|
+
label="password"
|
|
189
|
+
sx={{ width: 200, m: 1 }}
|
|
190
|
+
value={password}
|
|
191
|
+
type="password"
|
|
192
|
+
onChange={(event) => {
|
|
193
|
+
setPassword(event.target.value);
|
|
194
|
+
}}
|
|
195
|
+
onKeyDown={(event) => {
|
|
196
|
+
if (event.key === "Enter") {
|
|
197
|
+
handleLogin();
|
|
198
|
+
}
|
|
199
|
+
}}
|
|
200
|
+
/>
|
|
201
|
+
<Button
|
|
202
|
+
loading={isLoginInProcess}
|
|
203
|
+
onClick={handleLogin}
|
|
204
|
+
variant="contained"
|
|
205
|
+
color="primary"
|
|
206
|
+
sx={{ m: 1 }}
|
|
207
|
+
>
|
|
208
|
+
login
|
|
209
|
+
</Button>
|
|
210
|
+
</Paper>
|
|
211
|
+
) : (
|
|
212
|
+
<Paper
|
|
213
|
+
sx={{
|
|
214
|
+
width: "100%",
|
|
215
|
+
height: "100vh",
|
|
216
|
+
display: "flex",
|
|
217
|
+
alignItems: "center",
|
|
218
|
+
justifyContent: "center",
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
<CircularProgress sx={{ marginRight: 1 }} />
|
|
222
|
+
<div>You will be redirected shortly ... please wait</div>
|
|
223
|
+
</Paper>
|
|
224
|
+
)}
|
|
225
|
+
</ThemeProvider>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export default MobileLogin;
|
package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/ComboBox.tsx
CHANGED
|
@@ -73,11 +73,13 @@ const ComboBox: React.FC<ComboBoxProps> = (props) => {
|
|
|
73
73
|
props?.storeLoadParam,
|
|
74
74
|
props?.dataQueryId,
|
|
75
75
|
props?.commonStoreKey,
|
|
76
|
+
props?.options,
|
|
77
|
+
commonStoreData,
|
|
76
78
|
]);
|
|
77
79
|
|
|
78
80
|
const { t } = useTranslation();
|
|
79
81
|
const getValue = (v: string) => {
|
|
80
|
-
for (let option of
|
|
82
|
+
for (let option of comboboxData) {
|
|
81
83
|
if (option[props.valueField] == v) {
|
|
82
84
|
return option;
|
|
83
85
|
}
|
package/src/layout/Layout.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import NoLicenseComponent from "../components/common/NoLicenseComponent";
|
|
|
17
17
|
import { msalInstance } from "../components/msalConfig";
|
|
18
18
|
import { PublicClientApplication } from "@azure/msal-browser";
|
|
19
19
|
import AzureLogin from "../components/common/AzureLogin";
|
|
20
|
+
import MobileLogin from "../components/common/MobileLogin";
|
|
20
21
|
|
|
21
22
|
const Main = styled("main", {
|
|
22
23
|
shouldForwardProp: (prop) => prop !== "open",
|
|
@@ -89,8 +90,10 @@ const Layout: React.FC<LayoutProps> = ({ msalInstance }) => {
|
|
|
89
90
|
</Main>
|
|
90
91
|
) : appInfo.authenticationMethod === "AZURE" ? (
|
|
91
92
|
<AzureLogin msalInstance={msalInstance} />
|
|
92
|
-
) : (
|
|
93
|
+
) : !isMobile ? (
|
|
93
94
|
<Login />
|
|
95
|
+
) : (
|
|
96
|
+
<MobileLogin />
|
|
94
97
|
)}
|
|
95
98
|
</BrowserRouter>
|
|
96
99
|
);
|
package/src/main.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { BaseApp } from "./components";
|
|
|
3
3
|
|
|
4
4
|
createRoot(document.getElementById("root")!).render(
|
|
5
5
|
<BaseApp
|
|
6
|
-
apiBaseUrl="http://
|
|
6
|
+
apiBaseUrl="http://10.14.22.13:8080/api-base"
|
|
7
7
|
enableUINotifications={false}
|
|
8
8
|
appLogo={"/logo.png"}
|
|
9
9
|
appName="UI Base Library"
|
|
@@ -12,7 +12,7 @@ createRoot(document.getElementById("root")!).render(
|
|
|
12
12
|
backgroundImageNameInPublicFolder: "bg.jpg",
|
|
13
13
|
}}
|
|
14
14
|
appVersion="0.0"
|
|
15
|
-
authenticationMethod="
|
|
15
|
+
authenticationMethod="APP"
|
|
16
16
|
azureConfiguration={{
|
|
17
17
|
frontEndClientId: "c3bbbdbd-f392-4459-b3dd-2351cb07f924",
|
|
18
18
|
tenantId: "9f136fef-4529-475f-98e6-d271eb04eb00",
|
package/src/routes/index.ts
CHANGED