@ebubekirylmaz/link-test 1.1.13 → 1.2.17

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 CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@ebubekirylmaz/link-test",
3
- "version": "1.1.13",
3
+ "version": "1.2.17",
4
4
  "type": "module",
5
- "private": false,
6
5
  "exports": {
7
6
  ".": "./index.js",
8
7
  "./layouts": "./src/layouts/index.js",
@@ -35,6 +34,7 @@
35
34
  "@nucleoidai/react-event": "^1.1.9",
36
35
  "@nucleoidjs/webstorage": "^1.0.5",
37
36
  "autosuggest-highlight": "^3.3.4",
37
+ "aws-amplify": "^6.16.0",
38
38
  "axios": "^1.10.0",
39
39
  "axios-auth-refresh": "^3.3.6",
40
40
  "axios-retry": "^4.4.1",
package/src/http/index.js CHANGED
@@ -86,9 +86,7 @@ export const fetcher = (url) => instance.get(url).then((res) => res.data);
86
86
  const refreshAuthLogic = async (failedRequest) => {
87
87
  try {
88
88
  const { appId } = config();
89
-
90
89
  const projectId = storage.get("projectId");
91
-
92
90
  const identityProvider = storage.get("link", "identityProvider");
93
91
 
94
92
  const { data } = await oauth.post("/oauth", {
@@ -96,17 +94,25 @@ const refreshAuthLogic = async (failedRequest) => {
96
94
  appId,
97
95
  projectId,
98
96
  identityProvider,
97
+ ...(identityProvider === "DEMO" && {
98
+ username: "admin",
99
+ password: "admin",
100
+ }),
99
101
  });
100
102
 
101
- const accessToken = data.accessToken;
103
+ const { accessToken, refreshToken } = data;
102
104
 
103
105
  failedRequest.response.config.headers["Authorization"] =
104
106
  "Bearer " + accessToken;
105
107
 
106
108
  storage.set("link", "accessToken", accessToken);
109
+ if (refreshToken) {
110
+ storage.set("link", "refreshToken", refreshToken);
111
+ }
112
+
107
113
  return Promise.resolve();
108
114
  } catch (error) {
109
- const { name, base } = config();
115
+ const { base } = config();
110
116
 
111
117
  storage.remove("link", "accessToken");
112
118
  storage.remove("link", "refreshToken");
@@ -4,6 +4,7 @@ import Logo from "../../components/logo";
4
4
  import { Outlet } from "react-router";
5
5
  import React from "react";
6
6
  import Stack from "@mui/material/Stack";
7
+ import { alpha } from "@mui/material/styles";
7
8
  import { useResponsive } from "../../hooks/use-responsive";
8
9
 
9
10
  // ----------------------------------------------------------------------
@@ -16,28 +17,37 @@ export default function AuthModernLayout({ image }) {
16
17
  sx={{
17
18
  width: 1,
18
19
  mx: "auto",
19
- maxWidth: 480,
20
- px: { xs: 2, md: 8 },
20
+ maxWidth: 600,
21
+ px: { xs: 3, md: 10 },
22
+ py: { xs: 4, md: 0 },
21
23
  height: "100vh",
22
24
  justifyContent: "center",
23
25
  alignItems: "center",
24
26
  }}
25
27
  >
26
28
  <Logo
27
- maxSize={200}
29
+ maxSize={140}
28
30
  sx={{
29
- mt: { xs: 2, md: 8 },
30
- mb: { xs: 10, md: 8 },
31
+ mb: { xs: 1, md: 2 },
31
32
  }}
32
33
  />
33
34
 
34
35
  <Card
35
36
  sx={{
36
- py: { xs: 5, md: 0 },
37
- px: { xs: 3, md: 0 },
38
- boxShadow: { md: "none" },
37
+ width: 1,
38
+ py: { xs: 6, md: 8 },
39
+ px: { xs: 4, md: 6 },
40
+ boxShadow: {
41
+ xs: (theme) =>
42
+ `0 0 2px ${alpha(
43
+ theme.palette.grey[500],
44
+ 0.16
45
+ )}, 0 12px 24px -4px ${alpha(theme.palette.grey[500], 0.12)}`,
46
+ md: "none",
47
+ },
39
48
  overflow: { md: "unset" },
40
- bgcolor: { md: "background.default" },
49
+ bgcolor: { md: "transparent" },
50
+ borderRadius: 2,
41
51
  }}
42
52
  >
43
53
  <Outlet />
@@ -46,7 +56,12 @@ export default function AuthModernLayout({ image }) {
46
56
  );
47
57
 
48
58
  const renderSection = (
49
- <Stack flexGrow={1} sx={{ position: "relative" }}>
59
+ <Stack
60
+ flexGrow={1}
61
+ sx={{
62
+ position: "relative",
63
+ }}
64
+ >
50
65
  <Box
51
66
  component="img"
52
67
  alt="auth"
@@ -59,6 +74,7 @@ export default function AuthModernLayout({ image }) {
59
74
  position: "absolute",
60
75
  width: "calc(60% - 32px)",
61
76
  height: "calc(60% - 32px)",
77
+ borderRadius: 3,
62
78
  }}
63
79
  />
64
80
  </Stack>
@@ -1,3 +1,10 @@
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
+
1
8
  import Box from "@mui/material/Box";
2
9
  import IconButton from "@mui/material/IconButton";
3
10
  import Iconify from "../../../components/Iconify";
@@ -22,13 +29,6 @@ import { useEventListener } from "../../../hooks/use-event-listener";
22
29
  import { useNavigate } from "react-router-dom";
23
30
  import useProjects from "../../../hooks/useProjects";
24
31
 
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
34
  const { appId } = config();
@@ -94,21 +94,14 @@ function ProjectBar() {
94
94
  const refreshToken = storage.get("link", "refreshToken");
95
95
  const identityProvider = storage.get("link", "identityProvider");
96
96
 
97
- const isDemo = identityProvider?.toUpperCase() === "DEMO";
98
-
99
- const request = isDemo
100
- ? oauth.post("/oauth/demo", {
101
- appId,
102
- projectId,
103
- username: "admin",
104
- password: "admin",
105
- })
106
- : oauth.post("/oauth", {
107
- appId,
108
- refreshToken,
109
- projectId,
110
- identityProvider,
111
- });
97
+ const request = oauth.post("/oauth", {
98
+ appId,
99
+ refreshToken,
100
+ projectId,
101
+ identityProvider,
102
+ username: "admin",
103
+ password: "admin",
104
+ });
112
105
 
113
106
  request
114
107
  .then(({ data }) => {
@@ -1,3 +1,6 @@
1
+ import { Grid, Stack, Switch, Typography } from "@mui/material";
2
+ import { publish, useEvent } from "@nucleoidai/react-event";
3
+
1
4
  import Dialog from "@mui/material/Dialog";
2
5
  import DialogContent from "@mui/material/DialogContent";
3
6
  import DialogTitle from "@mui/material/DialogTitle";
@@ -7,9 +10,6 @@ import SelectAvatar from "../IconSelector/IconSelector";
7
10
  import SparkleInput from "../SparkleInput/SparkleInput";
8
11
  import StepComponent from "../StepComponent/StepComponent";
9
12
 
10
- import { Grid, Stack, Switch, Typography } from "@mui/material";
11
- import { publish, useEvent } from "@nucleoidai/react-event";
12
-
13
13
  function AddItemWizard({ onSubmit, items, steps, stepExp }) {
14
14
  const [activeStep, setActiveStep] = React.useState(0);
15
15
  const [newItems, setNewItems] = React.useState(items);
@@ -3,9 +3,9 @@ import Breadcrumbs from "@mui/material/Breadcrumbs";
3
3
  import Link from "@mui/material/Link";
4
4
  import LinkItem from "./link-item";
5
5
  import PropTypes from "prop-types";
6
+ import React from "react";
6
7
  import Stack from "@mui/material/Stack";
7
8
  import Typography from "@mui/material/Typography";
8
-
9
9
  export default function CustomBreadcrumbs({
10
10
  links,
11
11
  action,
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from "react";
1
+ import React, { useCallback, useState } from "react";
2
2
 
3
3
  export default function usePopover() {
4
4
  const [open, setOpen] = useState(null);
@@ -1,6 +1,6 @@
1
1
  import { FormProvider as Form } from "react-hook-form";
2
2
  import PropTypes from "prop-types";
3
-
3
+ import React from "react";
4
4
  export default function FormProvider({ children, onSubmit, methods }) {
5
5
  return (
6
6
  <Form {...methods}>
@@ -1,5 +1,6 @@
1
1
  import DialogContentText from "@mui/material/DialogContentText";
2
2
  import Grid from "@mui/material/Grid";
3
+ import React from "react";
3
4
  import SvgColor from "../SvgColor";
4
5
 
5
6
  import {
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import SvgColor from "../SvgColor";
2
3
 
3
4
  import {
@@ -1,8 +1,9 @@
1
- import { Controller, useFormContext } from "react-hook-form";
2
-
3
1
  import PropTypes from "prop-types";
2
+ import React from "react";
4
3
  import TextField from "@mui/material/TextField";
5
4
 
5
+ import { Controller, useFormContext } from "react-hook-form";
6
+
6
7
  export default function RHFTextField({ name, helperText, type, ...other }) {
7
8
  const { control } = useFormContext();
8
9
 
@@ -1,6 +1,6 @@
1
1
  import Paper from "@mui/material/Paper";
2
+ import React from "react";
2
3
  import Typography from "@mui/material/Typography";
3
-
4
4
  export default function SearchNotFound({ query, sx, ...other }) {
5
5
  return query ? (
6
6
  <Paper
@@ -1,6 +1,7 @@
1
1
  import Box from "@mui/material/Box";
2
2
  import PropTypes from "prop-types";
3
- import { forwardRef } from "react";
3
+
4
+ import React, { forwardRef } from "react";
4
5
 
5
6
  const SvgColor = forwardRef(({ src, sx, ...other }, ref) => (
6
7
  <Box
@@ -1,11 +1,11 @@
1
1
  import Box from "@mui/material/Box";
2
2
  import Checkbox from "@mui/material/Checkbox";
3
3
  import PropTypes from "prop-types";
4
+ import React from "react";
4
5
  import TableCell from "@mui/material/TableCell";
5
6
  import TableHead from "@mui/material/TableHead";
6
7
  import TableRow from "@mui/material/TableRow";
7
8
  import TableSortLabel from "@mui/material/TableSortLabel";
8
-
9
9
  const visuallyHidden = {
10
10
  border: 0,
11
11
  margin: -1,
@@ -1,8 +1,8 @@
1
1
  import Checkbox from "@mui/material/Checkbox";
2
2
  import PropTypes from "prop-types";
3
+ import React from "react";
3
4
  import Stack from "@mui/material/Stack";
4
5
  import Typography from "@mui/material/Typography";
5
-
6
6
  export default function TableSelectedAction({
7
7
  dense,
8
8
  action,
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import merge from "lodash/merge";
2
3
  import { useResponsive } from "../../hooks/use-responsive";
3
4
 
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from "react";
1
+ import React, { useCallback, useState } from "react";
2
2
 
3
3
  export default function useTable(props) {
4
4
  const [dense, setDense] = useState(!!props?.defaultDense);
@@ -1,3 +1,4 @@
1
+ import AmplifyLogin from "../widgets/Login/AmplifyLogin";
1
2
  import CognitoLogin from "../widgets/Login/CognitoLogin";
2
3
  import DemoLogin from "../widgets/Login/DemoLogin";
3
4
  import LoginForm from "../widgets/LoginForm/LoginForm";
@@ -31,7 +32,7 @@ function LoginPage() {
31
32
  }, [navigate]);
32
33
 
33
34
  if (credentials?.provider === "COGNITO") {
34
- return <CognitoLogin />;
35
+ return <AmplifyLogin />;
35
36
  }
36
37
 
37
38
  if (credentials?.provider === "DEMO") {
@@ -0,0 +1,54 @@
1
+ import { Button, Stack, TextField, Typography } from "@mui/material";
2
+
3
+ import { loginWithAmplify } from "./amplify";
4
+ import { storage } from "@nucleoidjs/webstorage";
5
+ import { useState } from "react";
6
+
7
+ export default function AmplifyLogin() {
8
+ const [username, setUsername] = useState("");
9
+ const [password, setPassword] = useState("");
10
+
11
+ const handleLogin = async () => {
12
+ try {
13
+ const result = await loginWithAmplify(username, password);
14
+
15
+ if (result.challenge) {
16
+ console.log("Challenge required:", result.challenge);
17
+ alert(`Challenge required: ${result.challenge}`);
18
+ return;
19
+ }
20
+
21
+ console.log("Login successful, tokens:", result);
22
+
23
+ storage.set("link", "accessToken", result.AccessToken);
24
+ storage.set("link", "refreshToken", result.RefreshToken);
25
+
26
+ window.location.href = "/";
27
+ } catch (e) {
28
+ console.error("Login error:", e);
29
+ alert(`Login failed: ${e.message || e}`);
30
+ }
31
+ };
32
+
33
+ return (
34
+ <>
35
+ <Typography variant="h4">Login</Typography>
36
+ <Stack spacing={2}>
37
+ <TextField
38
+ label="Username or Email"
39
+ value={username}
40
+ onChange={(e) => setUsername(e.target.value)}
41
+ />
42
+ <TextField
43
+ type="password"
44
+ label="Password"
45
+ value={password}
46
+ onChange={(e) => setPassword(e.target.value)}
47
+ />
48
+ <Button variant="contained" onClick={handleLogin}>
49
+ Login
50
+ </Button>
51
+ </Stack>
52
+ </>
53
+ );
54
+ }
@@ -1,4 +1,19 @@
1
- import { Button, Stack, TextField, Typography } from "@mui/material";
1
+ import {
2
+ Box,
3
+ Button,
4
+ IconButton,
5
+ InputAdornment,
6
+ Stack,
7
+ TextField,
8
+ Typography,
9
+ alpha,
10
+ } from "@mui/material";
11
+ import {
12
+ LockOutlined,
13
+ PersonOutline,
14
+ Visibility,
15
+ VisibilityOff,
16
+ } from "@mui/icons-material";
2
17
  import React, { useState } from "react";
3
18
 
4
19
  import config from "../../config/config";
@@ -8,12 +23,13 @@ import { useNavigate } from "react-router-dom";
8
23
  export default function DemoLogin() {
9
24
  const [username, setUsername] = useState("");
10
25
  const [password, setPassword] = useState("");
26
+ const [showPassword, setShowPassword] = useState(false);
11
27
  const navigate = useNavigate();
12
28
 
13
29
  const { appId } = config();
14
30
 
15
31
  async function handleLogin() {
16
- const res = await fetch("/api/oauth/demo", {
32
+ const res = await fetch("/api/oauth", {
17
33
  method: "POST",
18
34
  headers: { "Content-Type": "application/json" },
19
35
  body: JSON.stringify({
@@ -21,6 +37,7 @@ export default function DemoLogin() {
21
37
  projectId: "cb16e069-6214-47f1-9922-1f7fe7629525",
22
38
  username,
23
39
  password,
40
+ identityProvider: "DEMO",
24
41
  }),
25
42
  });
26
43
 
@@ -30,29 +47,133 @@ export default function DemoLogin() {
30
47
 
31
48
  storage.set("link", "accessToken", data.accessToken);
32
49
  storage.set("link", "refreshToken", data.refreshToken);
33
- storage.set("link", "identityProvider", "Demo");
50
+ storage.set("link", "identityProvider", "DEMO");
34
51
 
35
52
  navigate("/");
36
53
  }
37
54
 
38
55
  return (
39
- <Stack spacing={2} maxWidth={500} mx="auto">
40
- <Typography variant="h5">Login</Typography>
41
- <TextField
42
- label="Username"
43
- value={username}
44
- onChange={(e) => setUsername(e.target.value)}
45
- />
46
- <TextField
47
- label="Password"
48
- type="password"
49
- value={password}
50
- onChange={(e) => setPassword(e.target.value)}
51
- />
52
- <Button variant="contained" onClick={handleLogin}>
56
+ <Stack spacing={2.5}>
57
+ <Stack spacing={2}>
58
+ <TextField
59
+ label="Username"
60
+ value={username}
61
+ onChange={(e) => setUsername(e.target.value)}
62
+ fullWidth
63
+ InputProps={{
64
+ startAdornment: (
65
+ <InputAdornment position="start">
66
+ <PersonOutline sx={{ color: "text.secondary", fontSize: 22 }} />
67
+ </InputAdornment>
68
+ ),
69
+ }}
70
+ sx={{
71
+ "& .MuiOutlinedInput-root": {
72
+ fontSize: "1rem",
73
+ "& input": {
74
+ py: 1.5,
75
+ },
76
+ "&:hover fieldset": {
77
+ borderColor: "primary.main",
78
+ },
79
+ },
80
+ }}
81
+ />
82
+
83
+ <TextField
84
+ label="Password"
85
+ type={showPassword ? "text" : "password"}
86
+ value={password}
87
+ onChange={(e) => setPassword(e.target.value)}
88
+ fullWidth
89
+ InputProps={{
90
+ startAdornment: (
91
+ <InputAdornment position="start">
92
+ <LockOutlined sx={{ color: "text.secondary", fontSize: 22 }} />
93
+ </InputAdornment>
94
+ ),
95
+ endAdornment: (
96
+ <InputAdornment position="end">
97
+ <IconButton
98
+ onClick={() => setShowPassword(!showPassword)}
99
+ edge="end"
100
+ size="small"
101
+ tabIndex={-1}
102
+ >
103
+ {showPassword ? <VisibilityOff /> : <Visibility />}
104
+ </IconButton>
105
+ </InputAdornment>
106
+ ),
107
+ }}
108
+ sx={{
109
+ "& .MuiOutlinedInput-root": {
110
+ fontSize: "1rem",
111
+ "& input": {
112
+ py: 1.5,
113
+ },
114
+ "&:hover fieldset": {
115
+ borderColor: "primary.main",
116
+ },
117
+ },
118
+ }}
119
+ onKeyPress={(e) => {
120
+ if (e.key === "Enter") {
121
+ handleLogin();
122
+ }
123
+ }}
124
+ />
125
+ </Stack>
126
+
127
+ <Button
128
+ variant="contained"
129
+ onClick={handleLogin}
130
+ size="large"
131
+ fullWidth
132
+ sx={{
133
+ mt: 1,
134
+ py: 1.5,
135
+ fontSize: "1rem",
136
+ fontWeight: 600,
137
+ textTransform: "none",
138
+ borderRadius: 1.5,
139
+ boxShadow: (theme) =>
140
+ `0 8px 16px ${alpha(theme.palette.primary.main, 0.24)}`,
141
+ transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
142
+ "&:hover": {
143
+ transform: "translateY(-2px)",
144
+ boxShadow: (theme) =>
145
+ `0 12px 24px ${alpha(theme.palette.primary.main, 0.32)}`,
146
+ },
147
+ "&:active": {
148
+ transform: "translateY(0px)",
149
+ },
150
+ }}
151
+ >
53
152
  Sign in
54
153
  </Button>
55
- <Typography variant="caption">Use: admin / admin</Typography>
154
+
155
+ <Box
156
+ sx={{
157
+ mt: 1,
158
+ textAlign: "center",
159
+ p: 2,
160
+ borderRadius: 1.5,
161
+ bgcolor: (theme) => alpha(theme.palette.info.main, 0.08),
162
+ border: (theme) =>
163
+ `1px dashed ${alpha(theme.palette.info.main, 0.24)}`,
164
+ }}
165
+ >
166
+ <Typography
167
+ variant="caption"
168
+ color="text.secondary"
169
+ sx={{ fontSize: "0.8125rem" }}
170
+ >
171
+ Demo credentials:{" "}
172
+ <Box component="strong" sx={{ color: "text.primary" }}>
173
+ admin / admin
174
+ </Box>
175
+ </Typography>
176
+ </Box>
56
177
  </Stack>
57
178
  );
58
179
  }
@@ -0,0 +1,26 @@
1
+ import { Auth } from "aws-amplify";
2
+ import { initAmplifyAuth } from "./amplifyAuth";
3
+
4
+ export async function loginWithAmplify(username, password) {
5
+ console.log(Auth.configure());
6
+
7
+ initAmplifyAuth();
8
+
9
+ const user = await Auth.signIn(username, password);
10
+
11
+ // Handle challenges if needed
12
+ if (user.challengeName) {
13
+ return {
14
+ challenge: user.challengeName,
15
+ user,
16
+ };
17
+ }
18
+
19
+ const session = user.signInUserSession;
20
+
21
+ return {
22
+ AccessToken: session.accessToken.jwtToken,
23
+ IdToken: session.idToken.jwtToken,
24
+ RefreshToken: session.refreshToken.token,
25
+ };
26
+ }
@@ -0,0 +1,25 @@
1
+ import { Amplify } from "aws-amplify";
2
+ import config from "../../config/config";
3
+
4
+ let initialized = false;
5
+
6
+ export function initAmplifyAuth() {
7
+ if (initialized) return;
8
+
9
+ const { credentials } = config();
10
+ if (!credentials) {
11
+ throw new Error("Cognito credentials not initialized yet");
12
+ }
13
+
14
+ Amplify.configure({
15
+ Auth: {
16
+ region: credentials.region,
17
+ userPoolId: credentials.userPoolId,
18
+ userPoolWebClientId: credentials.clientId,
19
+ authenticationFlowType: "USER_SRP_AUTH",
20
+ },
21
+ });
22
+
23
+ initialized = true;
24
+ console.log("Amplify Auth initialized (SRP)");
25
+ }
package/vite/vite.js CHANGED
@@ -57,9 +57,18 @@ async function vite() {
57
57
  rollupOptions: {
58
58
  output: {
59
59
  entryFileNames: `assets/[name].[hash].js`,
60
- chunkFileNames: `assets/[name].[hash].js`,
60
+ chunkFileNames: (chunkInfo) => {
61
+ if (chunkInfo.name === "config") {
62
+ return "config.js";
63
+ }
64
+ return `assets/[name].[hash].js`;
65
+ },
61
66
  assetFileNames: `assets/[name].[hash].[ext]`,
62
67
  manualChunks(id) {
68
+ if (id.includes("config.js") && !id.includes("node_modules")) {
69
+ return "config";
70
+ }
71
+
63
72
  if (id.includes("node_modules")) {
64
73
  return id
65
74
  .toString()