Merge branch 'migration' into 'master'

Migrate APPM Store UI from antd v3 to v4

Closes product-iots#579

See merge request entgra/carbon-device-mgt!585
revert-70ac1926
Dharmakeerthi Lasantha 4 years ago
commit 21010b7996

@ -11,7 +11,7 @@
"license": "Apache License 2.0", "license": "Apache License 2.0",
"dependencies": { "dependencies": {
"acorn": "^6.2.0", "acorn": "^6.2.0",
"antd": "^3.23.6", "antd": "^4.0.0",
"axios": "^0.18.1", "axios": "^0.18.1",
"babel-eslint": "^9.0.0", "babel-eslint": "^9.0.0",
"d3": "^5.9.7", "d3": "^5.9.7",

@ -17,7 +17,8 @@
*/ */
import React from 'react'; import React from 'react';
import { Menu, Icon } from 'antd'; import { LogoutOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
import axios from 'axios'; import axios from 'axios';
import { withConfigContext } from '../../../../components/context/ConfigContext'; import { withConfigContext } from '../../../../components/context/ConfigContext';
import { handleApiError } from '../../../../services/utils/errorHandler'; import { handleApiError } from '../../../../services/utils/errorHandler';
@ -64,7 +65,7 @@ class Logout extends React.Component {
return ( return (
<Menu> <Menu>
<Menu.Item key="1" onClick={this.handleSubmit}> <Menu.Item key="1" onClick={this.handleSubmit}>
<Icon type="logout" /> <LogoutOutlined />
Logout Logout
</Menu.Item> </Menu.Item>
</Menu> </Menu>

@ -17,7 +17,17 @@
*/ */
import React from 'react'; import React from 'react';
import { Layout, Menu, Icon, Drawer, Button, Alert } from 'antd'; import {
UploadOutlined,
UserOutlined,
AndroidFilled,
AppleFilled,
WindowsFilled,
HddFilled,
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons';
import { Layout, Menu, Drawer, Button, Alert } from 'antd';
const { Header, Content, Footer } = Layout; const { Header, Content, Footer } = Layout;
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -112,23 +122,27 @@ class Dashboard extends React.Component {
}; };
render() { render() {
const config = this.props.context;
const { selectedKeys, deviceTypes, forbiddenErrors } = this.state; const { selectedKeys, deviceTypes, forbiddenErrors } = this.state;
const DeviceTypesData = deviceTypes.map(deviceType => { const DeviceTypesData = deviceTypes.map(deviceType => {
const platform = deviceType.name; let icon;
const defaultPlatformIcons = config.defaultPlatformIcons; switch (deviceType.name) {
let icon = defaultPlatformIcons.default.icon; case 'android':
let theme = defaultPlatformIcons.default.theme; icon = <AndroidFilled />;
if (defaultPlatformIcons.hasOwnProperty(platform)) { break;
icon = defaultPlatformIcons[platform].icon; case 'ios':
theme = defaultPlatformIcons[platform].theme; icon = <AppleFilled />;
break;
case 'windows':
icon = <WindowsFilled />;
break;
default:
icon = <HddFilled />;
} }
return ( return (
<Menu.Item key={platform}> <Menu.Item key={deviceType.name}>
<Link to={'/store/' + platform}> <Link to={'/store/' + deviceType.name}>
<Icon type={icon} theme={theme} /> {icon}
{platform} {deviceType.name}
</Link> </Link>
</Menu.Item> </Menu.Item>
); );
@ -161,7 +175,7 @@ class Dashboard extends React.Component {
<Menu.Item key="web-clip"> <Menu.Item key="web-clip">
<Link to="/store/web-clip"> <Link to="/store/web-clip">
<Icon type="upload" /> <UploadOutlined />
Web Clips Web Clips
</Link> </Link>
</Menu.Item> </Menu.Item>
@ -170,7 +184,7 @@ class Dashboard extends React.Component {
className="profile" className="profile"
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="user" /> <UserOutlined />
{this.config.user.username} {this.config.user.username}
</span> </span>
} }
@ -185,10 +199,11 @@ class Dashboard extends React.Component {
<Layout className="mobile-layout"> <Layout className="mobile-layout">
<div className="mobile-menu-button"> <div className="mobile-menu-button">
<Button type="link" onClick={this.showMobileNavigationBar}> <Button type="link" onClick={this.showMobileNavigationBar}>
<Icon {this.state.collapsed ? (
type={this.state.collapsed ? 'menu-fold' : 'menu-unfold'} <MenuFoldOutlined />
className="bar-icon" ) : (
/> <MenuUnfoldOutlined />
)}
</Button> </Button>
</div> </div>
</Layout> </Layout>
@ -221,7 +236,7 @@ class Dashboard extends React.Component {
<Menu.Item key="web-clip"> <Menu.Item key="web-clip">
<Link to="/store/web-clip"> <Link to="/store/web-clip">
<Icon type="upload" /> <UploadOutlined />
Web Clips Web Clips
</Link> </Link>
</Menu.Item> </Menu.Item>
@ -236,7 +251,7 @@ class Dashboard extends React.Component {
<SubMenu <SubMenu
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="user" /> <UserOutlined />
</span> </span>
} }
> >

@ -143,11 +143,13 @@ class AppList extends React.Component {
> >
<Row gutter={16}> <Row gutter={16}>
{apps.length === 0 && ( {apps.length === 0 && (
<Result <Col span={24}>
status="404" <Result
title="No apps, yet." status="404"
subTitle="No apps available, yet! When the administration uploads, apps will show up here." title="No apps, yet."
/> subTitle="No apps available, yet! When the administration uploads, apps will show up here."
/>
</Col>
)} )}
{apps.map(app => ( {apps.map(app => (
<Col key={app.id} xs={12} sm={6} md={6} lg={4} xl={3}> <Col key={app.id} xs={12} sm={6} md={6} lg={4} xl={3}>

@ -17,10 +17,10 @@
*/ */
import React from 'react'; import React from 'react';
import { StarOutlined } from '@ant-design/icons';
import { import {
Drawer, Drawer,
Button, Button,
Icon,
Row, Row,
Col, Col,
Typography, Typography,
@ -127,7 +127,7 @@ class AddReview extends React.Component {
return ( return (
<div> <div>
<Button type="primary" onClick={this.showDrawer}> <Button type="primary" onClick={this.showDrawer}>
<Icon type="star" /> Add a review <StarOutlined /> Add a review
</Button> </Button>
<Drawer <Drawer

@ -17,7 +17,8 @@
*/ */
import React from 'react'; import React from 'react';
import { Row, Typography, Icon } from 'antd'; import { TeamOutlined } from '@ant-design/icons';
import { Row, Typography } from 'antd';
import StarRatings from 'react-star-ratings'; import StarRatings from 'react-star-ratings';
import './styles.css'; import './styles.css';
import { withConfigContext } from '../../../../../../../../../../../../../../components/context/ConfigContext'; import { withConfigContext } from '../../../../../../../../../../../../../../components/context/ConfigContext';
@ -67,7 +68,7 @@ class Rating extends React.Component {
/> />
<br /> <br />
<Text type="secondary" className="people-count"> <Text type="secondary" className="people-count">
<Icon type="team" /> {totalCount} total <TeamOutlined /> {totalCount} total
</Text> </Text>
</div> </div>
<div className="bar-containers"> <div className="bar-containers">

@ -170,7 +170,7 @@ class Review extends React.Component {
); );
return ( return (
<div> <div style={{ width: '100%' }}>
<List.Item.Meta <List.Item.Meta
avatar={ avatar={
<Avatar <Avatar

@ -18,6 +18,7 @@
import React from 'react'; import React from 'react';
import axios from 'axios'; import axios from 'axios';
import { SyncOutlined } from '@ant-design/icons';
import { Tag, Table, Typography, Button, Alert } from 'antd'; import { Tag, Table, Typography, Button, Alert } from 'antd';
import TimeAgo from 'javascript-time-ago'; import TimeAgo from 'javascript-time-ago';
@ -235,7 +236,7 @@ class SubscriptionDetails extends React.Component {
</Text> </Text>
</div> </div>
<div style={{ textAlign: 'right', paddingBottom: 6 }}> <div style={{ textAlign: 'right', paddingBottom: 6 }}>
<Button icon="sync" onClick={this.fetch}> <Button icon={<SyncOutlined />} onClick={this.fetch}>
Refresh Refresh
</Button> </Button>
</div> </div>

@ -17,6 +17,7 @@
*/ */
import React from 'react'; import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import { import {
Divider, Divider,
Row, Row,
@ -26,7 +27,6 @@ import {
Dropdown, Dropdown,
notification, notification,
Menu, Menu,
Icon,
Tabs, Tabs,
Tag, Tag,
} from 'antd'; } from 'antd';
@ -216,13 +216,13 @@ class ReleaseView extends React.Component {
yes={ yes={
<Dropdown overlay={menu}> <Dropdown overlay={menu}>
<Button type="primary"> <Button type="primary">
Subscribe <Icon type="down" /> Subscribe <DownOutlined />
</Button> </Button>
</Dropdown> </Dropdown>
} }
no={ no={
<Button type="primary" disabled={true}> <Button type="primary" disabled={true}>
Subscribe <Icon type="down" /> Subscribe <DownOutlined />
</Button> </Button>
} }
/> />

@ -18,7 +18,8 @@
import React from 'react'; import React from 'react';
import '../../../../../../../../App.css'; import '../../../../../../../../App.css';
import { Skeleton, Typography, Row, Col, Card, Breadcrumb, Icon } from 'antd'; import { HomeOutlined } from '@ant-design/icons';
import { Skeleton, Typography, Row, Col, Card, Breadcrumb } from 'antd';
import ReleaseView from './components/ReleaseView'; import ReleaseView from './components/ReleaseView';
import axios from 'axios'; import axios from 'axios';
import { withConfigContext } from '../../../../../../../../components/context/ConfigContext'; import { withConfigContext } from '../../../../../../../../components/context/ConfigContext';
@ -110,7 +111,7 @@ class ReleasePage extends React.Component {
<Breadcrumb style={{ paddingBottom: 16 }}> <Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item> <Breadcrumb.Item>
<Link to={'/store/' + deviceType}> <Link to={'/store/' + deviceType}>
<Icon type="home" /> {deviceType + ' apps'}{' '} <HomeOutlined /> {deviceType + ' apps'}{' '}
</Link> </Link>
</Breadcrumb.Item> </Breadcrumb.Item>
<Breadcrumb.Item>{appName}</Breadcrumb.Item> <Breadcrumb.Item>{appName}</Breadcrumb.Item>

@ -17,14 +17,14 @@
*/ */
import React from 'react'; import React from 'react';
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { import {
Typography, Typography,
Row, Row,
Col, Col,
Form,
Icon,
Input, Input,
Button, Button,
Form,
Checkbox, Checkbox,
notification, notification,
} from 'antd'; } from 'antd';
@ -36,6 +36,62 @@ const { Title } = Typography;
const { Text } = Typography; const { Text } = Typography;
class Login extends React.Component { class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false,
};
}
handleSubmit = values => {
this.setState({
loading: true,
inValid: false,
});
const parameters = {
username: values.username,
password: values.password,
platform: 'store',
};
const request = Object.keys(parameters)
.map(key => key + '=' + parameters[key])
.join('&');
axios
.post(window.location.origin + '/store-ui-request-handler/login', request)
.then(res => {
if (res.status === 200) {
let redirectUrl = window.location.origin + '/store';
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has('redirect')) {
redirectUrl = searchParams.get('redirect');
}
window.location = redirectUrl;
} else {
throw new Error();
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
this.setState({
loading: false,
inValid: true,
});
} else {
notification.error({
message: 'There was a problem',
duration: 10,
description: '',
});
this.setState({
loading: false,
inValid: false,
});
}
});
};
render() { render() {
const config = this.props.context; const config = this.props.context;
return ( return (
@ -46,7 +102,13 @@ class Login extends React.Component {
<Col xs={3} sm={3} md={10}></Col> <Col xs={3} sm={3} md={10}></Col>
<Col xs={18} sm={18} md={4}> <Col xs={18} sm={18} md={4}>
<Row style={{ marginBottom: 20 }}> <Row style={{ marginBottom: 20 }}>
<Col style={{ textAlign: 'center' }}> <Col
style={{
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
}}
>
<img <img
style={{ style={{
marginTop: 36, marginTop: 36,
@ -57,7 +119,58 @@ class Login extends React.Component {
</Col> </Col>
</Row> </Row>
<Title level={2}>Login</Title> <Title level={2}>Login</Title>
<WrappedNormalLoginForm /> <Form
initialValues={{ remember: true }}
onFinish={this.handleSubmit}
>
<Form.Item
name="username"
rules={[
{ required: true, message: 'Please input your username!' },
]}
>
<Input
name="username"
style={{ height: 32 }}
prefix={
<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />
}
placeholder="Username"
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{ required: true, message: 'Please input your password!' },
]}
>
<Input.Password
prefix={
<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />
}
placeholder="Password"
/>
</Form.Item>
{this.state.loading && <Text type="secondary">Loading..</Text>}
{this.state.inValid && (
<Text type="danger">Invalid Login Details</Text>
)}
<br />
<a href="">Forgot password</a>
<Form.Item name="remember" valuePropName="checked">
<Checkbox>Remember me</Checkbox>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
block
loading={this.state.loading}
>
Log in
</Button>
</Form.Item>
</Form>
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -69,140 +182,4 @@ class Login extends React.Component {
} }
} }
class NormalLoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false,
};
}
handleSubmit = e => {
const thisForm = this;
const config = this.props.context;
e.preventDefault();
this.props.form.validateFields((err, values) => {
thisForm.setState({
inValid: false,
});
if (!err) {
thisForm.setState({
loading: true,
});
const parameters = {
username: values.username,
password: values.password,
platform: 'store',
};
const request = Object.keys(parameters)
.map(key => key + '=' + parameters[key])
.join('&');
axios
.post(window.location.origin + config.serverConfig.loginUri, request)
.then(res => {
if (res.status === 200) {
let redirectUrl = window.location.origin + '/store';
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has('redirect')) {
redirectUrl = searchParams.get('redirect');
}
window.location = redirectUrl;
}
})
.catch(function(error) {
if (
error.hasOwnProperty('response') &&
error.response.status === 401
) {
thisForm.setState({
loading: false,
inValid: true,
});
} else {
notification.error({
message: 'There was a problem',
duration: 10,
description: '',
});
thisForm.setState({
loading: false,
inValid: false,
});
}
});
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
let errorMsg = '';
if (this.state.inValid) {
errorMsg = <Text type="danger">Invalid Login Details</Text>;
}
let loading = '';
if (this.state.loading) {
loading = <Text type="secondary">Loading..</Text>;
}
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input
name="username"
style={{ height: 32 }}
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input
name="password"
style={{ height: 32 }}
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
{loading}
{errorMsg}
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(<Checkbox>Remember me</Checkbox>)}
<br />
<a className="login-form-forgot" href="">
Forgot password
</a>
<Button
loading={this.state.loading}
block
type="primary"
htmlType="submit"
className="login-form-button"
>
Log in
</Button>
</Form.Item>
</Form>
);
}
}
const WrappedNormalLoginForm = withConfigContext(
Form.create({ name: 'normal_login' })(NormalLoginForm),
);
export default withConfigContext(Login); export default withConfigContext(Login);

Loading…
Cancel
Save