提交 52963f85 编写于 作者: J Jason Park 提交者: Jason

Merge data and code parts into one

上级 fea69cee
...@@ -5,11 +5,11 @@ const getPath = (...args) => path.resolve(__dirname, '..', 'algorithm', ...args) ...@@ -5,11 +5,11 @@ const getPath = (...args) => path.resolve(__dirname, '..', 'algorithm', ...args)
const readCategories = () => { const readCategories = () => {
const createKey = name => name.toLowerCase().replace(/ /g, '-'); const createKey = name => name.toLowerCase().replace(/ /g, '-');
const subdirectories = dirPath => fs.readdirSync(dirPath).filter(subdir => !subdir.startsWith('.')); const list = dirPath => fs.readdirSync(dirPath).filter(filename => !filename.startsWith('.'));
const getCategory = categoryName => { const getCategory = categoryName => {
const categoryPath = getPath(categoryName);
const categoryKey = createKey(categoryName); const categoryKey = createKey(categoryName);
const algorithms = subdirectories(categoryPath).map(algorithmName => getAlgorithm(categoryName, algorithmName)); const categoryPath = getPath(categoryName);
const algorithms = list(categoryPath).map(algorithmName => getAlgorithm(categoryName, algorithmName));
return { return {
key: categoryKey, key: categoryKey,
name: categoryName, name: categoryName,
...@@ -17,29 +17,30 @@ const readCategories = () => { ...@@ -17,29 +17,30 @@ const readCategories = () => {
}; };
}; };
const getAlgorithm = (categoryName, algorithmName) => { const getAlgorithm = (categoryName, algorithmName) => {
const algorithmPath = getPath(categoryName, algorithmName);
const algorithmKey = createKey(algorithmName); const algorithmKey = createKey(algorithmName);
const files = subdirectories(algorithmPath).filter(fileName => fileName !== 'desc.json'); const algorithmPath = getPath(categoryName, algorithmName);
const files = list(algorithmPath);
return { return {
key: algorithmKey, key: algorithmKey,
name: algorithmName, name: algorithmName,
files, files,
} }
}; };
return subdirectories(getPath()).map(getCategory); return list(getPath()).map(getCategory);
}; };
const categories = readCategories(); const categories = readCategories();
categories.forEach(category => { categories.forEach(category => {
console.error('===', category.name, '===');
category.algorithms.forEach(algorithm => { category.algorithms.forEach(algorithm => {
algorithm.files.forEach(fileKey => { const fileName = algorithm.files.find(file => file !== 'desc.json');
const fileName = ['basic', 'normal'].includes(fileKey) ? algorithm.name : fileKey.split('_').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' '); const oldFilePath = getPath(category.name, algorithm.name, fileName);
const oldPath = getPath(category.name, algorithm.name, fileKey); const oldCodePath = getPath(category.name, algorithm.name, fileName, 'code.js');
const newPath = getPath(category.name, algorithm.name, fileName); const newCodePath = getPath(category.name, algorithm.name, 'code.js');
//fs.renameSync(oldPath, newPath); //console.log(oldCodePath, ' ==> ', newCodePath);
console.log(oldPath + '->', newPath); //fs.renameSync(oldCodePath, newCodePath);
}) //fs.rmdirSync(oldFilePath);
}) })
}); });
......
...@@ -9,7 +9,7 @@ const getPath = (...args) => path.resolve(__dirname, '..', '..', '..', 'algorith ...@@ -9,7 +9,7 @@ const getPath = (...args) => path.resolve(__dirname, '..', '..', '..', 'algorith
const readCategories = () => { const readCategories = () => {
const createKey = name => name.toLowerCase().replace(/ /g, '-'); const createKey = name => name.toLowerCase().replace(/ /g, '-');
const list = dirPath => fs.readdirSync(dirPath).filter(filename => !/\./.test(filename)); // visible directories only const list = dirPath => fs.readdirSync(dirPath).filter(filename => !filename.startsWith('.'));
const getCategory = categoryName => { const getCategory = categoryName => {
const categoryKey = createKey(categoryName); const categoryKey = createKey(categoryName);
const categoryPath = getPath(categoryName); const categoryPath = getPath(categoryName);
...@@ -23,20 +23,13 @@ const readCategories = () => { ...@@ -23,20 +23,13 @@ const readCategories = () => {
const getAlgorithm = (categoryName, algorithmName) => { const getAlgorithm = (categoryName, algorithmName) => {
const algorithmKey = createKey(algorithmName); const algorithmKey = createKey(algorithmName);
const algorithmPath = getPath(categoryName, algorithmName); const algorithmPath = getPath(categoryName, algorithmName);
const files = list(algorithmPath).map(fileName => getFile(categoryName, algorithmName, fileName)); const files = list(algorithmPath);
return { return {
key: algorithmKey, key: algorithmKey,
name: algorithmName, name: algorithmName,
files, files,
} }
}; };
const getFile = (categoryName, algorithmName, fileName) => {
const fileKey = createKey(fileName);
return {
key: fileKey,
name: fileName,
};
};
return list(getPath()).map(getCategory); return list(getPath()).map(getCategory);
}; };
...@@ -47,49 +40,22 @@ const getCategories = (req, res, next) => { ...@@ -47,49 +40,22 @@ const getCategories = (req, res, next) => {
}; };
const getFile = (req, res, next) => { const getFile = (req, res, next) => {
const { categoryKey, algorithmKey, fileKey } = req.params; const { categoryKey, algorithmKey, fileName } = req.params;
const category = categories.find(category => category.key === categoryKey);
if (!category) return next(new NotFoundError());
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
if (!algorithm) return next(new NotFoundError());
const file = algorithm.files.find(file => file.key === fileKey);
if (!file) return next(new NotFoundError());
const dataPath = getPath(category.name, algorithm.name, file.name, 'data.js');
const codePath = getPath(category.name, algorithm.name, file.name, 'code.js');
fs.readFile(dataPath, 'utf8', (err, data) => {
if (err) return next(err);
fs.readFile(codePath, 'utf8', (err, code) => {
if (err) return next(err);
res.json({ data, code });
});
});
};
const getDescription = (req, res, next) => {
const { categoryKey, algorithmKey } = req.params;
const category = categories.find(category => category.key === categoryKey); const category = categories.find(category => category.key === categoryKey);
if (!category) return next(new NotFoundError()); if (!category) return next(new NotFoundError());
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey); const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
if (!algorithm) return next(new NotFoundError()); if (!algorithm) return next(new NotFoundError());
if (!algorithm.files.includes(fileName)) return next(new NotFoundError());
const descriptionPath = getPath(category.name, algorithm.name, 'desc.json'); const filePath = getPath(category.name, algorithm.name, fileName);
fs.readFile(descriptionPath, 'utf8', (err, raw) => { res.sendFile(filePath);
if (err) return next(err);
const description = JSON.parse(raw);
res.json({ description });
});
}; };
router.route('/') router.route('/')
.get(getCategories); .get(getCategories);
router.route('/description/:categoryKey/:algorithmKey') router.route('/:categoryKey/:algorithmKey/:fileName')
.get(getDescription);
router.route('/:categoryKey/:algorithmKey/:fileKey')
.get(getFile); .get(getFile);
export default router; export default router;
\ No newline at end of file
...@@ -48,8 +48,7 @@ const PUT = URL => { ...@@ -48,8 +48,7 @@ const PUT = URL => {
const DirectoryApi = { const DirectoryApi = {
getCategories: GET('/directory'), getCategories: GET('/directory'),
getDescription: GET('/directory/description/:categoryKey/:algorithmKey'), getFile: GET('/directory/:categoryKey/:algorithmKey/:fileName'),
getFile: GET('/directory/:categoryKey/:algorithmKey/:fileKey'),
}; };
const WikiApi = { const WikiApi = {
......
...@@ -38,11 +38,10 @@ class App extends React.Component { ...@@ -38,11 +38,10 @@ class App extends React.Component {
DirectoryApi.getCategories() DirectoryApi.getCategories()
.then(({ categories }) => { .then(({ categories }) => {
this.props.setCategories(categories); this.props.setCategories(categories);
const { categoryKey, algorithmKey, fileKey } = this.props.env; const { categoryKey, algorithmKey } = this.props.env;
const category = categories.find(category => category.key === categoryKey) || categories[0]; const category = categories.find(category => category.key === categoryKey) || categories[0];
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey) || category.algorithms[0]; const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey) || category.algorithms[0];
const file = algorithm.files.find(file => file.key === fileKey) || algorithm.files[0]; this.props.history.push(`/${category.key}/${algorithm.key}`);
this.props.history.push(`/${category.key}/${algorithm.key}/${file.key}`);
}); });
tracerManager.setOnError(error => this.props.showErrorToast(error.message)); tracerManager.setOnError(error => this.props.showErrorToast(error.message));
...@@ -58,8 +57,8 @@ class App extends React.Component { ...@@ -58,8 +57,8 @@ class App extends React.Component {
tracerManager.setOnError(null); tracerManager.setOnError(null);
} }
updateDirectory({ categoryKey = null, algorithmKey = null, fileKey = null }) { updateDirectory({ categoryKey = null, algorithmKey = null }) {
this.props.setDirectory(categoryKey, algorithmKey, fileKey); this.props.setDirectory(categoryKey, algorithmKey);
} }
toggleNavigator(navigatorOpened = !this.state.navigatorOpened) { toggleNavigator(navigatorOpened = !this.state.navigatorOpened) {
...@@ -78,9 +77,9 @@ class App extends React.Component { ...@@ -78,9 +77,9 @@ class App extends React.Component {
render() { render() {
const { navigatorOpened, navigatorWidth, viewerSectionWidth } = this.state; const { navigatorOpened, navigatorWidth, viewerSectionWidth } = this.state;
const { categories, categoryKey, algorithmKey, fileKey } = this.props.env; const { categories, categoryKey, algorithmKey } = this.props.env;
return categories && categoryKey && algorithmKey && fileKey && ( return categories && categoryKey && algorithmKey && (
<div className={styles.app}> <div className={styles.app}>
<Header onClickTitleBar={() => this.toggleNavigator()} navigatorOpened={navigatorOpened} /> <Header onClickTitleBar={() => this.toggleNavigator()} navigatorOpened={navigatorOpened} />
<main className={styles.main} ref={ref => this.elMain = ref}> <main className={styles.main} ref={ref => this.elMain = ref}>
......
...@@ -35,8 +35,8 @@ class DescriptionViewer extends React.Component { ...@@ -35,8 +35,8 @@ class DescriptionViewer extends React.Component {
} }
loadDescription(categoryKey, algorithmKey) { loadDescription(categoryKey, algorithmKey) {
DirectoryApi.getDescription(categoryKey, algorithmKey) DirectoryApi.getFile(categoryKey, algorithmKey, 'desc.json')
.then(({ description }) => this.setState({ description })); .then(description => this.setState({ description }));
} }
getChild(value) { getChild(value) {
......
...@@ -5,8 +5,8 @@ import 'brace/mode/javascript'; ...@@ -5,8 +5,8 @@ import 'brace/mode/javascript';
import 'brace/theme/tomorrow_night_eighties'; import 'brace/theme/tomorrow_night_eighties';
import FontAwesomeIcon from '@fortawesome/react-fontawesome' import FontAwesomeIcon from '@fortawesome/react-fontawesome'
import faInfoCircle from '@fortawesome/fontawesome-free-solid/faInfoCircle'; import faInfoCircle from '@fortawesome/fontawesome-free-solid/faInfoCircle';
import { calculatePercentageHeight, classes } from '/common/util'; import { classes } from '/common/util';
import { Divider, Ellipsis, TabBar } from '/components'; import { Ellipsis, TabBar } from '/components';
import { actions as envActions } from '/reducers/env'; import { actions as envActions } from '/reducers/env';
import { tracerManager } from '/core'; import { tracerManager } from '/core';
import { DirectoryApi } from '/apis'; import { DirectoryApi } from '/apis';
...@@ -25,34 +25,29 @@ class EditorSection extends React.Component { ...@@ -25,34 +25,29 @@ class EditorSection extends React.Component {
const { lineIndicator } = tracerManager; const { lineIndicator } = tracerManager;
this.state = { this.state = {
dataContainerHeight: '30%',
lineMarker: this.createLineMarker(lineIndicator), lineMarker: this.createLineMarker(lineIndicator),
data: '',
code: '', code: '',
}; };
} }
componentDidMount() { componentDidMount() {
tracerManager.setDataGetter(() => this.state.data);
tracerManager.setCodeGetter(() => this.state.code); tracerManager.setCodeGetter(() => this.state.code);
tracerManager.setOnUpdateLineIndicator(lineIndicator => this.setState({ lineMarker: this.createLineMarker(lineIndicator) })); tracerManager.setOnUpdateLineIndicator(lineIndicator => this.setState({ lineMarker: this.createLineMarker(lineIndicator) }));
const { categoryKey, algorithmKey, fileKey } = this.props.env; const { categoryKey, algorithmKey } = this.props.env;
this.loadCodeAndData(categoryKey, algorithmKey, fileKey); this.loadCode(categoryKey, algorithmKey);
} }
componentWillUnmount() { componentWillUnmount() {
tracerManager.setDataGetter(null);
tracerManager.setCodeGetter(null); tracerManager.setCodeGetter(null);
tracerManager.setOnUpdateLineIndicator(null); tracerManager.setOnUpdateLineIndicator(null);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { categoryKey, algorithmKey, fileKey } = nextProps.env; const { categoryKey, algorithmKey } = nextProps.env;
if (categoryKey !== this.props.env.categoryKey || if (categoryKey !== this.props.env.categoryKey ||
algorithmKey !== this.props.env.algorithmKey || algorithmKey !== this.props.env.algorithmKey) {
fileKey !== this.props.env.fileKey) { this.loadCode(categoryKey, algorithmKey);
this.loadCodeAndData(categoryKey, algorithmKey, fileKey);
} }
} }
...@@ -71,40 +66,31 @@ class EditorSection extends React.Component { ...@@ -71,40 +66,31 @@ class EditorSection extends React.Component {
}; };
} }
loadCodeAndData(categoryKey, algorithmKey, fileKey) { loadCode(categoryKey, algorithmKey) {
DirectoryApi.getFile(categoryKey, algorithmKey, fileKey) DirectoryApi.getFile(categoryKey, algorithmKey, 'code.js')
.then(({ data, code }) => { .then(code => {
this.setState({ data, code }, () => tracerManager.runData()); this.setState({ code }, () => tracerManager.runInitial());
}); });
} }
handleResizeDataContainer(x, y) {
const dataContainerHeight = calculatePercentageHeight(this.elContent, y);
this.setState({ dataContainerHeight });
}
handleChangeData(data) {
this.setState({ data }, () => tracerManager.runData());
}
handleChangeCode(code) { handleChangeCode(code) {
this.setState({ code }, () => tracerManager.runData()); this.setState({ code }, () => tracerManager.runInitial());
} }
render() { render() {
const { dataContainerHeight, lineMarker, data, code } = this.state; const { lineMarker, code } = this.state;
const { className } = this.props; const { className } = this.props;
const { categories, categoryKey, algorithmKey, fileKey } = this.props.env; const { categories, categoryKey, algorithmKey } = this.props.env;
const category = categories.find(category => category.key === categoryKey); const category = categories.find(category => category.key === categoryKey);
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey); const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
const tabs = algorithm.files.map(file => ({ const tabs = ['code.js'].map(fileName => ({
title: file.name, title: fileName,
props: { props: {
to: `/${category.key}/${algorithm.key}/${file.key}` to: `/${category.key}/${algorithm.key}`
}, },
})); }));
const tabIndex = algorithm.files.findIndex(file => file.key === fileKey); const tabIndex = 0; // TODO
const fileInfo = ''; // TODO const fileInfo = ''; // TODO
return ( return (
...@@ -114,29 +100,16 @@ class EditorSection extends React.Component { ...@@ -114,29 +100,16 @@ class EditorSection extends React.Component {
<FontAwesomeIcon fixedWidth icon={faInfoCircle} className={styles.info_icon} /> <FontAwesomeIcon fixedWidth icon={faInfoCircle} className={styles.info_icon} />
<Ellipsis className={styles.info_text}>{fileInfo}</Ellipsis> <Ellipsis className={styles.info_text}>{fileInfo}</Ellipsis>
</div> </div>
<div className={styles.content} ref={ref => this.elContent = ref}> <div className={styles.content}>
<div className={styles.data_container} style={{ height: dataContainerHeight }}> <AceEditor
<AceEditor className={styles.editor}
className={styles.editor} mode="javascript"
mode="javascript" theme="tomorrow_night_eighties"
theme="tomorrow_night_eighties" name="code_editor"
name="data_editor" editorProps={{ $blockScrolling: true }}
editorProps={{ $blockScrolling: true }} onChange={value => this.handleChangeCode(value)}
onChange={value => this.handleChangeData(value)} markers={lineMarker ? [lineMarker] : []}
value={data} /> value={code} />
</div>
<Divider horizontal onResize={(x, y) => this.handleResizeDataContainer(x, y)} />
<div className={styles.code_container}>
<AceEditor
className={styles.editor}
mode="javascript"
theme="tomorrow_night_eighties"
name="code_editor"
editorProps={{ $blockScrolling: true }}
onChange={value => this.handleChangeCode(value)}
markers={lineMarker ? [lineMarker] : []}
value={code} />
</div>
</div> </div>
</section> </section>
); );
......
...@@ -35,38 +35,25 @@ ...@@ -35,38 +35,25 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.data_container { .editor {
border-bottom: 1px solid $theme-light; width: 100% !important;
} height: 100% !important;
.code_container { .current_line_marker {
flex: 1; background: rgba(#29d, 0.4);
} border: 1px solid #29d;
position: absolute;
.data_container,
.code_container {
min-height: $resizeable-min;
.editor {
width: 100% !important; width: 100% !important;
height: 100% !important;
.current_line_marker { animation: line_highlight .1s;
background: rgba(#29d, 0.4); }
border: 1px solid #29d;
position: absolute;
width: 100% !important;
animation: line_highlight .1s; @keyframes line_highlight {
from {
background: rgba(#29d, 0.1);
} }
to {
@keyframes line_highlight { background: rgba(#29d, 0.4);
from {
background: rgba(#29d, 0.1);
}
to {
background: rgba(#29d, 0.4);
}
} }
} }
} }
......
...@@ -91,10 +91,9 @@ class Navigator extends React.Component { ...@@ -91,10 +91,9 @@ class Navigator extends React.Component {
{ {
algorithms.map(algorithm => { algorithms.map(algorithm => {
const selected = category.key === selectedCategoryKey && algorithm.key === selectedAlgorithmKey; const selected = category.key === selectedCategoryKey && algorithm.key === selectedAlgorithmKey;
const [file] = algorithm.files;
return ( return (
<ListItem indent key={algorithm.key} selected={selected} <ListItem indent key={algorithm.key} selected={selected}
to={`/${category.key}/${algorithm.key}/${file.key}`}> to={`/${category.key}/${algorithm.key}`}>
<Ellipsis>{algorithm.name}</Ellipsis> <Ellipsis>{algorithm.name}</Ellipsis>
</ListItem> </ListItem>
) )
......
...@@ -15,7 +15,7 @@ class TracerManager { ...@@ -15,7 +15,7 @@ class TracerManager {
this.paused = false; this.paused = false;
this.started = false; this.started = false;
this.lineIndicator = null; this.lineIndicator = null;
this.reset(new Seed()); this.reset();
} }
setOnRender(onRender) { setOnRender(onRender) {
...@@ -34,10 +34,6 @@ class TracerManager { ...@@ -34,10 +34,6 @@ class TracerManager {
this.onError = onError; this.onError = onError;
} }
setDataGetter(dataGetter) {
this.dataGetter = dataGetter;
}
setCodeGetter(codeGetter) { setCodeGetter(codeGetter) {
this.codeGetter = codeGetter; this.codeGetter = codeGetter;
} }
...@@ -66,17 +62,12 @@ class TracerManager { ...@@ -66,17 +62,12 @@ class TracerManager {
if (this.onUpdateLineIndicator) this.onUpdateLineIndicator(lineIndicator); if (this.onUpdateLineIndicator) this.onUpdateLineIndicator(lineIndicator);
} }
getData() {
if (this.dataGetter) return this.dataGetter();
return null;
}
getCode() { getCode() {
if (this.codeGetter) return this.codeGetter(); if (this.codeGetter) return this.codeGetter();
return null; return null;
} }
reset(seed) { reset(seed = new Seed()) {
this.traces = seed.traces; this.traces = seed.traces;
this.resetCursor(); this.resetCursor();
this.stopTimer(); this.stopTimer();
...@@ -158,15 +149,13 @@ class TracerManager { ...@@ -158,15 +149,13 @@ class TracerManager {
} }
} }
execute(data, code, callback) { execute(callback) {
try { try {
const dataLines = data.split('\n'); const code = this.getCode();
const codeLines = code.split('\n'); const lines = code.split('\n').map((line, i) => line.replace(/(.+\. *wait *)(\( *\))/g, `$1(${i})`));
const lines = [...dataLines, ...codeLines];
const newLines = lines.map((line, i) => line.replace(/(.+\. *wait *)(\( *\))/g, `$1(${i - dataLines.length})`));
const seed = new Seed(); const seed = new Seed();
Tracer.seed = seed; Tracer.seed = seed;
eval(Babel.transform(newLines.join('\n'), { presets: ['es2015'] }).code); eval(Babel.transform(lines.join('\n'), { presets: ['es2015'] }).code);
this.reset(seed); this.reset(seed);
if (callback) callback(); if (callback) callback();
} catch (error) { } catch (error) {
...@@ -174,16 +163,19 @@ class TracerManager { ...@@ -174,16 +163,19 @@ class TracerManager {
} }
} }
runData() { runInitial() {
const data = this.getData(); const error = this.execute(() => this.applyTraceChunk());
this.execute(data, '', () => this.applyTraceChunk()); if (error) {
this.reset();
this.render();
}
} }
run() { run() {
const data = this.getData(); const error = this.execute(() => this.resume());
const code = this.getCode();
const error = this.execute(data, code, () => this.resume());
if (error) { if (error) {
this.reset();
this.render();
this.handleError(error); this.handleError(error);
} else { } else {
this.setStarted(true); this.setStarted(true);
...@@ -217,7 +209,6 @@ class TracerManager { ...@@ -217,7 +209,6 @@ class TracerManager {
handleError(error) { handleError(error) {
console.error(error); console.error(error);
this.reset(new Seed());
if (this.onError) this.onError(error); if (this.onError) this.onError(error);
} }
} }
......
...@@ -16,7 +16,7 @@ const render = (Component) => { ...@@ -16,7 +16,7 @@ const render = (Component) => {
<Provider store={store}> <Provider store={store}>
<BrowserRouter> <BrowserRouter>
<Switch> <Switch>
<Route exact path="/:categoryKey/:algorithmKey/:fileKey" component={Component} /> <Route exact path="/:categoryKey/:algorithmKey" component={Component} />
<Route path="/" component={Component} /> <Route path="/" component={Component} />
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>
......
...@@ -3,10 +3,9 @@ import { combineActions, createAction, handleActions } from 'redux-actions'; ...@@ -3,10 +3,9 @@ import { combineActions, createAction, handleActions } from 'redux-actions';
const prefix = 'ENV'; const prefix = 'ENV';
const setCategories = createAction(`${prefix}/SET_CATEGORIES`, categories => ({ categories })); const setCategories = createAction(`${prefix}/SET_CATEGORIES`, categories => ({ categories }));
const setDirectory = createAction(`${prefix}/SELECT_FILE`, (categoryKey, algorithmKey, fileKey) => ({ const setDirectory = createAction(`${prefix}/SET_DIRECTORY`, (categoryKey, algorithmKey) => ({
categoryKey, categoryKey,
algorithmKey, algorithmKey,
fileKey,
})); }));
export const actions = { export const actions = {
...@@ -20,7 +19,6 @@ const mutables = { ...@@ -20,7 +19,6 @@ const mutables = {
categories: null, categories: null,
categoryKey: null, categoryKey: null,
algorithmKey: null, algorithmKey: null,
fileKey: null,
}; };
export default handleActions({ export default handleActions({
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册