Skip to content

Commit 3c14060

Browse files
liiil825sunnywx
authored andcommitted
feat: App mgmt pages (#552)
1 parent 1e68693 commit 3c14060

File tree

31 files changed

+1941
-345
lines changed

31 files changed

+1941
-345
lines changed

config/i18n.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ const translations = {
33
translation: require('../src/locales/en/translation.json')
44
},
55
zh: {
6-
translation: require('../src/locales/zh/translation.json')
6+
translation: Object.assign(
7+
{},
8+
require('../src/locales/zh/apps.json'),
9+
require('../src/locales/zh/translation.json')
10+
)
711
}
812
};
913

src/components/Base/DocLink/index.jsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Link } from 'react-router-dom';
4+
import { translate } from 'react-i18next';
5+
6+
import links from 'config/doc-link';
7+
8+
@translate()
9+
export default class DocLink extends Component {
10+
static propTypes = {
11+
children: PropTypes.node,
12+
className: PropTypes.string,
13+
isExternal: PropTypes.bool,
14+
name: PropTypes.string,
15+
to: PropTypes.string
16+
};
17+
18+
static defaultProps = {
19+
children: null,
20+
className: '',
21+
isExternal: true,
22+
name: ''
23+
};
24+
25+
render() {
26+
const {
27+
t, to, name, children, className, isExternal
28+
} = this.props;
29+
let text = t(`LINK_${name}`);
30+
const linkTo = to || links[name];
31+
if (text === `LINK_${name}`) {
32+
text = linkTo;
33+
}
34+
if (children) {
35+
text = children;
36+
}
37+
if (!text) {
38+
return null;
39+
}
40+
if (isExternal) {
41+
if (!linkTo) {
42+
throw new Error(
43+
`You should edit a link url in the file of 'config/doc-links'. name:${name}`
44+
);
45+
}
46+
return (
47+
<a
48+
className={className}
49+
href={linkTo}
50+
target="_blank"
51+
rel="noopener noreferrer"
52+
>
53+
{text}
54+
</a>
55+
);
56+
}
57+
58+
return (
59+
<Link className={className} to={linkTo}>
60+
{text}
61+
</Link>
62+
);
63+
}
64+
}

src/components/Base/Upload/index.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class Upload extends Component {
4040

4141
state = {
4242
uid: getUid(),
43-
isDraging: true
43+
isDraging: false
4444
};
4545

4646
componentDidMount() {
@@ -170,11 +170,14 @@ export default class Upload extends Component {
170170
return (
171171
<span
172172
{...events}
173-
className={classNames('upload', {
174-
'upload-dragover': this.state.isDraging,
175-
'upload-disabled': disabled,
173+
className={classNames(
174+
'upload',
175+
{
176+
'upload-dragover': this.state.isDraging,
177+
'upload-disabled': disabled
178+
},
176179
className
177-
})}
180+
)}
178181
role="button"
179182
style={style}
180183
>

src/components/Base/Upload/index.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,9 @@
88
cursor: not-allowed;
99
pointer-events: none;
1010
}
11+
&.upload-dragover {
12+
opacity: 0.3;
13+
box-shadow: 0 1px 4px 0 rgba(73, 33, 173, 0.06), 0 4px 8px 0 rgba(35, 35, 36, 0.04);
14+
}
1115
}
1216
}

src/components/Base/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export Timeline from './Timeline';
1616
export Tooltip from './Tooltip';
1717
export Image from './Image';
1818
export Upload from './Upload';
19+
export DocLink from './DocLink';
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import classnames from 'classnames';
4+
import { withRouter } from 'react-router-dom';
5+
import { observer } from 'mobx-react';
6+
import { translate } from 'react-i18next';
7+
import _ from 'lodash';
8+
import Loading from 'components/Loading';
9+
10+
import { DocLink, Icon } from 'components/Base';
11+
12+
import styles from './index.scss';
13+
14+
@translate()
15+
@observer
16+
class LayoutStepper extends Component {
17+
static propTypes = {
18+
children: PropTypes.node,
19+
className: PropTypes.string,
20+
name: PropTypes.string,
21+
stepOption: PropTypes.shape({
22+
activeStep: PropTypes.number,
23+
steps: PropTypes.number,
24+
prevStep: PropTypes.func,
25+
disableNextStep: PropTypes.bool,
26+
isLoading: PropTypes.bool,
27+
nextStep: PropTypes.func
28+
})
29+
};
30+
31+
renderTopProgress() {
32+
const { stepOption } = this.props;
33+
const { steps, activeStep } = stepOption;
34+
const width = `${activeStep * 100 / steps}%`;
35+
const className = activeStep > steps ? 'headerStepNotFinished' : 'headerStepNotFinished';
36+
37+
const style = {
38+
width
39+
};
40+
41+
return (
42+
<div
43+
style={style}
44+
className={classnames(styles.headerStep, styles[className])}
45+
/>
46+
);
47+
}
48+
49+
renderTopNav() {
50+
const {
51+
name, stepOption, t, history
52+
} = this.props;
53+
const {
54+
activeStep, steps, prevStep, goBack
55+
} = stepOption;
56+
const funcBack = _.isFunction(goBack) ? goBack : history.goBack;
57+
58+
if (activeStep > steps) {
59+
return null;
60+
}
61+
62+
let text = '';
63+
if (activeStep > 1 && !!name) {
64+
text = t(`STEPPER_HEADER_${name.toUpperCase()}_${activeStep}`);
65+
}
66+
67+
return (
68+
<div className={styles.operate}>
69+
{activeStep > 1 && (
70+
<label onClick={prevStep}>
71+
←&nbsp;{t('Back')}&nbsp;
72+
<span className={styles.operateText}>{text}</span>
73+
</label>
74+
)}
75+
<label className="pull-right" onClick={funcBack}>
76+
{t('Esc')}&nbsp;
77+
<Icon name="close" size={20} type="dark" />
78+
</label>
79+
</div>
80+
);
81+
}
82+
83+
renderTitle() {
84+
const { name, stepOption, t } = this.props;
85+
const { activeStep, steps } = stepOption;
86+
87+
if (activeStep > steps) {
88+
return null;
89+
}
90+
91+
const nameKey = name.toUpperCase();
92+
const header = t(`STEPPER_NAME_${nameKey}_HEADER`, {
93+
activeStep,
94+
steps
95+
});
96+
const title = t(`STEPPER_TITLE_${nameKey}_${activeStep}`);
97+
return (
98+
<div className={classnames(styles.stepContent)}>
99+
<div className={styles.stepName}>{header}</div>
100+
<div className={styles.stepExplain}>{title}</div>
101+
</div>
102+
);
103+
}
104+
105+
renderFooter() {
106+
const {
107+
t, stepOption, name, disableNextStep
108+
} = this.props;
109+
const { activeStep, steps, nextStep } = stepOption;
110+
111+
if (activeStep > steps) {
112+
return null;
113+
}
114+
115+
const keyName = `STEPPER_FOOTER_${name.toLocaleUpperCase()}_${activeStep}`;
116+
const tipText = t(keyName);
117+
const tipLink = <DocLink name={keyName} />;
118+
119+
const buttonText = t('Go on');
120+
121+
return (
122+
<div className={styles.footer}>
123+
<span className={styles.footerTips}>
124+
<span className={styles.footerTipsButton}>{t('Tips')}</span>
125+
{tipText}
126+
{tipLink}
127+
</span>
128+
<button
129+
className={classnames(styles.button, {
130+
[styles.buttonActived]: !disableNextStep
131+
})}
132+
type="primary"
133+
onClick={nextStep}
134+
>
135+
{/*
136+
{activeStep === steps && <Icon className={styles.icon} name="checked-icon" size={20} />}
137+
*/}
138+
<span>{buttonText}</span>
139+
<Icon className={styles.icon} name="next-icon" size={20} />
140+
{/*
141+
{activeStep !== steps && <Icon className={styles.icon} name="next-icon" size={20} />}
142+
*/}
143+
</button>
144+
</div>
145+
);
146+
}
147+
148+
render() {
149+
const { className, children, stepOption } = this.props;
150+
return (
151+
<div className={classnames(styles.layout)}>
152+
{this.renderTopProgress()}
153+
{this.renderTopNav()}
154+
{this.renderTitle()}
155+
<Loading isLoading={stepOption.isLoading}>
156+
<div className={className}>{children}</div>
157+
</Loading>
158+
{this.renderFooter()}
159+
</div>
160+
);
161+
}
162+
}
163+
164+
export default withRouter(LayoutStepper);

0 commit comments

Comments
 (0)