datajunction-ui 0.0.1-rc.24 → 0.0.1-rc.26
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/.env +1 -0
- package/package.json +3 -2
- package/src/app/components/Tab.jsx +0 -1
- package/src/app/constants.js +2 -2
- package/src/app/icons/LoadingIcon.jsx +14 -0
- package/src/app/index.tsx +11 -1
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +28 -2
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +44 -9
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +1 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +0 -50
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +2 -0
- package/src/app/pages/AddEditNodePage/index.jsx +60 -6
- package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
- package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
- package/src/app/pages/AddEditTagPage/index.jsx +132 -0
- package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
- package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
- package/src/app/pages/LoginPage/__tests__/index.test.jsx +34 -2
- package/src/app/pages/LoginPage/index.jsx +9 -82
- package/src/app/pages/NamespacePage/index.jsx +5 -0
- package/src/app/pages/NodePage/AddBackfillPopover.jsx +166 -0
- package/src/app/pages/NodePage/AddMaterializationPopover.jsx +161 -0
- package/src/app/pages/NodePage/EditColumnPopover.jsx +1 -1
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +0 -1
- package/src/app/pages/NodePage/NodeColumnTab.jsx +102 -25
- package/src/app/pages/NodePage/NodeInfoTab.jsx +33 -23
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +158 -99
- package/src/app/pages/NodePage/PartitionColumnPopover.jsx +153 -0
- package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +47 -0
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +47 -17
- package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +101 -100
- package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +1 -0
- package/src/app/pages/Root/index.tsx +1 -1
- package/src/app/pages/TagPage/Loadable.jsx +16 -0
- package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
- package/src/app/pages/TagPage/index.jsx +79 -0
- package/src/app/services/DJService.js +166 -1
- package/src/app/services/__tests__/DJService.test.jsx +196 -1
- package/src/mocks/mockNodes.jsx +64 -31
- package/src/styles/dag.css +4 -0
- package/src/styles/index.css +89 -1
- package/src/styles/loading.css +34 -0
- package/src/styles/login.css +17 -3
- package/src/utils/form.jsx +2 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add or edit tags
|
|
3
|
+
*/
|
|
4
|
+
import { ErrorMessage, Field, Form, Formik } from 'formik';
|
|
5
|
+
|
|
6
|
+
import NamespaceHeader from '../../components/NamespaceHeader';
|
|
7
|
+
import React, { useContext } from 'react';
|
|
8
|
+
import DJClientContext from '../../providers/djclient';
|
|
9
|
+
import 'styles/node-creation.scss';
|
|
10
|
+
import { displayMessageAfterSubmit } from '../../../utils/form';
|
|
11
|
+
|
|
12
|
+
export function AddEditTagPage() {
|
|
13
|
+
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
14
|
+
const initialValues = {
|
|
15
|
+
name: '',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const validator = values => {
|
|
19
|
+
const errors = {};
|
|
20
|
+
if (!values.name) {
|
|
21
|
+
errors.name = 'Required';
|
|
22
|
+
}
|
|
23
|
+
return errors;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const handleSubmit = async (values, { setSubmitting, setStatus }) => {
|
|
27
|
+
const { status, json } = await djClient.addTag(
|
|
28
|
+
values.name,
|
|
29
|
+
values.display_name,
|
|
30
|
+
values.tag_type,
|
|
31
|
+
values.description,
|
|
32
|
+
);
|
|
33
|
+
if (status === 200 || status === 201) {
|
|
34
|
+
setStatus({
|
|
35
|
+
success: (
|
|
36
|
+
<>
|
|
37
|
+
Successfully added tag{' '}
|
|
38
|
+
<a href={`/tags/${json.name}`}>{json.display_name}</a>.
|
|
39
|
+
</>
|
|
40
|
+
),
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
setStatus({
|
|
44
|
+
failure: `${json.message}`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
setSubmitting(false);
|
|
48
|
+
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className="mid">
|
|
53
|
+
<NamespaceHeader namespace="" />
|
|
54
|
+
<div className="card">
|
|
55
|
+
<div className="card-header">
|
|
56
|
+
<h2>
|
|
57
|
+
Add{' '}
|
|
58
|
+
<span className={`node_type__source node_type_creation_heading`}>
|
|
59
|
+
Tag
|
|
60
|
+
</span>
|
|
61
|
+
</h2>
|
|
62
|
+
<center>
|
|
63
|
+
<Formik
|
|
64
|
+
initialValues={initialValues}
|
|
65
|
+
validate={validator}
|
|
66
|
+
onSubmit={handleSubmit}
|
|
67
|
+
>
|
|
68
|
+
{function Render({ isSubmitting, status }) {
|
|
69
|
+
return (
|
|
70
|
+
<Form>
|
|
71
|
+
{displayMessageAfterSubmit(status)}
|
|
72
|
+
{
|
|
73
|
+
<>
|
|
74
|
+
<div className="NodeCreationInput">
|
|
75
|
+
<ErrorMessage name="name" component="span" />
|
|
76
|
+
<label htmlFor="name">Name</label>
|
|
77
|
+
<Field
|
|
78
|
+
type="text"
|
|
79
|
+
name="name"
|
|
80
|
+
id="name"
|
|
81
|
+
placeholder="Tag Name"
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
<br />
|
|
85
|
+
<div className="FullNameInput NodeCreationInput">
|
|
86
|
+
<ErrorMessage name="display_name" component="span" />
|
|
87
|
+
<label htmlFor="display_name">Display Name</label>
|
|
88
|
+
<Field
|
|
89
|
+
type="text"
|
|
90
|
+
name="display_name"
|
|
91
|
+
id="display_name"
|
|
92
|
+
placeholder="Display Name"
|
|
93
|
+
class="FullNameField"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
<br />
|
|
97
|
+
<div className="NodeCreationInput">
|
|
98
|
+
<ErrorMessage name="tag_type" component="span" />
|
|
99
|
+
<label htmlFor="tag_type">Tag Type</label>
|
|
100
|
+
<Field
|
|
101
|
+
type="text"
|
|
102
|
+
name="tag_type"
|
|
103
|
+
id="tag_type"
|
|
104
|
+
placeholder="Tag Type"
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="DescriptionInput NodeCreationInput">
|
|
108
|
+
<ErrorMessage name="description" component="span" />
|
|
109
|
+
<label htmlFor="description">Description</label>
|
|
110
|
+
<Field
|
|
111
|
+
type="textarea"
|
|
112
|
+
as="textarea"
|
|
113
|
+
name="description"
|
|
114
|
+
id="Description"
|
|
115
|
+
placeholder="Describe the tag"
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
<button type="submit" disabled={isSubmitting}>
|
|
119
|
+
Add Tag
|
|
120
|
+
</button>
|
|
121
|
+
</>
|
|
122
|
+
}
|
|
123
|
+
</Form>
|
|
124
|
+
);
|
|
125
|
+
}}
|
|
126
|
+
</Formik>
|
|
127
|
+
</center>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Formik, Form, Field, ErrorMessage } from 'formik';
|
|
3
|
+
import '../../../styles/login.css';
|
|
4
|
+
import LoadingIcon from '../../icons/LoadingIcon';
|
|
5
|
+
import logo from '../Root/assets/dj-logo.png';
|
|
6
|
+
import GitHubLoginButton from './assets/sign-in-with-github.png';
|
|
7
|
+
import GoogleLoginButton from './assets/sign-in-with-google.png';
|
|
8
|
+
import * as Yup from 'yup';
|
|
9
|
+
|
|
10
|
+
const githubLoginURL = new URL('/github/login/', process.env.REACT_APP_DJ_URL);
|
|
11
|
+
const googleLoginURL = new URL('/google/login/', process.env.REACT_APP_DJ_URL);
|
|
12
|
+
|
|
13
|
+
const LoginSchema = Yup.object().shape({
|
|
14
|
+
username: Yup.string()
|
|
15
|
+
.min(2, 'Must be at least 2 characters')
|
|
16
|
+
.required('Username is required'),
|
|
17
|
+
password: Yup.string().required('Password is required'),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default function LoginForm({ setShowSignup }) {
|
|
21
|
+
const [, setError] = useState('');
|
|
22
|
+
|
|
23
|
+
// Add the path that the user was trying to access in order to properly redirect after auth
|
|
24
|
+
githubLoginURL.searchParams.append('target', window.location.pathname);
|
|
25
|
+
googleLoginURL.searchParams.append('target', window.location.pathname);
|
|
26
|
+
|
|
27
|
+
const handleBasicLogin = async ({ username, password }) => {
|
|
28
|
+
const data = new FormData();
|
|
29
|
+
data.append('username', username);
|
|
30
|
+
data.append('password', password);
|
|
31
|
+
await fetch(`${process.env.REACT_APP_DJ_URL}/basic/login/`, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
body: data,
|
|
34
|
+
credentials: 'include',
|
|
35
|
+
}).catch(error => {
|
|
36
|
+
setError(error ? JSON.stringify(error) : '');
|
|
37
|
+
});
|
|
38
|
+
window.location.reload();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Formik
|
|
43
|
+
initialValues={{
|
|
44
|
+
username: '',
|
|
45
|
+
password: '',
|
|
46
|
+
target: window.location.pathname,
|
|
47
|
+
}}
|
|
48
|
+
validationSchema={LoginSchema}
|
|
49
|
+
onSubmit={(values, { setSubmitting }) => {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
handleBasicLogin(values);
|
|
52
|
+
setSubmitting(false);
|
|
53
|
+
}, 400);
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
{({ isSubmitting }) => (
|
|
57
|
+
<Form>
|
|
58
|
+
<div className="logo-title">
|
|
59
|
+
<img src={logo} alt="DJ Logo" width="75px" height="75px" />
|
|
60
|
+
<h2>DataJunction</h2>
|
|
61
|
+
</div>
|
|
62
|
+
<div>
|
|
63
|
+
<Field type="text" name="username" placeholder="Username" />
|
|
64
|
+
</div>
|
|
65
|
+
<div>
|
|
66
|
+
<ErrorMessage
|
|
67
|
+
className="form-error"
|
|
68
|
+
name="username"
|
|
69
|
+
component="span"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
<div>
|
|
73
|
+
<Field type="password" name="password" placeholder="Password" />
|
|
74
|
+
</div>
|
|
75
|
+
<div>
|
|
76
|
+
<ErrorMessage
|
|
77
|
+
className="form-error"
|
|
78
|
+
name="password"
|
|
79
|
+
component="span"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
<div>
|
|
83
|
+
<p>
|
|
84
|
+
Don't have an account yet?{' '}
|
|
85
|
+
<a onClick={() => setShowSignup(true)}>Sign Up</a>
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
<button type="submit" disabled={isSubmitting}>
|
|
89
|
+
{isSubmitting ? <LoadingIcon /> : 'Login'}
|
|
90
|
+
</button>
|
|
91
|
+
<div>
|
|
92
|
+
<p>Or</p>
|
|
93
|
+
</div>
|
|
94
|
+
{process.env.REACT_ENABLE_GITHUB_OAUTH === 'true' ? (
|
|
95
|
+
<div>
|
|
96
|
+
<a href={githubLoginURL.href}>
|
|
97
|
+
<img
|
|
98
|
+
src={GitHubLoginButton}
|
|
99
|
+
alt="Sign in with GitHub"
|
|
100
|
+
width="200px"
|
|
101
|
+
/>
|
|
102
|
+
</a>
|
|
103
|
+
</div>
|
|
104
|
+
) : (
|
|
105
|
+
''
|
|
106
|
+
)}
|
|
107
|
+
{process.env.REACT_ENABLE_GOOGLE_OAUTH === 'true' ? (
|
|
108
|
+
<div>
|
|
109
|
+
<a href={googleLoginURL.href}>
|
|
110
|
+
<img
|
|
111
|
+
src={GoogleLoginButton}
|
|
112
|
+
alt="Sign in with Google"
|
|
113
|
+
width="200px"
|
|
114
|
+
/>
|
|
115
|
+
</a>
|
|
116
|
+
</div>
|
|
117
|
+
) : (
|
|
118
|
+
''
|
|
119
|
+
)}
|
|
120
|
+
</Form>
|
|
121
|
+
)}
|
|
122
|
+
</Formik>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Formik, Form, Field, ErrorMessage } from 'formik';
|
|
3
|
+
import '../../../styles/login.css';
|
|
4
|
+
import logo from '../Root/assets/dj-logo.png';
|
|
5
|
+
import LoadingIcon from '../../icons/LoadingIcon';
|
|
6
|
+
import GitHubLoginButton from './assets/sign-in-with-github.png';
|
|
7
|
+
import GoogleLoginButton from './assets/sign-in-with-google.png';
|
|
8
|
+
import * as Yup from 'yup';
|
|
9
|
+
|
|
10
|
+
const githubLoginURL = new URL('/github/login/', process.env.REACT_APP_DJ_URL);
|
|
11
|
+
const googleLoginURL = new URL('/google/login/', process.env.REACT_APP_DJ_URL);
|
|
12
|
+
|
|
13
|
+
const SignupSchema = Yup.object().shape({
|
|
14
|
+
email: Yup.string().email('Invalid email').required('Email is required'),
|
|
15
|
+
signupUsername: Yup.string()
|
|
16
|
+
.min(3, 'Must be at least 2 characters')
|
|
17
|
+
.max(20, 'Must be less than 20 characters')
|
|
18
|
+
.required('Username is required'),
|
|
19
|
+
signupPassword: Yup.string().required('Password is required'),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default function SignupForm({ setShowSignup }) {
|
|
23
|
+
const [, setError] = useState('');
|
|
24
|
+
|
|
25
|
+
// Add the path that the user was trying to access in order to properly redirect after auth
|
|
26
|
+
githubLoginURL.searchParams.append('target', window.location.pathname);
|
|
27
|
+
googleLoginURL.searchParams.append('target', window.location.pathname);
|
|
28
|
+
|
|
29
|
+
const handleBasicSignup = async ({
|
|
30
|
+
email,
|
|
31
|
+
signupUsername,
|
|
32
|
+
signupPassword,
|
|
33
|
+
}) => {
|
|
34
|
+
const data = new FormData();
|
|
35
|
+
data.append('email', email);
|
|
36
|
+
data.append('username', signupUsername);
|
|
37
|
+
data.append('password', signupPassword);
|
|
38
|
+
await fetch(`${process.env.REACT_APP_DJ_URL}/basic/user/`, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
body: data,
|
|
41
|
+
credentials: 'include',
|
|
42
|
+
}).catch(error => {
|
|
43
|
+
setError(error ? JSON.stringify(error) : '');
|
|
44
|
+
});
|
|
45
|
+
const loginData = new FormData();
|
|
46
|
+
loginData.append('username', signupUsername);
|
|
47
|
+
loginData.append('password', signupPassword);
|
|
48
|
+
await fetch(`${process.env.REACT_APP_DJ_URL}/basic/login/`, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
body: data,
|
|
51
|
+
credentials: 'include',
|
|
52
|
+
}).catch(error => {
|
|
53
|
+
setError(error ? JSON.stringify(error) : '');
|
|
54
|
+
});
|
|
55
|
+
window.location.reload();
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Formik
|
|
60
|
+
initialValues={{
|
|
61
|
+
email: '',
|
|
62
|
+
signupUsername: '',
|
|
63
|
+
signupPassword: '',
|
|
64
|
+
target: window.location.pathname,
|
|
65
|
+
}}
|
|
66
|
+
validationSchema={SignupSchema}
|
|
67
|
+
onSubmit={(values, { setSubmitting }) => {
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
handleBasicSignup(values);
|
|
70
|
+
setSubmitting(false);
|
|
71
|
+
}, 400);
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
{({ isSubmitting }) => (
|
|
75
|
+
<Form>
|
|
76
|
+
<div className="logo-title">
|
|
77
|
+
<img src={logo} alt="DJ Logo" width="75px" height="75px" />
|
|
78
|
+
<h2>DataJunction</h2>
|
|
79
|
+
</div>
|
|
80
|
+
<div>
|
|
81
|
+
<Field type="text" name="email" placeholder="Email" />
|
|
82
|
+
</div>
|
|
83
|
+
<div>
|
|
84
|
+
<ErrorMessage
|
|
85
|
+
className="form-error"
|
|
86
|
+
name="email"
|
|
87
|
+
component="span"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
<div>
|
|
91
|
+
<Field type="text" name="signupUsername" placeholder="Username" />
|
|
92
|
+
</div>
|
|
93
|
+
<div>
|
|
94
|
+
<ErrorMessage
|
|
95
|
+
className="form-error"
|
|
96
|
+
name="signupUsername"
|
|
97
|
+
component="span"
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
<div>
|
|
101
|
+
<Field
|
|
102
|
+
type="password"
|
|
103
|
+
name="signupPassword"
|
|
104
|
+
placeholder="Password"
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
107
|
+
<div>
|
|
108
|
+
<ErrorMessage
|
|
109
|
+
className="form-error"
|
|
110
|
+
name="signupPassword"
|
|
111
|
+
component="span"
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
<div>
|
|
115
|
+
<p>
|
|
116
|
+
Have an account already?{' '}
|
|
117
|
+
<a onClick={() => setShowSignup(false)}>Login</a>
|
|
118
|
+
</p>
|
|
119
|
+
</div>
|
|
120
|
+
<button type="submit" disabled={isSubmitting}>
|
|
121
|
+
{isSubmitting ? <LoadingIcon /> : 'Sign Up'}
|
|
122
|
+
</button>
|
|
123
|
+
<div>
|
|
124
|
+
<p>Or</p>
|
|
125
|
+
</div>
|
|
126
|
+
{process.env.REACT_ENABLE_GITHUB_OAUTH === 'true' ? (
|
|
127
|
+
<div>
|
|
128
|
+
<a href={githubLoginURL.href}>
|
|
129
|
+
<img
|
|
130
|
+
src={GitHubLoginButton}
|
|
131
|
+
alt="Sign in with GitHub"
|
|
132
|
+
width="200px"
|
|
133
|
+
/>
|
|
134
|
+
</a>
|
|
135
|
+
</div>
|
|
136
|
+
) : (
|
|
137
|
+
''
|
|
138
|
+
)}
|
|
139
|
+
{process.env.REACT_ENABLE_GOOGLE_OAUTH === 'true' ? (
|
|
140
|
+
<div>
|
|
141
|
+
<a href={googleLoginURL.href}>
|
|
142
|
+
<img
|
|
143
|
+
src={GoogleLoginButton}
|
|
144
|
+
alt="Sign in with Google"
|
|
145
|
+
width="200px"
|
|
146
|
+
/>
|
|
147
|
+
</a>
|
|
148
|
+
</div>
|
|
149
|
+
) : (
|
|
150
|
+
''
|
|
151
|
+
)}
|
|
152
|
+
</Form>
|
|
153
|
+
)}
|
|
154
|
+
</Formik>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
@@ -33,11 +33,12 @@ describe('LoginPage', () => {
|
|
|
33
33
|
|
|
34
34
|
await waitFor(() => {
|
|
35
35
|
expect(getByText('DataJunction')).toBeInTheDocument();
|
|
36
|
-
expect(
|
|
36
|
+
expect(getByText('Username is required')).toBeInTheDocument();
|
|
37
|
+
expect(getByText('Password is required')).toBeInTheDocument();
|
|
37
38
|
});
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
it('calls fetch with correct data on
|
|
41
|
+
it('calls fetch with correct data on login', async () => {
|
|
41
42
|
const username = 'testUser';
|
|
42
43
|
const password = 'testPassword';
|
|
43
44
|
|
|
@@ -62,4 +63,35 @@ describe('LoginPage', () => {
|
|
|
62
63
|
expect(window.location.reload).toHaveBeenCalled();
|
|
63
64
|
});
|
|
64
65
|
});
|
|
66
|
+
|
|
67
|
+
it('calls fetch with correct data on signup', async () => {
|
|
68
|
+
const email = 'testEmail@testEmail.com';
|
|
69
|
+
const username = 'testUser';
|
|
70
|
+
const password = 'testPassword';
|
|
71
|
+
|
|
72
|
+
const { getByText, getByPlaceholderText } = render(<LoginPage />);
|
|
73
|
+
fireEvent.click(getByText('Sign Up'));
|
|
74
|
+
fireEvent.change(getByPlaceholderText('Email'), {
|
|
75
|
+
target: { value: email },
|
|
76
|
+
});
|
|
77
|
+
fireEvent.change(getByPlaceholderText('Username'), {
|
|
78
|
+
target: { value: username },
|
|
79
|
+
});
|
|
80
|
+
fireEvent.change(getByPlaceholderText('Password'), {
|
|
81
|
+
target: { value: password },
|
|
82
|
+
});
|
|
83
|
+
fireEvent.click(getByText('Sign Up'));
|
|
84
|
+
|
|
85
|
+
await waitFor(() => {
|
|
86
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
87
|
+
`${process.env.REACT_APP_DJ_URL}/basic/user/`,
|
|
88
|
+
expect.objectContaining({
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: expect.any(FormData),
|
|
91
|
+
credentials: 'include',
|
|
92
|
+
}),
|
|
93
|
+
);
|
|
94
|
+
expect(window.location.reload).toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
65
97
|
});
|
|
@@ -1,90 +1,17 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import { Formik, Form, Field, ErrorMessage } from 'formik';
|
|
3
2
|
import '../../../styles/login.css';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import SignupForm from './SignupForm';
|
|
4
|
+
import LoginForm from './LoginForm';
|
|
6
5
|
|
|
7
6
|
export function LoginPage() {
|
|
8
|
-
const [,
|
|
9
|
-
const githubLoginURL = new URL('/github/login/', process.env.REACT_APP_DJ_URL)
|
|
10
|
-
.href;
|
|
11
|
-
|
|
12
|
-
const handleBasicLogin = async ({ username, password }) => {
|
|
13
|
-
const data = new FormData();
|
|
14
|
-
data.append('username', username);
|
|
15
|
-
data.append('password', password);
|
|
16
|
-
await fetch(`${process.env.REACT_APP_DJ_URL}/basic/login/`, {
|
|
17
|
-
method: 'POST',
|
|
18
|
-
body: data,
|
|
19
|
-
credentials: 'include',
|
|
20
|
-
}).catch(error => {
|
|
21
|
-
setError(error ? JSON.stringify(error) : '');
|
|
22
|
-
});
|
|
23
|
-
window.location.reload();
|
|
24
|
-
};
|
|
25
|
-
|
|
7
|
+
const [showSignup, setShowSignup] = useState(false);
|
|
26
8
|
return (
|
|
27
|
-
<div className="container">
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const errors = {};
|
|
34
|
-
if (!values.username) {
|
|
35
|
-
errors.username = 'Required';
|
|
36
|
-
}
|
|
37
|
-
if (!values.password) {
|
|
38
|
-
errors.password = 'Required';
|
|
39
|
-
}
|
|
40
|
-
return errors;
|
|
41
|
-
}}
|
|
42
|
-
onSubmit={(values, { setSubmitting }) => {
|
|
43
|
-
setTimeout(() => {
|
|
44
|
-
handleBasicLogin(values);
|
|
45
|
-
setSubmitting(false);
|
|
46
|
-
}, 400);
|
|
47
|
-
}}
|
|
48
|
-
>
|
|
49
|
-
{({ isSubmitting }) => (
|
|
50
|
-
<Form>
|
|
51
|
-
<div className="logo-title">
|
|
52
|
-
<img src={logo} alt="DJ Logo" width="75px" height="75px" />
|
|
53
|
-
<h2>DataJunction</h2>
|
|
54
|
-
</div>
|
|
55
|
-
<div className="inputContainer">
|
|
56
|
-
<ErrorMessage name="username" component="span" />
|
|
57
|
-
<Field type="text" name="username" placeholder="Username" />
|
|
58
|
-
</div>
|
|
59
|
-
<div>
|
|
60
|
-
<ErrorMessage name="password" component="span" />
|
|
61
|
-
<Field
|
|
62
|
-
type="password"
|
|
63
|
-
name="password"
|
|
64
|
-
placeholder="Password"
|
|
65
|
-
/>
|
|
66
|
-
</div>
|
|
67
|
-
<button type="submit" disabled={isSubmitting}>
|
|
68
|
-
Login
|
|
69
|
-
</button>
|
|
70
|
-
{process.env.REACT_ENABLE_GITHUB_OAUTH === 'true' ? (
|
|
71
|
-
<div>
|
|
72
|
-
<a href={githubLoginURL}>
|
|
73
|
-
<img
|
|
74
|
-
src={GitHubLoginButton}
|
|
75
|
-
alt="Sign in with GitHub"
|
|
76
|
-
width="200px"
|
|
77
|
-
/>
|
|
78
|
-
</a>
|
|
79
|
-
</div>
|
|
80
|
-
) : (
|
|
81
|
-
''
|
|
82
|
-
)}
|
|
83
|
-
</Form>
|
|
84
|
-
)}
|
|
85
|
-
</Formik>
|
|
86
|
-
</center>
|
|
87
|
-
</div>
|
|
9
|
+
<div className="container login">
|
|
10
|
+
{showSignup ? (
|
|
11
|
+
<SignupForm setShowSignup={setShowSignup} />
|
|
12
|
+
) : (
|
|
13
|
+
<LoginForm setShowSignup={setShowSignup} />
|
|
14
|
+
)}
|
|
88
15
|
</div>
|
|
89
16
|
);
|
|
90
17
|
}
|