@ebubekirylmaz/link-test 1.2.43 → 1.2.45
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/package.json +9 -6
- package/src/Platform.jsx +14 -15
- package/src/config/schemas.js +1 -0
- package/src/context/Context.js +98 -0
- package/src/context/reducer.js +590 -10
- package/src/hooks/index.js +2 -1
- package/src/hooks/use-beta.js +8 -0
- package/src/layouts/auth/modern.jsx +4 -2
- package/src/layouts/common/account-popover.jsx +1 -2
- package/src/lib/APIDialogAction/APIDialogAction.jsx +109 -0
- package/src/lib/APIDialogAction/index.js +1 -0
- package/src/lib/APIDialogAction/styles.js +6 -0
- package/src/lib/APIParams/APIParams.jsx +57 -0
- package/src/lib/APIParams/index.js +1 -0
- package/src/lib/APIPath/APIPath.jsx +82 -0
- package/src/lib/APIPath/index.js +1 -0
- package/src/lib/APIPath/styles.js +19 -0
- package/src/lib/APITree/APITree.jsx +409 -0
- package/src/lib/APITree/Arrow.jsx +21 -0
- package/src/lib/APITree/DeleteMethodDialog.jsx +41 -0
- package/src/lib/APITree/index.js +1 -0
- package/src/lib/APITree/styles.js +19 -0
- package/src/lib/APITypes/APITypes.jsx +141 -0
- package/src/lib/APITypes/TypeEditor.jsx +46 -0
- package/src/lib/APITypes/TypeList.jsx +180 -0
- package/src/lib/APITypes/index.js +1 -0
- package/src/lib/BlankTreeMessage/BlankTreeMessage.jsx +39 -0
- package/src/lib/BlankTreeMessage/index.js +1 -0
- package/src/lib/DialogTootip/DialogTooltip.jsx +67 -0
- package/src/lib/DialogTootip/index.js +1 -0
- package/src/lib/DialogTootip/styles.js +9 -0
- package/src/lib/Flow/connectors/DynamicConnector.jsx +179 -107
- package/src/lib/Flow/core/Flow.jsx +2 -0
- package/src/lib/Flow/core/FlowNode.jsx +2 -0
- package/src/lib/Flow/core/FlowViewport.jsx +41 -9
- package/src/lib/Flow/hooks/useNodeStyle.js +14 -0
- package/src/lib/Flow/nodes/FlowNodeView.jsx +105 -21
- package/src/lib/Flow/styles.js +4 -0
- package/src/lib/NewApiBody/NewAPIBody.jsx +97 -0
- package/src/lib/NewApiBody/ParamView.jsx +38 -0
- package/src/lib/NucDialog/NucDialog.jsx +108 -0
- package/src/lib/NucDialog/index.js +1 -0
- package/src/lib/ParamTable/ParamTable.jsx +133 -0
- package/src/lib/ParamTable/TypeMenu.jsx +102 -0
- package/src/lib/ParamTable/defaults.js +47 -0
- package/src/lib/ParamTable/index.js +1 -0
- package/src/lib/ParamTable/styles.js +12 -0
- package/src/lib/ResourceMenu/AlertMassage.jsx +28 -0
- package/src/lib/ResourceMenu/DeleteResourceDialog.jsx +60 -0
- package/src/lib/ResourceMenu/ResourceMenu.jsx +156 -0
- package/src/lib/ResourceMenu/index.js +1 -0
- package/src/lib/ResourceMenu/styles.js +5 -0
- package/src/lib/Schema/Schema.jsx +204 -0
- package/src/lib/Schema/index.js +1 -0
- package/src/lib/SchemaEditor/SchemaEditor.jsx +258 -0
- package/src/lib/SchemaEditor/SchemaEditor.test.js +193 -0
- package/src/lib/SchemaEditor/SchemaPropertyEditor.jsx +135 -0
- package/src/lib/SchemaEditor/SchemaUtils.js +152 -0
- package/src/lib/SchemaEditor/index.js +1 -0
- package/src/lib/ToggleableMenu/ToggleableMenu.jsx +35 -0
- package/src/lib/ToggleableMenu/index.js +1 -0
- package/src/lib/index.js +14 -0
- package/src/pages/Callback.jsx +6 -8
- package/src/pages/LoginPage.jsx +3 -12
- package/src/stories/APITree.stories.jsx +429 -0
- package/src/stories/FlowChart.stories.jsx +1 -1
- package/src/templates/ActionTemplate.js +24 -0
- package/src/widgets/Login/CognitoLogin.jsx +212 -41
- package/src/widgets/Login/DemoLogin.jsx +9 -7
- package/src/widgets/Login/amplifyAuth.js +6 -6
- package/src/widgets/Login/amplifyConfig.js +3 -0
- package/src/widgets/LoginForm/LoginForm.jsx +8 -3
- package/src/widgets/SettingsDialog.jsx +171 -7
|
@@ -4,20 +4,56 @@ import { storage } from "@nucleoidjs/webstorage";
|
|
|
4
4
|
import { useNavigate } from "react-router-dom";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Box,
|
|
9
|
+
Button,
|
|
10
|
+
IconButton,
|
|
11
|
+
InputAdornment,
|
|
12
|
+
Stack,
|
|
13
|
+
TextField,
|
|
14
|
+
Typography,
|
|
15
|
+
alpha,
|
|
16
|
+
} from "@mui/material";
|
|
17
|
+
import {
|
|
18
|
+
CheckOutlined,
|
|
19
|
+
EmailOutlined,
|
|
20
|
+
LockOutlined,
|
|
21
|
+
MarkEmailReadOutlined,
|
|
22
|
+
Visibility,
|
|
23
|
+
VisibilityOff,
|
|
24
|
+
} from "@mui/icons-material";
|
|
8
25
|
import { confirmSignup, getTokens, login, signup } from "./amplifyAuth";
|
|
9
26
|
|
|
27
|
+
const inputSx = {
|
|
28
|
+
"& .MuiOutlinedInput-root": {
|
|
29
|
+
fontSize: "1rem",
|
|
30
|
+
"& input": { py: 1.5 },
|
|
31
|
+
"&:hover fieldset": { borderColor: "primary.main" },
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const primaryButtonSx = {
|
|
36
|
+
py: 1.5,
|
|
37
|
+
fontSize: "1rem",
|
|
38
|
+
fontWeight: 600,
|
|
39
|
+
textTransform: "none",
|
|
40
|
+
borderRadius: 1.5,
|
|
41
|
+
"&:active": { transform: "translateY(0px)" },
|
|
42
|
+
};
|
|
43
|
+
|
|
10
44
|
export default function CognitoLogin() {
|
|
11
45
|
const [mode, setMode] = useState("login");
|
|
12
46
|
|
|
13
|
-
const [username, setUsername] = useState("");
|
|
14
47
|
const [email, setEmail] = useState("");
|
|
15
48
|
const [password, setPassword] = useState("");
|
|
49
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
16
50
|
const [code, setCode] = useState("");
|
|
51
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
52
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
|
17
53
|
|
|
18
54
|
const navigate = useNavigate();
|
|
19
55
|
|
|
20
|
-
const { appId } = config();
|
|
56
|
+
const { appId, credentials } = config();
|
|
21
57
|
|
|
22
58
|
const handleLogin = async () => {
|
|
23
59
|
try {
|
|
@@ -27,7 +63,9 @@ export default function CognitoLogin() {
|
|
|
27
63
|
if (!tokens?.accessToken)
|
|
28
64
|
throw new Error("No Cognito access token received");
|
|
29
65
|
|
|
30
|
-
const
|
|
66
|
+
const requestUrl = credentials.requestUrl || "/api/oauth";
|
|
67
|
+
|
|
68
|
+
const res = await fetch(requestUrl, {
|
|
31
69
|
method: "POST",
|
|
32
70
|
headers: { "Content-Type": "application/json" },
|
|
33
71
|
body: JSON.stringify({
|
|
@@ -59,7 +97,7 @@ export default function CognitoLogin() {
|
|
|
59
97
|
|
|
60
98
|
const handleSignup = async () => {
|
|
61
99
|
try {
|
|
62
|
-
await signup(email, password
|
|
100
|
+
await signup(email, password);
|
|
63
101
|
publish("GLOBAL_MESSAGE_POSTED", {
|
|
64
102
|
status: true,
|
|
65
103
|
message:
|
|
@@ -94,36 +132,128 @@ export default function CognitoLogin() {
|
|
|
94
132
|
}
|
|
95
133
|
};
|
|
96
134
|
|
|
135
|
+
const titles = {
|
|
136
|
+
login: { heading: "Sign in", sub: "Welcome back! Enter your credentials." },
|
|
137
|
+
signup: {
|
|
138
|
+
heading: "Create account",
|
|
139
|
+
sub: "Sign up to get started for free.",
|
|
140
|
+
},
|
|
141
|
+
confirm: {
|
|
142
|
+
heading: "Verify your email",
|
|
143
|
+
sub: "Enter the confirmation code sent to your inbox.",
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const passwordAdornment = (
|
|
148
|
+
<InputAdornment position="end">
|
|
149
|
+
<IconButton
|
|
150
|
+
onClick={() => setShowPassword(!showPassword)}
|
|
151
|
+
edge="end"
|
|
152
|
+
size="small"
|
|
153
|
+
tabIndex={-1}
|
|
154
|
+
>
|
|
155
|
+
{showPassword ? <VisibilityOff /> : <Visibility />}
|
|
156
|
+
</IconButton>
|
|
157
|
+
</InputAdornment>
|
|
158
|
+
);
|
|
159
|
+
|
|
97
160
|
return (
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
161
|
+
<Stack spacing={3} sx={{ mb: 2 }}>
|
|
162
|
+
<Box sx={{ textAlign: "center" }}>
|
|
163
|
+
<Box
|
|
164
|
+
sx={{
|
|
165
|
+
width: 52,
|
|
166
|
+
height: 52,
|
|
167
|
+
borderRadius: 2,
|
|
168
|
+
display: "inline-flex",
|
|
169
|
+
alignItems: "center",
|
|
170
|
+
justifyContent: "center",
|
|
171
|
+
mb: 2,
|
|
172
|
+
bgcolor: (theme) => alpha(theme.palette.primary.main, 0.1),
|
|
173
|
+
color: "primary.main",
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
{mode === "confirm" ? (
|
|
177
|
+
<MarkEmailReadOutlined sx={{ fontSize: 26 }} />
|
|
178
|
+
) : (
|
|
179
|
+
<LockOutlined sx={{ fontSize: 26 }} />
|
|
180
|
+
)}
|
|
181
|
+
</Box>
|
|
182
|
+
|
|
183
|
+
<Typography variant="h4" fontWeight={700} gutterBottom>
|
|
184
|
+
{titles[mode].heading}
|
|
185
|
+
</Typography>
|
|
186
|
+
<Typography variant="body2" color="text.secondary">
|
|
187
|
+
{titles[mode].sub}
|
|
188
|
+
</Typography>
|
|
189
|
+
</Box>
|
|
104
190
|
|
|
105
191
|
<Stack spacing={2}>
|
|
106
192
|
<TextField
|
|
107
193
|
label="Email"
|
|
108
194
|
value={email}
|
|
109
195
|
onChange={(e) => setEmail(e.target.value)}
|
|
196
|
+
fullWidth
|
|
197
|
+
InputProps={{
|
|
198
|
+
startAdornment: (
|
|
199
|
+
<InputAdornment position="start">
|
|
200
|
+
<EmailOutlined sx={{ color: "text.secondary", fontSize: 22 }} />
|
|
201
|
+
</InputAdornment>
|
|
202
|
+
),
|
|
203
|
+
}}
|
|
204
|
+
sx={inputSx}
|
|
110
205
|
/>
|
|
111
206
|
|
|
112
|
-
{mode
|
|
207
|
+
{mode !== "confirm" && (
|
|
113
208
|
<TextField
|
|
114
|
-
type="password"
|
|
209
|
+
type={showPassword ? "text" : "password"}
|
|
115
210
|
label="Password"
|
|
116
211
|
value={password}
|
|
117
212
|
onChange={(e) => setPassword(e.target.value)}
|
|
213
|
+
fullWidth
|
|
214
|
+
InputProps={{
|
|
215
|
+
startAdornment: (
|
|
216
|
+
<InputAdornment position="start">
|
|
217
|
+
<LockOutlined
|
|
218
|
+
sx={{ color: "text.secondary", fontSize: 22 }}
|
|
219
|
+
/>
|
|
220
|
+
</InputAdornment>
|
|
221
|
+
),
|
|
222
|
+
endAdornment: passwordAdornment,
|
|
223
|
+
}}
|
|
224
|
+
sx={inputSx}
|
|
118
225
|
/>
|
|
119
226
|
)}
|
|
120
227
|
|
|
121
|
-
{mode
|
|
228
|
+
{mode === "signup" && (
|
|
122
229
|
<TextField
|
|
123
|
-
type="password"
|
|
124
|
-
label="Password"
|
|
125
|
-
value={
|
|
126
|
-
onChange={(e) =>
|
|
230
|
+
type={showConfirmPassword ? "text" : "password"}
|
|
231
|
+
label="Confirm Password"
|
|
232
|
+
value={confirmPassword}
|
|
233
|
+
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
234
|
+
fullWidth
|
|
235
|
+
InputProps={{
|
|
236
|
+
startAdornment: (
|
|
237
|
+
<InputAdornment position="start">
|
|
238
|
+
<LockOutlined
|
|
239
|
+
sx={{ color: "text.secondary", fontSize: 22 }}
|
|
240
|
+
/>
|
|
241
|
+
</InputAdornment>
|
|
242
|
+
),
|
|
243
|
+
endAdornment: (
|
|
244
|
+
<InputAdornment position="end">
|
|
245
|
+
<IconButton
|
|
246
|
+
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
|
247
|
+
edge="end"
|
|
248
|
+
size="small"
|
|
249
|
+
tabIndex={-1}
|
|
250
|
+
>
|
|
251
|
+
{showConfirmPassword ? <VisibilityOff /> : <Visibility />}
|
|
252
|
+
</IconButton>
|
|
253
|
+
</InputAdornment>
|
|
254
|
+
),
|
|
255
|
+
}}
|
|
256
|
+
sx={inputSx}
|
|
127
257
|
/>
|
|
128
258
|
)}
|
|
129
259
|
|
|
@@ -132,33 +262,74 @@ export default function CognitoLogin() {
|
|
|
132
262
|
label="Confirmation Code"
|
|
133
263
|
value={code}
|
|
134
264
|
onChange={(e) => setCode(e.target.value)}
|
|
265
|
+
fullWidth
|
|
266
|
+
InputProps={{
|
|
267
|
+
startAdornment: (
|
|
268
|
+
<InputAdornment position="start">
|
|
269
|
+
<CheckOutlined
|
|
270
|
+
sx={{ color: "text.secondary", fontSize: 22 }}
|
|
271
|
+
/>
|
|
272
|
+
</InputAdornment>
|
|
273
|
+
),
|
|
274
|
+
}}
|
|
275
|
+
sx={inputSx}
|
|
135
276
|
/>
|
|
136
277
|
)}
|
|
278
|
+
</Stack>
|
|
137
279
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
280
|
+
{mode === "login" && (
|
|
281
|
+
<Stack spacing={1.5}>
|
|
282
|
+
<Button
|
|
283
|
+
variant="contained"
|
|
284
|
+
onClick={handleLogin}
|
|
285
|
+
size="large"
|
|
286
|
+
fullWidth
|
|
287
|
+
sx={primaryButtonSx}
|
|
288
|
+
>
|
|
289
|
+
Sign in
|
|
290
|
+
</Button>
|
|
291
|
+
<Button
|
|
292
|
+
onClick={() => setMode("signup")}
|
|
293
|
+
fullWidth
|
|
294
|
+
sx={{ textTransform: "none", fontWeight: 500 }}
|
|
295
|
+
>
|
|
296
|
+
Create an account
|
|
297
|
+
</Button>
|
|
298
|
+
</Stack>
|
|
299
|
+
)}
|
|
155
300
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
301
|
+
{mode === "signup" && (
|
|
302
|
+
<Stack spacing={1.5}>
|
|
303
|
+
<Button
|
|
304
|
+
variant="contained"
|
|
305
|
+
onClick={handleSignup}
|
|
306
|
+
size="large"
|
|
307
|
+
fullWidth
|
|
308
|
+
sx={primaryButtonSx}
|
|
309
|
+
>
|
|
310
|
+
Sign Up
|
|
159
311
|
</Button>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
312
|
+
<Button
|
|
313
|
+
onClick={() => setMode("login")}
|
|
314
|
+
fullWidth
|
|
315
|
+
sx={{ textTransform: "none", fontWeight: 500 }}
|
|
316
|
+
>
|
|
317
|
+
Back to login
|
|
318
|
+
</Button>
|
|
319
|
+
</Stack>
|
|
320
|
+
)}
|
|
321
|
+
|
|
322
|
+
{mode === "confirm" && (
|
|
323
|
+
<Button
|
|
324
|
+
variant="contained"
|
|
325
|
+
onClick={handleConfirm}
|
|
326
|
+
size="large"
|
|
327
|
+
fullWidth
|
|
328
|
+
sx={primaryButtonSx}
|
|
329
|
+
>
|
|
330
|
+
Confirm
|
|
331
|
+
</Button>
|
|
332
|
+
)}
|
|
333
|
+
</Stack>
|
|
163
334
|
);
|
|
164
335
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import config from "../../config/config";
|
|
2
|
+
import { storage } from "@nucleoidjs/webstorage";
|
|
3
|
+
import { useNavigate } from "react-router-dom";
|
|
4
|
+
|
|
1
5
|
import {
|
|
2
6
|
Box,
|
|
3
7
|
Button,
|
|
@@ -16,20 +20,18 @@ import {
|
|
|
16
20
|
} from "@mui/icons-material";
|
|
17
21
|
import React, { useState } from "react";
|
|
18
22
|
|
|
19
|
-
import config from "../../config/config";
|
|
20
|
-
import { storage } from "@nucleoidjs/webstorage";
|
|
21
|
-
import { useNavigate } from "react-router-dom";
|
|
22
|
-
|
|
23
23
|
export default function DemoLogin() {
|
|
24
24
|
const [username, setUsername] = useState("");
|
|
25
25
|
const [password, setPassword] = useState("");
|
|
26
26
|
const [showPassword, setShowPassword] = useState(false);
|
|
27
27
|
const navigate = useNavigate();
|
|
28
28
|
|
|
29
|
-
const { appId } = config();
|
|
29
|
+
const { appId, credentials } = config();
|
|
30
30
|
|
|
31
31
|
async function handleLogin() {
|
|
32
|
-
const
|
|
32
|
+
const requestUrl = credentials.requestUrl || "/api/oauth";
|
|
33
|
+
|
|
34
|
+
const res = await fetch(requestUrl, {
|
|
33
35
|
method: "POST",
|
|
34
36
|
headers: { "Content-Type": "application/json" },
|
|
35
37
|
body: JSON.stringify({
|
|
@@ -53,7 +55,7 @@ export default function DemoLogin() {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
|
-
<Stack spacing={2.5}>
|
|
58
|
+
<Stack spacing={2.5} sx={{ mb: 2 }}>
|
|
57
59
|
<Stack spacing={2}>
|
|
58
60
|
<TextField
|
|
59
61
|
label="Username"
|
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
signUp,
|
|
7
7
|
} from "aws-amplify/auth";
|
|
8
8
|
|
|
9
|
-
export async function login(
|
|
10
|
-
return signIn({ username, password });
|
|
9
|
+
export async function login(email, password) {
|
|
10
|
+
return signIn({ username: email, password });
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export async function signup(
|
|
13
|
+
export async function signup(email, password) {
|
|
14
14
|
return signUp({
|
|
15
|
-
username,
|
|
15
|
+
username: email,
|
|
16
16
|
password,
|
|
17
17
|
options: {
|
|
18
18
|
userAttributes: {
|
|
@@ -22,9 +22,9 @@ export async function signup(username, password, email) {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export async function confirmSignup(
|
|
25
|
+
export async function confirmSignup(email, code) {
|
|
26
26
|
return confirmSignUp({
|
|
27
|
-
username,
|
|
27
|
+
username: email,
|
|
28
28
|
confirmationCode: code,
|
|
29
29
|
});
|
|
30
30
|
}
|
|
@@ -18,12 +18,17 @@ const handleOAuthLogin = (
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
function LoginForm() {
|
|
21
|
-
const { name, project } = config();
|
|
21
|
+
const { name, project, credentials } = config();
|
|
22
22
|
|
|
23
23
|
const [email, setEmail] = useState("");
|
|
24
24
|
const [password, setPassword] = useState("");
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const providerCheck =
|
|
27
|
+
credentials?.provider === "COGNITO" || credentials?.provider === "DEMO";
|
|
28
|
+
|
|
29
|
+
const hasContent = !providerCheck || !!project.nucleoid;
|
|
30
|
+
|
|
31
|
+
const renderHead = hasContent ? (
|
|
27
32
|
<Stack spacing={2} sx={{ mb: 5 }}>
|
|
28
33
|
<Typography variant="h4">Sign in to {name}</Typography>
|
|
29
34
|
{project.nucleoid && (
|
|
@@ -34,7 +39,7 @@ function LoginForm() {
|
|
|
34
39
|
</Stack>
|
|
35
40
|
)}
|
|
36
41
|
</Stack>
|
|
37
|
-
);
|
|
42
|
+
) : null;
|
|
38
43
|
|
|
39
44
|
const renderForm = (
|
|
40
45
|
<>
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import Iconify from "../components/Iconify";
|
|
2
|
+
import config from "../config/config";
|
|
3
|
+
import { useEvent } from "@nucleoidai/react-event";
|
|
4
|
+
import useSettings from "../hooks/useSettings";
|
|
5
|
+
import { useSettingsContext } from "../components/settings/context";
|
|
6
|
+
import { useUser } from "../hooks/use-user";
|
|
7
|
+
|
|
1
8
|
import {
|
|
2
9
|
Avatar,
|
|
3
10
|
Box,
|
|
11
|
+
Chip,
|
|
4
12
|
FormControl,
|
|
5
13
|
Grow,
|
|
6
14
|
IconButton,
|
|
7
15
|
InputLabel,
|
|
16
|
+
Link,
|
|
8
17
|
List,
|
|
9
18
|
ListItem,
|
|
10
19
|
ListItemAvatar,
|
|
@@ -12,6 +21,7 @@ import {
|
|
|
12
21
|
ListItemText,
|
|
13
22
|
NativeSelect,
|
|
14
23
|
Stack,
|
|
24
|
+
Switch,
|
|
15
25
|
Tab,
|
|
16
26
|
Tabs,
|
|
17
27
|
TextField,
|
|
@@ -20,11 +30,17 @@ import {
|
|
|
20
30
|
import { Button, Dialog, DialogActions, DialogContent } from "@mui/material";
|
|
21
31
|
import React, { useEffect, useState } from "react";
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
let pkg = {
|
|
34
|
+
name: "",
|
|
35
|
+
version: "",
|
|
36
|
+
description: "",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
pkg = require("../../../../../../package.json");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error("Failed to load package.json for About tab:", error);
|
|
43
|
+
}
|
|
28
44
|
|
|
29
45
|
function a11yProps(index) {
|
|
30
46
|
return {
|
|
@@ -42,6 +58,9 @@ const TabPanel = (props) => {
|
|
|
42
58
|
const SettingsDialogTabs = ({ tabs }) => {
|
|
43
59
|
const [value, setValue] = useState(0);
|
|
44
60
|
|
|
61
|
+
const hasPkgInfo =
|
|
62
|
+
pkg && (pkg.name || pkg.version || pkg.description) ? true : false;
|
|
63
|
+
|
|
45
64
|
const handleChange = (event, newValue) => {
|
|
46
65
|
setValue(newValue);
|
|
47
66
|
};
|
|
@@ -95,13 +114,20 @@ const SettingsDialogTabs = ({ tabs }) => {
|
|
|
95
114
|
sx={{ "& label": { color: "custom.grey" } }}
|
|
96
115
|
{...a11yProps(1)}
|
|
97
116
|
/>
|
|
117
|
+
{hasPkgInfo && (
|
|
118
|
+
<Tab
|
|
119
|
+
label={"About"}
|
|
120
|
+
sx={{ "& label": { color: "custom.grey" } }}
|
|
121
|
+
{...a11yProps(2)}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
98
124
|
{tabs?.map((tab, index) => (
|
|
99
125
|
<Tab
|
|
100
126
|
key={tab.label}
|
|
101
127
|
iconPosition="start"
|
|
102
128
|
label={tab.label}
|
|
103
129
|
sx={{ "& label": { color: "custom.grey" } }}
|
|
104
|
-
{...a11yProps(index + 2)}
|
|
130
|
+
{...a11yProps(index + (hasPkgInfo ? 3 : 2))}
|
|
105
131
|
/>
|
|
106
132
|
))}
|
|
107
133
|
</Tabs>
|
|
@@ -112,8 +138,17 @@ const SettingsDialogTabs = ({ tabs }) => {
|
|
|
112
138
|
<TabPanel value={value} index={1}>
|
|
113
139
|
<Settings />
|
|
114
140
|
</TabPanel>
|
|
141
|
+
{hasPkgInfo && (
|
|
142
|
+
<TabPanel value={value} index={2}>
|
|
143
|
+
<About />
|
|
144
|
+
</TabPanel>
|
|
145
|
+
)}
|
|
115
146
|
{tabs?.map((tab, index) => (
|
|
116
|
-
<TabPanel
|
|
147
|
+
<TabPanel
|
|
148
|
+
key={tab.label}
|
|
149
|
+
value={value}
|
|
150
|
+
index={index + (hasPkgInfo ? 3 : 2)}
|
|
151
|
+
>
|
|
117
152
|
<tab.panel />
|
|
118
153
|
</TabPanel>
|
|
119
154
|
))}
|
|
@@ -249,6 +284,7 @@ const Permission = () => {
|
|
|
249
284
|
const Settings = () => {
|
|
250
285
|
const projectId = localStorage.getItem("projectId");
|
|
251
286
|
const { settings, updateSettings } = useSettings(projectId);
|
|
287
|
+
const { beta, onUpdate } = useSettingsContext();
|
|
252
288
|
|
|
253
289
|
const timeZones = [
|
|
254
290
|
"Asia/Kolkata",
|
|
@@ -300,9 +336,137 @@ const Settings = () => {
|
|
|
300
336
|
</NativeSelect>
|
|
301
337
|
</FormControl>
|
|
302
338
|
</ListItem>
|
|
339
|
+
<ListItem
|
|
340
|
+
sx={{
|
|
341
|
+
backgroundColor: "background.paper",
|
|
342
|
+
boxShadow: 1,
|
|
343
|
+
borderRadius: 1,
|
|
344
|
+
m: 1,
|
|
345
|
+
p: 2,
|
|
346
|
+
":hover": { boxShadow: 3 },
|
|
347
|
+
transition: "all 0.2s ease-in-out",
|
|
348
|
+
}}
|
|
349
|
+
>
|
|
350
|
+
<ListItemText primary="Beta" secondary="Enable beta features" />
|
|
351
|
+
<Switch checked={beta} onChange={() => onUpdate("beta", !beta)} />
|
|
352
|
+
</ListItem>
|
|
303
353
|
</List>
|
|
304
354
|
</Stack>
|
|
305
355
|
);
|
|
306
356
|
};
|
|
307
357
|
|
|
358
|
+
const About = () => {
|
|
359
|
+
const iconSrc = config().template?.login?.icon || "";
|
|
360
|
+
|
|
361
|
+
const appName = pkg.name;
|
|
362
|
+
const version = pkg.version;
|
|
363
|
+
const description = pkg.description;
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
<Stack direction="column" spacing={2} p={2}>
|
|
367
|
+
<Box
|
|
368
|
+
sx={{
|
|
369
|
+
p: 3,
|
|
370
|
+
borderRadius: 3,
|
|
371
|
+
border: "1px solid",
|
|
372
|
+
borderColor: "divider",
|
|
373
|
+
background:
|
|
374
|
+
"linear-gradient(135deg, rgba(255,255,255,0.06), rgba(255,255,255,0.01))",
|
|
375
|
+
}}
|
|
376
|
+
>
|
|
377
|
+
<Stack direction="row" spacing={2.5} alignItems="center">
|
|
378
|
+
<Avatar
|
|
379
|
+
src={iconSrc}
|
|
380
|
+
variant="rounded"
|
|
381
|
+
sx={{
|
|
382
|
+
width: 56,
|
|
383
|
+
height: 56,
|
|
384
|
+
borderRadius: 2,
|
|
385
|
+
bgcolor: "background.paper",
|
|
386
|
+
boxShadow: 1,
|
|
387
|
+
}}
|
|
388
|
+
>
|
|
389
|
+
<Iconify icon="solar:widget-bold-duotone" width={28} />
|
|
390
|
+
</Avatar>
|
|
391
|
+
|
|
392
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
393
|
+
<Typography variant="h5" fontWeight={600}>
|
|
394
|
+
{appName.toUpperCase()}
|
|
395
|
+
</Typography>
|
|
396
|
+
|
|
397
|
+
{description && (
|
|
398
|
+
<Typography
|
|
399
|
+
variant="body2"
|
|
400
|
+
color="text.secondary"
|
|
401
|
+
sx={{ mt: 0.5, maxWidth: 520 }}
|
|
402
|
+
>
|
|
403
|
+
{description}
|
|
404
|
+
</Typography>
|
|
405
|
+
)}
|
|
406
|
+
|
|
407
|
+
<Stack direction="row" spacing={1} sx={{ mt: 1 }}>
|
|
408
|
+
<Chip size="small" label={`v${version}`} />
|
|
409
|
+
</Stack>
|
|
410
|
+
</Box>
|
|
411
|
+
</Stack>
|
|
412
|
+
|
|
413
|
+
<Box
|
|
414
|
+
sx={{
|
|
415
|
+
my: 2,
|
|
416
|
+
borderBottom: "1px dashed",
|
|
417
|
+
borderColor: "divider",
|
|
418
|
+
}}
|
|
419
|
+
/>
|
|
420
|
+
|
|
421
|
+
<Stack spacing={1.2}>
|
|
422
|
+
<InfoRow label="Version" value={version} />
|
|
423
|
+
<InfoRow label="Deployment" value="On-Premise" />
|
|
424
|
+
<InfoRow
|
|
425
|
+
label="Support"
|
|
426
|
+
value="support@greycollar.ai"
|
|
427
|
+
link="mailto:support@greycollar.ai"
|
|
428
|
+
/>
|
|
429
|
+
<InfoRow
|
|
430
|
+
label="Documentation"
|
|
431
|
+
value="greycollar.ai/docs"
|
|
432
|
+
link="https://greycollar.ai/docs"
|
|
433
|
+
/>
|
|
434
|
+
</Stack>
|
|
435
|
+
|
|
436
|
+
<Box
|
|
437
|
+
sx={{
|
|
438
|
+
mt: 3,
|
|
439
|
+
pt: 2,
|
|
440
|
+
borderTop: "1px dashed",
|
|
441
|
+
borderColor: "divider",
|
|
442
|
+
textAlign: "center",
|
|
443
|
+
}}
|
|
444
|
+
>
|
|
445
|
+
<Typography variant="caption" color="text.secondary">
|
|
446
|
+
© 2026 greycollar.ai. All rights reserved.
|
|
447
|
+
</Typography>
|
|
448
|
+
</Box>
|
|
449
|
+
</Box>
|
|
450
|
+
</Stack>
|
|
451
|
+
);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const InfoRow = ({ label, value, link }) => {
|
|
455
|
+
return (
|
|
456
|
+
<Stack direction="row" spacing={1.5} alignItems="center">
|
|
457
|
+
<Typography variant="body2" color="text.secondary" sx={{ minWidth: 110 }}>
|
|
458
|
+
{label}
|
|
459
|
+
</Typography>
|
|
460
|
+
|
|
461
|
+
{link ? (
|
|
462
|
+
<Link href={link} target="_blank" rel="noreferrer" underline="hover">
|
|
463
|
+
{value}
|
|
464
|
+
</Link>
|
|
465
|
+
) : (
|
|
466
|
+
<Typography variant="body2">{value}</Typography>
|
|
467
|
+
)}
|
|
468
|
+
</Stack>
|
|
469
|
+
);
|
|
470
|
+
};
|
|
471
|
+
|
|
308
472
|
export default SettingsDialog;
|