Skip to content
This repository was archived by the owner on Aug 31, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/router.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ module.exports = [
name: 'profile',
component: './Profile',
},
{
path: '/result',
name: 'result',
component: './Result',
},
{
path: '/expiring-results',
name: 'expiring-results',
component: './ExpiringResults',
},
{
path: '/exception/403',
name: 'exception-403',
Expand Down
21 changes: 15 additions & 6 deletions mock/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ export const mockControllers = new Array(DEFAULT_SIZE).fill().map((value, index)
}));

export const mockResults = hostname =>
new Array(DEFAULT_SIZE).fill().map((value, index) => ({
new Array(DEFAULT_SIZE).fill().map(() => ({
'@metadata.controller_dir': hostname,
config: casual.word,
controller: hostname,
end: moment.utc(),
// Since dataset id is a long hex string, removed "-" characters here to make it look like real data
id: casual.uuid.replace(/-/g, ''),
result: `${index}${hostname.slice(0, -6)}${index}`,
start: moment.utc(),
id: createUniqueKey(),
result: `${casual.word}.${casual.word}.${casual.word}`,
start: moment.utc().subtract(Math.random() * 10 + 10, 'days'),
serverMetadata: {
dashboard: {
saved: false,
seen: false,
},
'dataset.access': 'public',
'dataset.owner': '[email protected]',
'server.deletion': moment.utc().add('days', Math.random() * 10 + 10),
},
}));

export const mockSamples = {
Expand Down Expand Up @@ -330,7 +338,8 @@ export default {
'POST /api/v1/controllers/list': mockControllers,
'POST /api/v1/datasets/list': (req, res) => {
const data = {};
data[req.body.controller] = mockResults(req.body.controller);
const controller = req.body.controller || 'mock-controller';
data[controller] = mockResults(controller);
res.send(data);
},
'POST /api/v1/datasets/detail': (req, res) => {
Expand Down
15 changes: 15 additions & 0 deletions src/common/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ export const menuData = [
},
],
},
{
name: 'Overview',
icon: 'overview',
path: '/overview',
routes: [
{
name: 'Expiring Results',
path: '/expiring-results',
},
{
name: 'result',
path: '/result',
},
],
},
{
name: 'Search',
path: '/search',
Expand Down
2 changes: 1 addition & 1 deletion src/components/AuthLayout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class AuthLayout extends Component {
<Button
variant="link"
className={styles.continueBtn}
onClick={() => this.navigate('controllers')}
onClick={() => this.navigate('')}
>
here
</Button>
Expand Down
126 changes: 126 additions & 0 deletions src/components/LoginForm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React, { useState, useEffect } from 'react';
import {
Form,
FormGroup,
TextInput,
Checkbox,
ActionGroup,
Button,
Title,
} from '@patternfly/react-core';
import { connect } from 'dva';
import styles from './index.less';
import { validateEmail } from '@/utils/validator';

const mapStateToProps = state => {
const { auth } = state;
return { auth };
};

const LoginForm = props => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState({
email: '',
});
const [btnDisabled, setBtnDisabled] = useState(true);

const handleUsernameChange = val => {
setUsername(val);
const validEmail = validateEmail(val);
setErrors({
...errors,
...validEmail,
});
};

const handleLoginSubmit = () => {
const { dispatch } = props;
dispatch({
type: 'auth/loginUser',
payload: {
username,
password,
},
});
};

/* eslint-disable no-restricted-syntax */
const validateForm = () => {
if (username.trim() === '' || password.trim() === '') {
return false;
}
for (const dep of Object.entries(errors)) {
if (dep[1].length > 0) {
return false;
}
}
// if we reach here, it means
// we have covered all of the edge cases.
return true;
};

useEffect(
() => {
if (validateForm()) {
setBtnDisabled(false);
} else setBtnDisabled(true);
},
[username, password]
);

const form = (
<div className={styles.section}>
<Form className={styles.section}>
<FormGroup label="Email address" isRequired fieldId="horizontal-form-name">
<TextInput
isRequired
type="text"
id="horizontal-form-name"
aria-describedby="horizontal-form-name-helper"
name="horizontal-form-name"
onChange={handleUsernameChange}
/>
<p className={styles.error}>{errors.email}</p>
</FormGroup>
<FormGroup label="Password" isRequired fieldId="horizontal-form-password">
<TextInput
isRequired
type="password"
id="horizontal-form-password"
name="horizontal-form-password"
onChange={val => setPassword(val)}
/>
</FormGroup>
<FormGroup fieldId="remember-me">
<Checkbox
label="Keep me logged in"
id="alt-form-checkbox-1"
name="alt-form-checkbox-1"
className={styles.check}
/>
</FormGroup>
<ActionGroup>
<Button
isBlock
onClick={handleLoginSubmit}
className={styles.btn}
id="submitBtn"
isDisabled={btnDisabled}
>
<Title
headingLevel="h4"
size="xl"
style={btnDisabled ? { color: 'black' } : { color: 'white' }}
>
Submit
</Title>
</Button>
</ActionGroup>
</Form>
</div>
);
return <React.Fragment>{form}</React.Fragment>;
};

export default connect(mapStateToProps)(LoginForm);
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
.section {
padding: 5% 10% 5% 10% !important;
padding: 5% 10% 5% 10%;
}

.btn {
padding: 10px;
color: white;
}

.inlineLink {
font-size: var(--pf-global--FontSize--xl);
}

.pf-c-form__group .pf-c-form__label {
font-size: 50px !important;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/LoginHint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import styles from './index.less';
store,
auth: auth.auth,
}))
class Overview extends Component {
class LoginHint extends Component {
navigateToAuth = () => {
const { dispatch } = this.props;
dispatch(routerRedux.push(`/auth`));
Expand Down Expand Up @@ -49,4 +49,4 @@ class Overview extends Component {
}
}

export default Overview;
export default LoginHint;
94 changes: 94 additions & 0 deletions src/components/LoginModal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import {
Modal,
ModalVariant,
Button,
TextContent,
Text,
TextVariants,
} from '@patternfly/react-core';
import { routerRedux } from 'dva/router';
import { connect } from 'dva';
import LoginForm from '@/components/LoginForm';

@connect(auth => ({
auth: auth.auth,
}))
class LoginModal extends React.Component {
constructor(props) {
super(props);
this.state = {
isModalOpen: false,
modalView: false,
};
}

componentDidMount() {
this.handleModalToggle();
}

handleModalToggle = () => {
this.setState(({ isModalOpen }) => ({
isModalOpen: !isModalOpen,
}));
};

handleModalCancel = () => {
const { dispatch } = this.props;
this.setState(({ isModalOpen }) => ({
isModalOpen: !isModalOpen,
}));
dispatch(routerRedux.push(`/`));
};

handleLoginModal = () => {
this.setState({
modalView: true,
});
};

handleSignupModal = () => {
const { dispatch } = this.props;
this.setState(({ isModalOpen }) => ({
isModalOpen: !isModalOpen,
}));
dispatch(routerRedux.push(`/signup`));
};

render() {
const { isModalOpen, modalView } = this.state;
const loginAction = (
<div>
<TextContent>
<Text component={TextVariants.h4}>
This action requires login. Please login to Pbench Dashboard to continue.
</Text>
</TextContent>
<Button key="confirm" variant="primary" onClick={this.handleLoginModal}>
Login
</Button>
<Button key="confirm" variant="link" onClick={this.handleSignupModal}>
Signup
</Button>
<Button key="cancel" variant="link" onClick={this.handleModalCancel}>
Cancel
</Button>
</div>
);
const modalContent = !modalView ? loginAction : <LoginForm />;
return (
<React.Fragment>
<Modal
variant={ModalVariant.small}
isOpen={isModalOpen}
onClose={this.handleModalCancel}
showClose="false"
>
{modalContent}
</Modal>
</React.Fragment>
);
}
}

export default LoginModal;
Loading