Skip to content

Commit

Permalink
feat: init task log
Browse files Browse the repository at this point in the history
feat: add log read

mod: change key

mod: code review
  • Loading branch information
hetao92 committed Mar 14, 2022
1 parent c52a497 commit 743a693
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 31 deletions.
1 change: 1 addition & 0 deletions app/app.less
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
border: none;
white-space: nowrap;
color: @darkBlue;

&.ant-radio-button-wrapper-checked {
color: #fff;
}
Expand Down
3 changes: 2 additions & 1 deletion app/config/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,10 @@
"createTask": "New Import",
"uploadTemp": "Import Template",
"downloadConfig": "Download Config",
"downloadLog": "Download Log",
"viewLogs": "View Logs",
"details": "Details",
"lines": "Lines",
"task": "import task",
"taskList": "Task List",
"taskName": "Task Name",
"vertices": "Map Vertices",
Expand Down
3 changes: 2 additions & 1 deletion app/config/locale/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,10 @@
"createTask": "创建导入任务",
"uploadTemp": "导入模板",
"downloadConfig": "下载配置文件",
"downloadLog": "下载日志",
"viewLogs": "查看日志",
"details": "详情",
"lines": "",
"task": "导入任务",
"taskList": "任务列表",
"taskName": "任务名称",
"vertices": "关联点",
Expand Down
14 changes: 14 additions & 0 deletions app/config/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const importData = post('/api-nebula/task/import');
const handleImportAction = post('/api-nebula/task/import/action');

const getLog = get('/api/import/log');
const getErrLog = get('/api/import/err_log');
const finishImport = post('/api/import/finish');

const getImportWokingDir = get('/api/import/working_dir');
Expand All @@ -31,6 +32,15 @@ const uploadFiles = (params?, config?) =>
'Content-Type': 'multipart/form-data',
},
});


const getTaskLogs = (params?, config?) => {
const { id, ...others } = params;
return get(`/api/import/task_log_paths/${id}`)(others, config);
};

const getTaskConfigUrl = (id: number) => `/api-nebula/task/import/config/${id}`;
const getTaskLogUrl = (path: string) => `/api-nebula/task/import/log?pathName=${encodeURI(path)}`;
export default {
execNGQL,
batchExecNGQL,
Expand All @@ -40,10 +50,14 @@ export default {
finishImport,
handleImportAction,
getLog,
getErrLog,
getImportWokingDir,
getUploadDir,
getTaskDir,
deteleFile,
getFiles,
uploadFiles,
getTaskConfigUrl,
getTaskLogs,
getTaskLogUrl
};
9 changes: 6 additions & 3 deletions app/interfaces/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ export enum ITaskStatus {
}

export interface ITaskStats {
totalLine: number;
totalCount: number;
totalBatches: number;
totalBytes: number;
totalImportedBytes: number;
totalLatency: number;
totalReqTime: number;
numFailed: number;
numReadFailed: number;
}
Expand All @@ -23,7 +26,7 @@ export interface ITaskItem {
user: string;
taskStatus: ITaskStatus;
taskMessage: string;
statsQuery: ITaskStats;
stats: ITaskStats;
}

export interface IVerticesConfig {
Expand Down
2 changes: 0 additions & 2 deletions app/pages/Console/OutputBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,7 @@ const OutputBox = (props: IProps) => {
const link = document.createElement('a');
link.href = url;
link.download = `result.csv`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};

const handleExplore = () => {
Expand Down
2 changes: 1 addition & 1 deletion app/pages/Console/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, Select, Tooltip, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import intl from 'react-intl-universal';
import { observer } from 'mobx-react-lite';
import { trackPageView, trackEvent } from '@app/utils/stat';
import { trackEvent, trackPageView } from '@app/utils/stat';
import { useStore } from '@app/stores';
import Instruction from '@app/components/Instruction';
import Icon from '@app/components/Icon';
Expand Down
4 changes: 2 additions & 2 deletions app/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ interface IProps {
const VerticesConfig = (props: IProps) => {
const { tag, tagIndex, configIndex, file } = props;
const { dataImport, schema } = useStore();
const { asyncUpdateTagConfig, updateTagPropMapping } = dataImport;
const { updateTagConfig, updateTagPropMapping } = dataImport;
const { tags } = schema;

const handleTagChange = (configIndex: number, tagIndex: number, value: string) => {
asyncUpdateTagConfig({ configIndex, tagIndex, tag: value });
updateTagConfig({ configIndex, tagIndex, tag: value });
};

const handlePropChange = (index, field, value) => {
Expand Down
4 changes: 2 additions & 2 deletions app/pages/Import/TaskCreate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const formItemLayout = {
};
const TaskCreate = () => {
const { dataImport, schema, global } = useStore();
const { taskDir, asyncGetTaskDir, basicConfig, verticesConfig, edgesConfig, updateBasicConfig, importTask } = dataImport;
const { taskDir, getTaskDir, basicConfig, verticesConfig, edgesConfig, updateBasicConfig, importTask } = dataImport;
const { spaces, spaceVidType, getSpaces, updateSpaceInfo, currentSpace } = schema;
const { host, username } = global;
const { batchSize } = basicConfig;
Expand Down Expand Up @@ -125,7 +125,7 @@ const TaskCreate = () => {
};

useEffect(() => {
asyncGetTaskDir();
getTaskDir();
getSpaces();
if(currentSpace) {
updateSpaceInfo(currentSpace);
Expand Down
62 changes: 62 additions & 0 deletions app/pages/Import/TaskList/TaskItem/LogModal/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@import '~@app/common.less';
.log-modal {
height: 100vh;
.ant-modal {
height: 80%;
.ant-modal-content {
height: 100%;
}
}
.import-modal-title {
display: flex;
align-items: center;
}
.ant-modal-header {
border-bottom: none;
padding-right: 80px;
padding-top: 15px;
.ant-modal-title {
display: flex;
align-items: center;
justify-content: space-between;
}
.ant-modal-close {
top: 5px;
}
}
.ant-modal-body {
display: flex;
height: 91%;
}
.log-container {
width: 100%;
height: 100%;
overflow: auto;
padding: 10px 20px 120px;
font-size: 18px;
text-align: left;
background: #333;
color: #fff;
word-break: break-all;
}
}
.log-tab {
max-height: 65vh;
.ant-tabs-nav {
width: 200px;
.ant-tabs-tab {
background-color: @lightGray;
color: @darkBlue;
}
.ant-tabs-tab-active {
background-color: #0091FF;
color: #fff;
.ant-tabs-tab-btn {
color: #fff;
}
}
}
.ant-tabs-content-holder > .ant-tabs-content {
display: none
}
}
131 changes: 131 additions & 0 deletions app/pages/Import/TaskList/TaskItem/LogModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { Button, Modal, Tabs } from 'antd';
import _ from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import intl from 'react-intl-universal';
import Icon from '@app/components/Icon';
import './index.less';
import { useStore } from '@app/stores';
import { ITaskStatus } from '@app/interfaces/import';

const { TabPane } = Tabs;

interface ILogDimension {
space: string;
id: number;
status: ITaskStatus;
}

interface ILog {
name: string;
path: string;
}
interface IProps {
logDimension: ILogDimension;
visible: boolean;
onCancel: () => void;
}
const LogModal = (props: IProps) => {
const { visible, onCancel, logDimension: { space, id, status } } = props;
const { dataImport: { getLogs, downloadTaskLog, getImportLogDetail, getErrLogDetail } } = useStore();
const logRef = useRef<HTMLDivElement>(null);
const timer = useRef<any>(null);
const offset = useRef(0);
const _status = useRef(status);
const [logs, setLogs] = useState<ILog[]>([]);
const [currentLog, setCurrentLog] = useState<ILog | null>(null);
const handleTabChange = (key: string) => {
setCurrentLog(logs.filter(item => item.name === key)[0]);
};

const getAllLogs = async() => {
const { code, data } = await getLogs(id);
if(code === 0) {
setLogs(data);
setCurrentLog(data[0]);
}
};

const handleLogDownload = () => {
if(currentLog) {
downloadTaskLog(currentLog.path);
}
};

const readLog = async() => {
const getLogDetail = currentLog!.name === 'import.log' ? getImportLogDetail : getErrLogDetail;
const res = await getLogDetail({
offset: offset.current,
taskId: id,
path: currentLog!.path
});
handleLogData(res);
};

const handleLogData = (res) => {
const { data } = res;
if(!logRef.current) {
timer.current = setTimeout(readLog, 2000);
return;
}
if (data) {
logRef.current.innerHTML += data.join('<br/>') + '<br/>';
logRef.current.scrollTop = logRef.current.scrollHeight;
offset.current += data.length;
timer.current = setTimeout(readLog, 2000);
} else if (_status.current === ITaskStatus.StatusProcessing) {
timer.current = setTimeout(readLog, 2000);
} else {
offset.current = 0;
}
};

useEffect(() => {
getAllLogs();
return () => {
clearTimeout(timer.current);
};
}, []);

useEffect(() => {
_status.current = status;
}, [status]);
useEffect(() => {
clearTimeout(timer.current);
if(logRef.current) {
logRef.current.innerHTML = '';
}
offset.current = 0;
if(currentLog) {
readLog();
}
}, [currentLog]);
return (
<Modal
title={<>
<div className="import-modal-title">
<span>{`${space} ${intl.get('import.task')} - ${intl.get('common.log')}`}</span>
{status === ITaskStatus.StatusProcessing && <Button type="text" loading={true} />}
</div>
<Button className="studio-add-btn primary-btn" onClick={handleLogDownload}>
<Icon type="icon-studio-btn-download" />
{intl.get('import.downloadLog')}
</Button>
</>}
width="80%"
visible={visible}
onCancel={onCancel}
wrapClassName="log-modal"
destroyOnClose={true}
footer={false}
>
<Tabs className="log-tab" tabBarGutter={0} tabPosition="left" onChange={handleTabChange}>
{logs.map(log => (
<TabPane tab={`${log.name}`} key={log.name} />
))}
</Tabs>
<div className="log-container" ref={logRef}/>
</Modal>
);
};

export default LogModal;
15 changes: 9 additions & 6 deletions app/pages/Import/TaskList/TaskItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import './index.less';
import { ITaskItem, ITaskStatus } from '@app/interfaces/import';
import dayjs from 'dayjs';
import { floor } from 'lodash';
import { getFileSize } from '@app/utils/file';
import Icon from '@app/components/Icon';
interface IProps {
data: ITaskItem;
handleStop: (id: number) => void;
handleDelete: (id: number) => void;
handleDownload: (id: number) => void;
onViewLog: (id: number, space: string, taskStatus: ITaskStatus) => void;
}


Expand Down Expand Up @@ -39,12 +41,13 @@ const TaskItem = (props: IProps) => {
space,
taskID,
name,
statsQuery: { totalCount, totalLine, numFailed, numReadFailed },
stats: { totalImportedBytes, totalBytes, numFailed, numReadFailed },
taskStatus,
taskMessage,
updatedTime,
createdTime
},
onViewLog,
handleDownload,
handleStop,
handleDelete } = props;
Expand Down Expand Up @@ -99,20 +102,20 @@ const TaskItem = (props: IProps) => {
</span>
<div className="more-info">
<span>
{taskStatus !== ITaskStatus.StatusFinished && `${totalCount} ${intl.get('import.lines')} / `}
{totalLine}{' '}{intl.get('import.lines')}
{taskStatus !== ITaskStatus.StatusFinished && `${getFileSize(totalImportedBytes)} / `}
{getFileSize(totalBytes)}{' '}
</span>
<span>{dayjs.duration(dayjs.unix(updatedTime).diff(dayjs.unix(createdTime))).format('HH:mm:ss')}</span>
</div>
</div>
<Progress
status={status}
percent={taskStatus !== ITaskStatus.StatusFinished ? floor(totalCount / totalLine * 100, 2) : 100}
percent={taskStatus !== ITaskStatus.StatusFinished ? floor(totalImportedBytes / totalBytes * 100, 2) : 100}
strokeColor={status && COLOR_MAP[status]} />
</div>
<div className="operations">
<Button className="primary-btn">{intl.get('import.details')}</Button>
<Button className="primary-btn">{intl.get('import.viewLogs')}</Button>
{/* <Button className="primary-btn">{intl.get('import.details')}</Button> */}
<Button className="primary-btn" onClick={() => onViewLog(taskID, space, taskStatus)}>{intl.get('import.viewLogs')}</Button>
{taskStatus === ITaskStatus.StatusProcessing &&
<Popconfirm
placement="left"
Expand Down
Loading

0 comments on commit 743a693

Please sign in to comment.