@canmingir/link 1.2.5 → 1.2.7
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 +1 -1
- package/src/context/reducer.js +1 -4
- package/src/http/index.js +11 -8
- package/src/http/user.js +48 -16
- package/src/layouts/DashboardLayout/nav-mini.jsx +34 -14
- package/src/layouts/FullScreenLayout/nav-horizontal.jsx +6 -1
- package/src/layouts/common/ProjectBar/index.jsx +13 -13
- package/src/layouts/common/account-popover.jsx +2 -3
- package/src/lib/Flow/DynamicConnector.jsx +19 -15
- package/src/lib/Flow/Flow.jsx +7 -1
- package/src/lib/Flow/FlowNode.jsx +128 -27
- package/src/lib/Flow/layouts/CardLayout.jsx +160 -76
- package/src/pages/Callback.jsx +9 -9
- package/src/pages/LoginPage.jsx +4 -1
- package/src/widgets/Login/Login.jsx +4 -1
- package/src/widgets/LoginForm/LoginForm.jsx +5 -5
package/package.json
CHANGED
package/src/context/reducer.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import config from "../config/config";
|
|
2
1
|
import { jwtDecode } from "jwt-decode";
|
|
3
2
|
import { storage } from "@nucleoidjs/webstorage";
|
|
4
3
|
|
|
5
|
-
const { name } = config();
|
|
6
|
-
|
|
7
4
|
let login = true;
|
|
8
5
|
const itemId = storage.get("itemId");
|
|
9
6
|
try {
|
|
10
|
-
const token = storage.get(
|
|
7
|
+
const token = storage.get("link", "accessToken");
|
|
11
8
|
const decodedToken = jwtDecode(token);
|
|
12
9
|
|
|
13
10
|
if (decodedToken.exp * 1000 < Date.now()) {
|
package/src/http/index.js
CHANGED
|
@@ -15,8 +15,8 @@ const instance = axios.create({
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
instance.interceptors.request.use((request) => {
|
|
18
|
-
const {
|
|
19
|
-
const accessToken = storage.get(
|
|
18
|
+
const { base } = config();
|
|
19
|
+
const accessToken = storage.get("link", "accessToken");
|
|
20
20
|
|
|
21
21
|
if (!accessToken) {
|
|
22
22
|
window.location.href = base === "/" ? "/login" : `${base}/login`;
|
|
@@ -85,14 +85,17 @@ export const fetcher = (url) => instance.get(url).then((res) => res.data);
|
|
|
85
85
|
|
|
86
86
|
const refreshAuthLogic = async (failedRequest) => {
|
|
87
87
|
try {
|
|
88
|
-
const {
|
|
88
|
+
const { appId } = config();
|
|
89
89
|
|
|
90
90
|
const projectId = storage.get("projectId");
|
|
91
91
|
|
|
92
|
+
const identityProvider = storage.get("link", "identityProvider");
|
|
93
|
+
|
|
92
94
|
const { data } = await oauth.post("/oauth", {
|
|
93
|
-
refreshToken: storage.get(
|
|
95
|
+
refreshToken: storage.get("link", "refreshToken"),
|
|
94
96
|
appId,
|
|
95
97
|
projectId,
|
|
98
|
+
identityProvider,
|
|
96
99
|
});
|
|
97
100
|
|
|
98
101
|
const accessToken = data.accessToken;
|
|
@@ -100,13 +103,13 @@ const refreshAuthLogic = async (failedRequest) => {
|
|
|
100
103
|
failedRequest.response.config.headers["Authorization"] =
|
|
101
104
|
"Bearer " + accessToken;
|
|
102
105
|
|
|
103
|
-
storage.set(
|
|
106
|
+
storage.set("link", "accessToken", accessToken);
|
|
104
107
|
return Promise.resolve();
|
|
105
108
|
} catch (error) {
|
|
106
109
|
const { name, base } = config();
|
|
107
110
|
|
|
108
|
-
storage.remove(
|
|
109
|
-
storage.remove(
|
|
111
|
+
storage.remove("link", "accessToken");
|
|
112
|
+
storage.remove("link", "refreshToken");
|
|
110
113
|
|
|
111
114
|
window.location.href = `${window.location.origin}${base}/login`;
|
|
112
115
|
return Promise.reject(error);
|
|
@@ -122,7 +125,7 @@ refreshInterceptor(instance, refreshAuthLogic, {
|
|
|
122
125
|
statusCodes: [401, 403],
|
|
123
126
|
shouldRefresh: () => {
|
|
124
127
|
const { name, base } = config();
|
|
125
|
-
const token = storage.get(
|
|
128
|
+
const token = storage.get("link", "accessToken");
|
|
126
129
|
|
|
127
130
|
if (!token) {
|
|
128
131
|
window.location.href = `${window.location.origin}${base}/login`;
|
package/src/http/user.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import config from "../config/config.js";
|
|
3
3
|
import http from "./index";
|
|
4
|
+
import { jwtDecode } from "jwt-decode";
|
|
5
|
+
import oauth from "./oauth";
|
|
4
6
|
import { storage } from "@nucleoidjs/webstorage";
|
|
5
7
|
|
|
6
8
|
const instance = axios.create({
|
|
@@ -11,15 +13,8 @@ const instance = axios.create({
|
|
|
11
13
|
},
|
|
12
14
|
});
|
|
13
15
|
|
|
14
|
-
function getProjectName() {
|
|
15
|
-
const { name } = config();
|
|
16
|
-
if (name) {
|
|
17
|
-
return name;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
16
|
instance.interceptors.request.use(async (request) => {
|
|
22
|
-
const refreshToken = await storage.get(
|
|
17
|
+
const refreshToken = await storage.get("link", "refreshToken");
|
|
23
18
|
if (refreshToken) {
|
|
24
19
|
request.headers["Authorization"] = `Bearer ${refreshToken}`;
|
|
25
20
|
}
|
|
@@ -28,25 +23,62 @@ instance.interceptors.request.use(async (request) => {
|
|
|
28
23
|
|
|
29
24
|
instance.getUserDetails = async () => {
|
|
30
25
|
try {
|
|
31
|
-
const refreshToken = await storage.get(
|
|
26
|
+
const refreshToken = await storage.get("link", "refreshToken");
|
|
27
|
+
|
|
32
28
|
if (!refreshToken) {
|
|
33
29
|
console.log("No refresh token found");
|
|
34
30
|
return null;
|
|
35
31
|
}
|
|
36
32
|
|
|
33
|
+
let accessToken = await storage.get("link", "accessToken");
|
|
34
|
+
|
|
35
|
+
if (!accessToken) {
|
|
36
|
+
console.log("No access token found");
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const decodedToken = jwtDecode(accessToken);
|
|
42
|
+
const isExpired = decodedToken.exp * 1000 < Date.now();
|
|
43
|
+
|
|
44
|
+
if (isExpired) {
|
|
45
|
+
console.log(
|
|
46
|
+
"Access token expired, refreshing before fetching user details..."
|
|
47
|
+
);
|
|
48
|
+
const { appId } = config();
|
|
49
|
+
const projectId = storage.get("projectId");
|
|
50
|
+
const identityProvider = storage.get("link", "identityProvider");
|
|
51
|
+
|
|
52
|
+
const { data } = await oauth.post("/oauth", {
|
|
53
|
+
refreshToken,
|
|
54
|
+
appId,
|
|
55
|
+
projectId,
|
|
56
|
+
identityProvider,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
accessToken = data.accessToken;
|
|
60
|
+
storage.set("link", "accessToken", accessToken);
|
|
61
|
+
console.log(
|
|
62
|
+
"Access token refreshed successfully, now fetching user details"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("Error checking or refreshing token:", error);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
37
70
|
const response = await http.get("/oauth/user", {
|
|
38
71
|
headers: {
|
|
39
|
-
|
|
40
|
-
}
|
|
72
|
+
"X-Refresh-Token": refreshToken,
|
|
73
|
+
},
|
|
41
74
|
});
|
|
42
|
-
|
|
75
|
+
|
|
43
76
|
if (response.data && response.data.user) {
|
|
44
77
|
return response.data.user;
|
|
45
78
|
}
|
|
46
|
-
|
|
79
|
+
|
|
47
80
|
console.log("No user data received from server");
|
|
48
81
|
return null;
|
|
49
|
-
|
|
50
82
|
} catch (error) {
|
|
51
83
|
console.error("Error fetching user details from server:", error);
|
|
52
84
|
return null;
|
|
@@ -55,7 +87,7 @@ instance.getUserDetails = async () => {
|
|
|
55
87
|
|
|
56
88
|
instance.getPermittedUsers = async () => {
|
|
57
89
|
const userIds = [];
|
|
58
|
-
const refreshToken = await storage.get(
|
|
90
|
+
const refreshToken = await storage.get("link", "refreshToken");
|
|
59
91
|
const response = await http.get("/permissions");
|
|
60
92
|
|
|
61
93
|
response.data.forEach((permission) => {
|
|
@@ -75,4 +107,4 @@ instance.getPermittedUsers = async () => {
|
|
|
75
107
|
return users;
|
|
76
108
|
};
|
|
77
109
|
|
|
78
|
-
export default instance;
|
|
110
|
+
export default instance;
|
|
@@ -9,15 +9,16 @@ import SettingsDialog from "../../widgets/SettingsDialog";
|
|
|
9
9
|
import Stack from "@mui/material/Stack";
|
|
10
10
|
import config from "../../config/config";
|
|
11
11
|
import { hideScroll } from "../../theme/css";
|
|
12
|
+
import { useResponsive } from "../../hooks/use-responsive";
|
|
12
13
|
import { useUser } from "../../hooks/use-user";
|
|
13
14
|
|
|
14
15
|
import React, { useState } from "react";
|
|
15
16
|
|
|
16
17
|
export default function NavMini({ only }) {
|
|
17
18
|
const { user } = useUser();
|
|
18
|
-
const { sideMenu } = config().menu;
|
|
19
|
+
const { sideMenu, actionButtons } = config().menu;
|
|
19
20
|
const [openSettings, setOpenSettings] = useState(false);
|
|
20
|
-
|
|
21
|
+
const lgUp = useResponsive("up", "lg");
|
|
21
22
|
const handleCloseSettings = () => {
|
|
22
23
|
setOpenSettings(false);
|
|
23
24
|
};
|
|
@@ -57,21 +58,40 @@ export default function NavMini({ only }) {
|
|
|
57
58
|
}}
|
|
58
59
|
/>
|
|
59
60
|
<Box sx={{ flexGrow: 1 }} />
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
<Stack
|
|
62
|
+
direction={"column"}
|
|
63
|
+
alignItems={"center"}
|
|
64
|
+
justifyItems={"center"}
|
|
65
|
+
sx={{
|
|
66
|
+
marginBottom: lgUp ? 3 : 0,
|
|
67
|
+
position: lgUp ? "static" : "fixed",
|
|
68
|
+
bottom: lgUp ? "auto" : 66,
|
|
69
|
+
width: "100%",
|
|
70
|
+
}}
|
|
71
|
+
gap={2}
|
|
64
72
|
>
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
{actionButtons &&
|
|
74
|
+
actionButtons.map((Action, index) => (
|
|
75
|
+
<Box key={index} component={Action}></Box>
|
|
76
|
+
))}
|
|
77
|
+
<Button
|
|
78
|
+
onClick={() => setOpenSettings(true)}
|
|
67
79
|
sx={{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
mx: "auto",
|
|
80
|
+
position: lgUp ? "static" : "fixed",
|
|
81
|
+
bottom: lgUp ? "auto" : 16,
|
|
82
|
+
width: "100%",
|
|
72
83
|
}}
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
>
|
|
85
|
+
<Iconify
|
|
86
|
+
icon={"ic:baseline-settings"}
|
|
87
|
+
sx={{
|
|
88
|
+
width: 32,
|
|
89
|
+
height: 32,
|
|
90
|
+
color: "text.secondary",
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
</Button>
|
|
94
|
+
</Stack>
|
|
75
95
|
<SettingsDialog open={openSettings} handleClose={handleCloseSettings} />
|
|
76
96
|
</Stack>
|
|
77
97
|
</Box>
|
|
@@ -16,7 +16,7 @@ function NavHorizontal() {
|
|
|
16
16
|
|
|
17
17
|
const { user } = useUser();
|
|
18
18
|
|
|
19
|
-
const { sideMenu } = config().menu;
|
|
19
|
+
const { sideMenu, actionButtons } = config().menu;
|
|
20
20
|
return (
|
|
21
21
|
<AppBar component="div" data-cy="nav-horizontal">
|
|
22
22
|
<Toolbar
|
|
@@ -35,6 +35,11 @@ function NavHorizontal() {
|
|
|
35
35
|
...theme.mixins.toolbar,
|
|
36
36
|
}}
|
|
37
37
|
/>
|
|
38
|
+
|
|
39
|
+
{actionButtons &&
|
|
40
|
+
actionButtons.map((Action, index) => (
|
|
41
|
+
<Box key={index} component={Action}></Box>
|
|
42
|
+
))}
|
|
38
43
|
</Toolbar>
|
|
39
44
|
|
|
40
45
|
<HeaderShadow />
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { Button, DialogActions } from "@mui/material";
|
|
2
|
-
import Dialog, { dialogClasses } from "@mui/material/Dialog";
|
|
3
|
-
import React, { useCallback, useState } from "react";
|
|
4
|
-
import { publish, useEvent } from "@nucleoidai/react-event";
|
|
5
|
-
import { storage, useStorage } from "@nucleoidjs/webstorage";
|
|
6
|
-
import { useMediaQuery, useTheme } from "@mui/material";
|
|
7
|
-
|
|
8
1
|
import Box from "@mui/material/Box";
|
|
9
2
|
import IconButton from "@mui/material/IconButton";
|
|
10
3
|
import Iconify from "../../../components/Iconify";
|
|
@@ -29,9 +22,16 @@ import { useEventListener } from "../../../hooks/use-event-listener";
|
|
|
29
22
|
import { useNavigate } from "react-router-dom";
|
|
30
23
|
import useProjects from "../../../hooks/useProjects";
|
|
31
24
|
|
|
25
|
+
import { Button, DialogActions } from "@mui/material";
|
|
26
|
+
import Dialog, { dialogClasses } from "@mui/material/Dialog";
|
|
27
|
+
import React, { useCallback, useState } from "react";
|
|
28
|
+
import { publish, useEvent } from "@nucleoidai/react-event";
|
|
29
|
+
import { storage, useStorage } from "@nucleoidjs/webstorage";
|
|
30
|
+
import { useMediaQuery, useTheme } from "@mui/material";
|
|
31
|
+
|
|
32
32
|
function ProjectBar() {
|
|
33
33
|
const label = config().template?.projectBar?.label;
|
|
34
|
-
const { appId
|
|
34
|
+
const { appId } = config();
|
|
35
35
|
const theme = useTheme();
|
|
36
36
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down(435));
|
|
37
37
|
const { loading, projects, getProjects } = useProjects();
|
|
@@ -91,15 +91,15 @@ function ProjectBar() {
|
|
|
91
91
|
const handleSelect = (project) => {
|
|
92
92
|
const { id: projectId } = project;
|
|
93
93
|
|
|
94
|
-
const refreshToken = storage.get(
|
|
95
|
-
const
|
|
94
|
+
const refreshToken = storage.get("link", "refreshToken");
|
|
95
|
+
const identityProvider = storage.get("link", "identityProvider");
|
|
96
96
|
|
|
97
97
|
oauth
|
|
98
|
-
.post("/oauth", { appId, refreshToken, projectId,
|
|
98
|
+
.post("/oauth", { appId, refreshToken, projectId, identityProvider })
|
|
99
99
|
.then(({ data }) => {
|
|
100
100
|
const { refreshToken, accessToken } = data;
|
|
101
|
-
storage.set(
|
|
102
|
-
storage.set(
|
|
101
|
+
storage.set("link", "accessToken", accessToken);
|
|
102
|
+
storage.set("link", "refreshToken", refreshToken);
|
|
103
103
|
storage.set("projectId", projectId);
|
|
104
104
|
})
|
|
105
105
|
.finally(() => {
|
|
@@ -19,7 +19,6 @@ import CustomPopover, { usePopover } from "../../components/custom-popover";
|
|
|
19
19
|
// ----------------------------------------------------------------------
|
|
20
20
|
|
|
21
21
|
export default function AccountPopover() {
|
|
22
|
-
const { name } = config();
|
|
23
22
|
const { options } = config().menu;
|
|
24
23
|
const router = useRouter();
|
|
25
24
|
const { user } = useUser();
|
|
@@ -28,8 +27,8 @@ export default function AccountPopover() {
|
|
|
28
27
|
|
|
29
28
|
const handleLogout = async () => {
|
|
30
29
|
try {
|
|
31
|
-
storage.remove(
|
|
32
|
-
storage.remove(
|
|
30
|
+
storage.remove("link", "accessToken");
|
|
31
|
+
storage.remove("link", "refreshToken");
|
|
33
32
|
popover.onClose();
|
|
34
33
|
router.replace("/login");
|
|
35
34
|
} catch (error) {
|
|
@@ -30,6 +30,7 @@ const DynamicConnector = ({
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
const children = childEls.map((el) => {
|
|
33
|
+
if (!el) return { x: parent.x, y: parent.y };
|
|
33
34
|
const r = el.getBoundingClientRect();
|
|
34
35
|
return {
|
|
35
36
|
x: r.left + r.width / 2 - cRect.left,
|
|
@@ -45,12 +46,13 @@ const DynamicConnector = ({
|
|
|
45
46
|
setDims({ w: cRect.width, h: cRect.height });
|
|
46
47
|
};
|
|
47
48
|
|
|
49
|
+
update();
|
|
50
|
+
|
|
48
51
|
const ro = new ResizeObserver(update);
|
|
49
52
|
ro.observe(containerEl);
|
|
50
53
|
ro.observe(parentEl);
|
|
51
54
|
childEls.forEach((el) => el && ro.observe(el));
|
|
52
55
|
|
|
53
|
-
update();
|
|
54
56
|
return () => ro.disconnect();
|
|
55
57
|
}, [containerEl, parentEl, childEls, tick]);
|
|
56
58
|
|
|
@@ -65,6 +67,18 @@ const DynamicConnector = ({
|
|
|
65
67
|
|
|
66
68
|
const onlyOne = points.children.length === 1;
|
|
67
69
|
|
|
70
|
+
const svgProps = {
|
|
71
|
+
style: {
|
|
72
|
+
position: "absolute",
|
|
73
|
+
inset: 0,
|
|
74
|
+
pointerEvents: "none",
|
|
75
|
+
overflow: "visible",
|
|
76
|
+
},
|
|
77
|
+
width: "100%",
|
|
78
|
+
height: "100%",
|
|
79
|
+
viewBox: `0 0 ${dims.w} ${dims.h}`,
|
|
80
|
+
};
|
|
81
|
+
|
|
68
82
|
if (connectorType === "curved" || connectorType === "n8n") {
|
|
69
83
|
const createN8nPath = (from, to) => {
|
|
70
84
|
const v = Math.max(32, Math.abs(to.y - from.y) * 0.35);
|
|
@@ -83,12 +97,7 @@ const DynamicConnector = ({
|
|
|
83
97
|
};
|
|
84
98
|
|
|
85
99
|
return (
|
|
86
|
-
<svg
|
|
87
|
-
style={{ position: "absolute", inset: 0, pointerEvents: "none" }}
|
|
88
|
-
width="100%"
|
|
89
|
-
height="100%"
|
|
90
|
-
viewBox={`0 0 ${dims.w} ${dims.h}`}
|
|
91
|
-
>
|
|
100
|
+
<svg {...svgProps}>
|
|
92
101
|
{points.children.map((child, i) => (
|
|
93
102
|
<path
|
|
94
103
|
key={i}
|
|
@@ -106,12 +115,7 @@ const DynamicConnector = ({
|
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
return (
|
|
109
|
-
<svg
|
|
110
|
-
style={{ position: "absolute", inset: 0, pointerEvents: "none" }}
|
|
111
|
-
width="100%"
|
|
112
|
-
height="100%"
|
|
113
|
-
viewBox={`0 0 ${dims.w} ${dims.h}`}
|
|
114
|
-
>
|
|
118
|
+
<svg {...svgProps}>
|
|
115
119
|
{onlyOne ? (
|
|
116
120
|
<line
|
|
117
121
|
x1={points.parent.x}
|
|
@@ -136,8 +140,8 @@ const DynamicConnector = ({
|
|
|
136
140
|
|
|
137
141
|
{(() => {
|
|
138
142
|
const xs = points.children.map((c) => c.x);
|
|
139
|
-
const xMin = Math.min(...xs);
|
|
140
|
-
const xMax = Math.max(...xs);
|
|
143
|
+
const xMin = Math.min(...xs, points.parent.x);
|
|
144
|
+
const xMax = Math.max(...xs, points.parent.x);
|
|
141
145
|
return (
|
|
142
146
|
<line
|
|
143
147
|
x1={xMin}
|
package/src/lib/Flow/Flow.jsx
CHANGED
|
@@ -27,7 +27,13 @@ export const Flow = ({ data, variant = "simple", style, plugin }) => {
|
|
|
27
27
|
}, [nodesById, roots]);
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
|
-
<FlowNode
|
|
30
|
+
<FlowNode
|
|
31
|
+
node={treeData}
|
|
32
|
+
variant={variant}
|
|
33
|
+
style={style}
|
|
34
|
+
plugin={plugin}
|
|
35
|
+
isRoot={true}
|
|
36
|
+
/>
|
|
31
37
|
);
|
|
32
38
|
};
|
|
33
39
|
|
|
@@ -11,7 +11,15 @@ import {
|
|
|
11
11
|
toPxNumber,
|
|
12
12
|
} from "./styles";
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const NodeContent = ({
|
|
15
|
+
node,
|
|
16
|
+
type,
|
|
17
|
+
variant,
|
|
18
|
+
style,
|
|
19
|
+
plugin,
|
|
20
|
+
registerRef,
|
|
21
|
+
onDrag,
|
|
22
|
+
}) => {
|
|
15
23
|
const baseStyle = getBaseStyleForVariant(variant);
|
|
16
24
|
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
|
17
25
|
|
|
@@ -25,23 +33,19 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
25
33
|
styleTokens = style;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
let
|
|
36
|
+
let _plugin = null;
|
|
29
37
|
if (plugin) {
|
|
30
38
|
if (typeof plugin === "function") {
|
|
31
|
-
|
|
32
|
-
} else if (
|
|
33
|
-
|
|
34
|
-
(typeof plugin.renderNode === "function" ||
|
|
35
|
-
typeof plugin.resolveStyle === "function")
|
|
36
|
-
) {
|
|
37
|
-
plugins = plugin;
|
|
39
|
+
_plugin = plugin(type, node) || null;
|
|
40
|
+
} else if (typeof plugin === "object") {
|
|
41
|
+
_plugin = plugin;
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
let pluginTokens = {};
|
|
42
|
-
if (
|
|
46
|
+
if (_plugin && typeof _plugin.style === "function") {
|
|
43
47
|
pluginTokens =
|
|
44
|
-
|
|
48
|
+
_plugin.style({
|
|
45
49
|
node,
|
|
46
50
|
style: styleTokens,
|
|
47
51
|
}) || {};
|
|
@@ -82,7 +86,11 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
82
86
|
const [childElList, setChildElList] = useState([]);
|
|
83
87
|
|
|
84
88
|
const [connectorTick, setConnectorTick] = useState(0);
|
|
85
|
-
|
|
89
|
+
|
|
90
|
+
const handleDrag = (newOffset) => {
|
|
91
|
+
setConnectorTick((t) => t + 1);
|
|
92
|
+
if (onDrag) onDrag(newOffset);
|
|
93
|
+
};
|
|
86
94
|
|
|
87
95
|
useLayoutEffect(() => {
|
|
88
96
|
const els = (node.children || [])
|
|
@@ -194,8 +202,8 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
194
202
|
};
|
|
195
203
|
|
|
196
204
|
const renderContent = () => {
|
|
197
|
-
if (
|
|
198
|
-
return
|
|
205
|
+
if (_plugin && typeof _plugin.node === "function") {
|
|
206
|
+
return _plugin.node({
|
|
199
207
|
node,
|
|
200
208
|
title,
|
|
201
209
|
subtitle,
|
|
@@ -217,9 +225,15 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
217
225
|
position: "relative",
|
|
218
226
|
}}
|
|
219
227
|
>
|
|
220
|
-
<
|
|
228
|
+
<DraggableNode
|
|
229
|
+
registerRef={(el) => {
|
|
230
|
+
parentRef.current = el;
|
|
231
|
+
if (registerRef) registerRef(el);
|
|
232
|
+
}}
|
|
233
|
+
onDrag={handleDrag}
|
|
234
|
+
>
|
|
221
235
|
{renderContent()}
|
|
222
|
-
</
|
|
236
|
+
</DraggableNode>
|
|
223
237
|
|
|
224
238
|
{hasChildren && (
|
|
225
239
|
<>
|
|
@@ -246,19 +260,17 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
246
260
|
}}
|
|
247
261
|
>
|
|
248
262
|
{node.children.map((child) => (
|
|
249
|
-
<
|
|
263
|
+
<FlowNode
|
|
250
264
|
key={child.id}
|
|
265
|
+
node={child}
|
|
266
|
+
type={type}
|
|
267
|
+
variant={variant}
|
|
268
|
+
style={style}
|
|
269
|
+
plugin={plugin}
|
|
251
270
|
registerRef={(el) => (childRefs.current[child.id] = el)}
|
|
252
|
-
onDrag={
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
node={child}
|
|
256
|
-
type={type}
|
|
257
|
-
variant={variant}
|
|
258
|
-
style={style}
|
|
259
|
-
plugin={plugin}
|
|
260
|
-
/>
|
|
261
|
-
</DraggableNode>
|
|
271
|
+
onDrag={() => setConnectorTick((t) => t + 1)}
|
|
272
|
+
isRoot={false}
|
|
273
|
+
/>
|
|
262
274
|
))}
|
|
263
275
|
</Box>
|
|
264
276
|
</>
|
|
@@ -267,4 +279,93 @@ const FlowNode = ({ node, type, variant, style, plugin }) => {
|
|
|
267
279
|
);
|
|
268
280
|
};
|
|
269
281
|
|
|
282
|
+
const FlowNode = ({ isRoot = false, ...props }) => {
|
|
283
|
+
if (!isRoot) {
|
|
284
|
+
return <NodeContent {...props} />;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
|
288
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
289
|
+
|
|
290
|
+
const [zoom, setZoom] = useState(1);
|
|
291
|
+
|
|
292
|
+
const clampZoom = (z) => Math.min(2.5, Math.max(0.25, z));
|
|
293
|
+
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
const onWheel = (e) => {
|
|
296
|
+
const wantsZoom = e.ctrlKey || e.metaKey;
|
|
297
|
+
if (!wantsZoom) return;
|
|
298
|
+
|
|
299
|
+
e.preventDefault();
|
|
300
|
+
|
|
301
|
+
const direction = e.deltaY > 0 ? -1 : 1;
|
|
302
|
+
const factor = direction > 0 ? 1.1 : 1 / 1.1;
|
|
303
|
+
|
|
304
|
+
setZoom((z) => clampZoom(z * factor));
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
window.addEventListener("wheel", onWheel, { passive: false });
|
|
308
|
+
return () => window.removeEventListener("wheel", onWheel);
|
|
309
|
+
}, []);
|
|
310
|
+
|
|
311
|
+
const handleCanvasMouseDown = (e) => {
|
|
312
|
+
if (e.target?.closest?.('[data-flow-zoom="true"]')) return;
|
|
313
|
+
|
|
314
|
+
if (e.button !== 0) return;
|
|
315
|
+
|
|
316
|
+
setIsDragging(true);
|
|
317
|
+
|
|
318
|
+
const startX = e.clientX;
|
|
319
|
+
const startY = e.clientY;
|
|
320
|
+
const startOffset = { ...offset };
|
|
321
|
+
|
|
322
|
+
const onMove = (ev) => {
|
|
323
|
+
setOffset({
|
|
324
|
+
x: startOffset.x + (ev.clientX - startX),
|
|
325
|
+
y: startOffset.y + (ev.clientY - startY),
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const onUp = () => {
|
|
330
|
+
setIsDragging(false);
|
|
331
|
+
window.removeEventListener("mousemove", onMove);
|
|
332
|
+
window.removeEventListener("mouseup", onUp);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
window.addEventListener("mousemove", onMove);
|
|
336
|
+
window.addEventListener("mouseup", onUp);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<Box
|
|
341
|
+
onMouseDown={handleCanvasMouseDown}
|
|
342
|
+
sx={{
|
|
343
|
+
width: "100vw",
|
|
344
|
+
height: "100vh",
|
|
345
|
+
overflow: "hidden",
|
|
346
|
+
bgcolor: "none",
|
|
347
|
+
cursor: isDragging ? "grabbing" : "default",
|
|
348
|
+
userSelect: "none",
|
|
349
|
+
position: "relative",
|
|
350
|
+
}}
|
|
351
|
+
>
|
|
352
|
+
<Box
|
|
353
|
+
sx={{
|
|
354
|
+
transform: `translate(${offset.x}px, ${offset.y}px) scale(${zoom})`,
|
|
355
|
+
transformOrigin: "center center",
|
|
356
|
+
width: "100%",
|
|
357
|
+
height: "100%",
|
|
358
|
+
display: "flex",
|
|
359
|
+
alignItems: "center",
|
|
360
|
+
justifyContent: "center",
|
|
361
|
+
transition: isDragging ? "none" : "transform 0.1s ease-out",
|
|
362
|
+
pointerEvents: "auto",
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
<NodeContent {...props} />
|
|
366
|
+
</Box>
|
|
367
|
+
</Box>
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
270
371
|
export default FlowNode;
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { Box, Card, Stack } from "@mui/material";
|
|
3
|
+
import { Box, Card, Stack, Typography } from "@mui/material";
|
|
4
4
|
import { alpha, useTheme } from "@mui/material/styles";
|
|
5
5
|
|
|
6
|
+
const STYLES = {
|
|
7
|
+
width: "100%",
|
|
8
|
+
display: "-webkit-box",
|
|
9
|
+
WebkitLineClamp: 2,
|
|
10
|
+
WebkitBoxOrient: "vertical",
|
|
11
|
+
overflow: "hidden",
|
|
12
|
+
textOverflow: "ellipsis",
|
|
13
|
+
wordBreak: "break-word",
|
|
14
|
+
lineHeight: 1.3,
|
|
15
|
+
opacity: 0.85,
|
|
16
|
+
};
|
|
17
|
+
|
|
6
18
|
export function MediaAvatarCard({
|
|
7
19
|
sx,
|
|
8
20
|
leftContent,
|
|
9
21
|
rightContent,
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
footer,
|
|
10
25
|
background,
|
|
11
26
|
overlayColor,
|
|
12
27
|
backgroundClassName = "animated-background-image",
|
|
@@ -25,6 +40,9 @@ export function MediaAvatarCard({
|
|
|
25
40
|
position: "relative",
|
|
26
41
|
display: "flex",
|
|
27
42
|
flexDirection: "row",
|
|
43
|
+
fontSize: 12,
|
|
44
|
+
color: "rgba(255,255,255,0.82)",
|
|
45
|
+
lineHeight: 1.3,
|
|
28
46
|
boxShadow: (theme) => theme.shadows[3],
|
|
29
47
|
"&:hover": {
|
|
30
48
|
boxShadow: (theme) => theme.shadows[6],
|
|
@@ -82,75 +100,44 @@ export function MediaAvatarCard({
|
|
|
82
100
|
|
|
83
101
|
<Stack
|
|
84
102
|
direction="column"
|
|
85
|
-
spacing={1}
|
|
86
103
|
sx={{
|
|
87
104
|
flex: 1,
|
|
88
105
|
padding: 2,
|
|
89
106
|
zIndex: 1,
|
|
90
107
|
position: "relative",
|
|
108
|
+
height: "100%",
|
|
109
|
+
justifyContent: "space-between",
|
|
91
110
|
}}
|
|
92
111
|
>
|
|
93
|
-
{rightContent
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
112
|
+
{rightContent ? (
|
|
113
|
+
rightContent
|
|
114
|
+
) : (
|
|
115
|
+
<>
|
|
116
|
+
<Stack spacing={1} sx={{ width: "100%", minWidth: 0 }}>
|
|
117
|
+
<Box>{title}</Box>
|
|
98
118
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}) {
|
|
106
|
-
const theme = useTheme();
|
|
119
|
+
{description && (
|
|
120
|
+
<Typography variant="inherit" sx={STYLES}>
|
|
121
|
+
{description}
|
|
122
|
+
</Typography>
|
|
123
|
+
)}
|
|
124
|
+
</Stack>
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"&:before": {
|
|
124
|
-
height: "100%",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
"&:before": {
|
|
128
|
-
content: '""',
|
|
129
|
-
width: "100%",
|
|
130
|
-
height: "40%",
|
|
131
|
-
position: "absolute",
|
|
132
|
-
top: 0,
|
|
133
|
-
left: 0,
|
|
134
|
-
background: `linear-gradient(135deg, ${alpha(
|
|
135
|
-
theme.palette.secondary.light,
|
|
136
|
-
0.2
|
|
137
|
-
)}, ${alpha(theme.palette.primary.main, 0.3)})`,
|
|
138
|
-
borderRadius: "8px 8px 0 0",
|
|
139
|
-
transition: "height 0.3s ease-in-out",
|
|
140
|
-
},
|
|
141
|
-
...sx,
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<Stack
|
|
145
|
-
spacing={2}
|
|
146
|
-
sx={{
|
|
147
|
-
height: "100%",
|
|
148
|
-
position: "relative",
|
|
149
|
-
zIndex: 1,
|
|
150
|
-
}}
|
|
151
|
-
>
|
|
152
|
-
{header}
|
|
153
|
-
{children}
|
|
126
|
+
{footer && (
|
|
127
|
+
<Box
|
|
128
|
+
sx={{
|
|
129
|
+
display: "flex",
|
|
130
|
+
justifyContent: "flex-end",
|
|
131
|
+
alignItems: "center",
|
|
132
|
+
gap: 0.5,
|
|
133
|
+
mt: 0.5,
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
{footer}
|
|
137
|
+
</Box>
|
|
138
|
+
)}
|
|
139
|
+
</>
|
|
140
|
+
)}
|
|
154
141
|
</Stack>
|
|
155
142
|
</Card>
|
|
156
143
|
);
|
|
@@ -160,6 +147,9 @@ export function SideStripeCard({
|
|
|
160
147
|
sx,
|
|
161
148
|
stripeContent,
|
|
162
149
|
mainContent,
|
|
150
|
+
title,
|
|
151
|
+
description,
|
|
152
|
+
footer,
|
|
163
153
|
minWidth = 200,
|
|
164
154
|
maxWidth = 290,
|
|
165
155
|
height = 100,
|
|
@@ -168,11 +158,7 @@ export function SideStripeCard({
|
|
|
168
158
|
const theme = useTheme();
|
|
169
159
|
|
|
170
160
|
return (
|
|
171
|
-
<Box
|
|
172
|
-
sx={{
|
|
173
|
-
cursor: "pointer",
|
|
174
|
-
}}
|
|
175
|
-
>
|
|
161
|
+
<Box sx={{ cursor: "pointer" }}>
|
|
176
162
|
<Card
|
|
177
163
|
sx={{
|
|
178
164
|
display: "flex",
|
|
@@ -185,6 +171,9 @@ export function SideStripeCard({
|
|
|
185
171
|
boxShadow: 3,
|
|
186
172
|
position: "relative",
|
|
187
173
|
overflow: "hidden",
|
|
174
|
+
fontSize: 12,
|
|
175
|
+
lineHeight: 1.3,
|
|
176
|
+
color: "rgba(255,255,255,0.82)",
|
|
188
177
|
"&:hover": {
|
|
189
178
|
boxShadow: 6,
|
|
190
179
|
"& .animated-background-selector": {
|
|
@@ -233,20 +222,118 @@ export function SideStripeCard({
|
|
|
233
222
|
|
|
234
223
|
<Stack
|
|
235
224
|
direction="column"
|
|
236
|
-
spacing={1}
|
|
237
225
|
sx={{
|
|
238
226
|
padding: 2,
|
|
239
227
|
position: "relative",
|
|
240
228
|
zIndex: 1,
|
|
229
|
+
flex: 1,
|
|
230
|
+
height: "100%",
|
|
231
|
+
justifyContent: "space-between",
|
|
241
232
|
}}
|
|
242
233
|
>
|
|
243
|
-
{mainContent
|
|
234
|
+
{mainContent ? (
|
|
235
|
+
mainContent
|
|
236
|
+
) : (
|
|
237
|
+
<>
|
|
238
|
+
<Box sx={{ minWidth: 0 }}>
|
|
239
|
+
{typeof title === "string" ? (
|
|
240
|
+
<Typography
|
|
241
|
+
variant="inherit"
|
|
242
|
+
sx={{
|
|
243
|
+
color: "text.primary",
|
|
244
|
+
wordBreak: "break-word",
|
|
245
|
+
hyphens: "auto",
|
|
246
|
+
fontWeight: 600,
|
|
247
|
+
}}
|
|
248
|
+
>
|
|
249
|
+
{title}
|
|
250
|
+
</Typography>
|
|
251
|
+
) : (
|
|
252
|
+
title
|
|
253
|
+
)}
|
|
254
|
+
|
|
255
|
+
{description && (
|
|
256
|
+
<Typography
|
|
257
|
+
variant="inherit"
|
|
258
|
+
sx={{
|
|
259
|
+
...STYLES,
|
|
260
|
+
mt: 0.5,
|
|
261
|
+
color: "text.primary",
|
|
262
|
+
opacity: 0.8,
|
|
263
|
+
}}
|
|
264
|
+
>
|
|
265
|
+
{description}
|
|
266
|
+
</Typography>
|
|
267
|
+
)}
|
|
268
|
+
</Box>
|
|
269
|
+
|
|
270
|
+
{footer && (
|
|
271
|
+
<Box sx={{ alignSelf: "flex-end", mt: 0.5 }}>{footer}</Box>
|
|
272
|
+
)}
|
|
273
|
+
</>
|
|
274
|
+
)}
|
|
244
275
|
</Stack>
|
|
245
276
|
</Card>
|
|
246
277
|
</Box>
|
|
247
278
|
);
|
|
248
279
|
}
|
|
249
280
|
|
|
281
|
+
export function HeaderCard({
|
|
282
|
+
sx,
|
|
283
|
+
header,
|
|
284
|
+
children,
|
|
285
|
+
height = 140,
|
|
286
|
+
padding = 2,
|
|
287
|
+
}) {
|
|
288
|
+
const theme = useTheme();
|
|
289
|
+
return (
|
|
290
|
+
<Card
|
|
291
|
+
sx={{
|
|
292
|
+
p: padding,
|
|
293
|
+
minWidth: 200,
|
|
294
|
+
maxWidth: 420,
|
|
295
|
+
height,
|
|
296
|
+
borderRadius: 3,
|
|
297
|
+
position: "relative",
|
|
298
|
+
overflow: "hidden",
|
|
299
|
+
backgroundColor: theme.palette.background.paper,
|
|
300
|
+
fontSize: 12,
|
|
301
|
+
lineHeight: 1.3,
|
|
302
|
+
color: "rgba(255,255,255,0.82)",
|
|
303
|
+
transition: "all 0.3s ease-in-out",
|
|
304
|
+
"&:hover": {
|
|
305
|
+
transform: "translateY(-4px)",
|
|
306
|
+
boxShadow: theme.shadows[8],
|
|
307
|
+
"&:before": { height: "100%" },
|
|
308
|
+
},
|
|
309
|
+
"&:before": {
|
|
310
|
+
content: '""',
|
|
311
|
+
width: "100%",
|
|
312
|
+
height: "40%",
|
|
313
|
+
position: "absolute",
|
|
314
|
+
top: 0,
|
|
315
|
+
left: 0,
|
|
316
|
+
background: `linear-gradient(135deg, ${alpha(
|
|
317
|
+
theme.palette.secondary.light,
|
|
318
|
+
0.2
|
|
319
|
+
)}, ${alpha(theme.palette.primary.main, 0.3)})`,
|
|
320
|
+
borderRadius: "8px 8px 0 0",
|
|
321
|
+
transition: "height 0.3s ease-in-out",
|
|
322
|
+
},
|
|
323
|
+
...sx,
|
|
324
|
+
}}
|
|
325
|
+
>
|
|
326
|
+
<Stack
|
|
327
|
+
spacing={2}
|
|
328
|
+
sx={{ height: "100%", position: "relative", zIndex: 1 }}
|
|
329
|
+
>
|
|
330
|
+
{header}
|
|
331
|
+
{children}
|
|
332
|
+
</Stack>
|
|
333
|
+
</Card>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
250
337
|
export function AvatarRoleCard({
|
|
251
338
|
sx,
|
|
252
339
|
leftContent,
|
|
@@ -264,13 +351,14 @@ export function AvatarRoleCard({
|
|
|
264
351
|
borderRadius: 2,
|
|
265
352
|
position: "relative",
|
|
266
353
|
backgroundColor: theme.palette.background.paper,
|
|
354
|
+
fontSize: 12,
|
|
355
|
+
lineHeight: 1.3,
|
|
356
|
+
color: "rgba(255,255,255,0.82)",
|
|
267
357
|
transition: "all 0.3s ease-in-out",
|
|
268
358
|
"&:hover": {
|
|
269
359
|
transform: "translateY(-4px)",
|
|
270
360
|
boxShadow: theme.shadows[8],
|
|
271
|
-
"&:before": {
|
|
272
|
-
height: "100%",
|
|
273
|
-
},
|
|
361
|
+
"&:before": { height: "100%" },
|
|
274
362
|
},
|
|
275
363
|
"&:before": {
|
|
276
364
|
content: '""',
|
|
@@ -291,11 +379,7 @@ export function AvatarRoleCard({
|
|
|
291
379
|
>
|
|
292
380
|
<Stack
|
|
293
381
|
spacing={1}
|
|
294
|
-
sx={{
|
|
295
|
-
height: "100%",
|
|
296
|
-
position: "relative",
|
|
297
|
-
zIndex: 1,
|
|
298
|
-
}}
|
|
382
|
+
sx={{ height: "100%", position: "relative", zIndex: 1 }}
|
|
299
383
|
>
|
|
300
384
|
<Stack
|
|
301
385
|
direction="row"
|
package/src/pages/Callback.jsx
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react";
|
|
2
|
-
|
|
3
1
|
import Page from "../layouts/Page";
|
|
4
2
|
import React from "react";
|
|
5
3
|
import config from "../config/config";
|
|
@@ -10,6 +8,8 @@ import { useContext } from "../ContextProvider/ContextProvider";
|
|
|
10
8
|
import { useLocation } from "react-router-dom";
|
|
11
9
|
import { useNavigate } from "react-router-dom";
|
|
12
10
|
|
|
11
|
+
import { useEffect, useRef } from "react";
|
|
12
|
+
|
|
13
13
|
function Callback() {
|
|
14
14
|
const { project: appConfig, name, appId } = config();
|
|
15
15
|
const projectBar = config().template?.projectBar;
|
|
@@ -28,12 +28,12 @@ function Callback() {
|
|
|
28
28
|
const parsedQuery = qs.parse(location.search, { ignoreQueryPrefix: true });
|
|
29
29
|
const { code, error, error_description, state } = parsedQuery;
|
|
30
30
|
|
|
31
|
-
let
|
|
31
|
+
let identityProvider;
|
|
32
32
|
let stateData = {};
|
|
33
33
|
|
|
34
34
|
if (state) {
|
|
35
35
|
stateData = JSON.parse(decodeURIComponent(state));
|
|
36
|
-
|
|
36
|
+
identityProvider = stateData.identityProvider;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (error) {
|
|
@@ -59,7 +59,7 @@ function Callback() {
|
|
|
59
59
|
google,
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
const providerConfig = providerConfigs[
|
|
62
|
+
const providerConfig = providerConfigs[identityProvider];
|
|
63
63
|
|
|
64
64
|
if (!providerConfig) {
|
|
65
65
|
console.error("Could not determine OAuth provider or redirect URI");
|
|
@@ -85,7 +85,7 @@ function Callback() {
|
|
|
85
85
|
appId,
|
|
86
86
|
code,
|
|
87
87
|
redirectUri,
|
|
88
|
-
|
|
88
|
+
identityProvider: identityProvider,
|
|
89
89
|
grant_type: "authorization_code",
|
|
90
90
|
})
|
|
91
91
|
.then(({ data }) => {
|
|
@@ -93,10 +93,10 @@ function Callback() {
|
|
|
93
93
|
const refreshToken = data.refreshToken;
|
|
94
94
|
const userInfo = data.user;
|
|
95
95
|
|
|
96
|
-
storage.set(
|
|
97
|
-
storage.set(
|
|
96
|
+
storage.set("link", "accessToken", accessToken);
|
|
97
|
+
storage.set("link", "refreshToken", refreshToken);
|
|
98
98
|
// TODO - update provider info
|
|
99
|
-
storage.set(
|
|
99
|
+
storage.set("link", "identityProvider", identityProvider);
|
|
100
100
|
|
|
101
101
|
dispatch({ type: "LOGIN", payload: { user: userInfo } });
|
|
102
102
|
|
package/src/pages/LoginPage.jsx
CHANGED
|
@@ -11,7 +11,10 @@ function LoginPage() {
|
|
|
11
11
|
const navigate = useNavigate();
|
|
12
12
|
|
|
13
13
|
function token() {
|
|
14
|
-
if (
|
|
14
|
+
if (
|
|
15
|
+
storage.get("link", "refreshToken") &&
|
|
16
|
+
storage.get("link", "accessToken")
|
|
17
|
+
) {
|
|
15
18
|
return true;
|
|
16
19
|
} else {
|
|
17
20
|
return false;
|
|
@@ -19,7 +19,10 @@ export default function Auth0LoginView() {
|
|
|
19
19
|
const navigate = useNavigate();
|
|
20
20
|
|
|
21
21
|
function token() {
|
|
22
|
-
if (
|
|
22
|
+
if (
|
|
23
|
+
storage.get("link", "refreshToken") &&
|
|
24
|
+
storage.get("link", "accessToken")
|
|
25
|
+
) {
|
|
23
26
|
return true;
|
|
24
27
|
} else {
|
|
25
28
|
return false;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Box, Divider, Link as MuiLink, Typography } from "@mui/material";
|
|
2
|
-
import React, { useState } from "react";
|
|
3
|
-
|
|
4
1
|
import NucleoidLoginForm from "../../components/NucleoidLoginForm";
|
|
5
2
|
import SocialLoginButtons from "../../components/SocialLoginButtons";
|
|
6
3
|
import Stack from "@mui/material/Stack";
|
|
7
4
|
import config from "../../config/config";
|
|
8
5
|
|
|
6
|
+
import { Box, Divider, Link as MuiLink, Typography } from "@mui/material";
|
|
7
|
+
import React, { useState } from "react";
|
|
8
|
+
|
|
9
9
|
const handleOAuthLogin = (
|
|
10
10
|
{ redirectUri, authUrl, clientId, scope },
|
|
11
|
-
|
|
11
|
+
identityProvider
|
|
12
12
|
) => {
|
|
13
13
|
const state = JSON.stringify({
|
|
14
|
-
|
|
14
|
+
identityProvider: identityProvider,
|
|
15
15
|
});
|
|
16
16
|
const encodedState = encodeURIComponent(state);
|
|
17
17
|
window.location.href = `${authUrl}?client_id=${clientId}&scope=${scope}&response_type=code&redirect_uri=${redirectUri}&state=${encodedState}`;
|