Skip to content

Commit 4313209

Browse files
authored
Merge pull request #13 from open-mmlab/dev
Copy Project / Import Config from clipboard
2 parents 624f325 + c16d6a9 commit 4313209

File tree

8 files changed

+151
-39
lines changed

8 files changed

+151
-39
lines changed

electron/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ipcListen } from './ipcEvent';
22
const electron = require('electron');
33
const platform = require('os').platform(); // 获取平台:https://nodejs.org/api/os.html#os_os_platform
4-
const version = '0.1.0';
4+
const version = '0.1.1';
55

66
// 控制app生命周期.
77
const app = electron.app;

src/ProjectPlatform/CreateProjectModal/MultiStep/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// cl 2021/9/13 09:53
22
import React, { useEffect, useMemo, useState } from 'react';
33
import { Col, Row, Select, Button, Form, message } from 'antd';
4-
import { isNumber, omit, pick } from 'lodash';
4+
import { isNumber, omit, pick, maxBy } from 'lodash';
55
import { IStepInfo } from '@/store';
66
import { EToolName, TOOL_NAME } from '@/constant/store';
77
import SelectTool, { annotationTypeList, Itool } from '../SelectTool';
@@ -64,9 +64,10 @@ const MultiStep: React.FC<IProps> = ({ stepId, stepList, setStepLIst, changeTask
6464
);
6565
const index = stepList.findIndex((item) => item.id === stepInfo?.id);
6666
const newStepList = [...stepList];
67+
const maxStep = maxBy(stepList, 'step')?.step ?? 0;
6768
if (index === -1) {
6869
newStepList.push({
69-
step: stepList.length + 1,
70+
step: maxStep + 1,
7071
dataSourceStep,
7172
tool: toolName,
7273
id: uuid(),

src/ProjectPlatform/CreateProjectModal/index.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import MultiStep from './MultiStep';
88
import SelectTool from './SelectTool';
99
import TaskStep from '@/ProjectPlatform/CreateProjectModal/TaskStep';
1010
import { IStepInfo, useAnnotation } from '../../store';
11-
import { EToolName } from '@/constant/store';
11+
import { EToolName, TOOL_NAME } from '@/constant/store';
1212
import DefaultConfig from './ToolConfig/DefaultConfig';
1313
import { getCreateProjectCmt } from '@/utils/tool/common';
1414
import { repeatInputList } from '@/utils/tool/editTool';
@@ -171,6 +171,44 @@ const CreateProjectModal: React.FC<IProps> = ({ type, visible, onCancel }) => {
171171
}
172172
}, [form, visible]);
173173

174+
const importFromClipboard = () => {
175+
const promise = navigator.clipboard.readText();
176+
promise.then((res) => {
177+
try {
178+
const clipboardData = JSON.parse(res);
179+
const toolNames = Object.keys(TOOL_NAME);
180+
const newData: any = [];
181+
// 过滤掉质检步骤、暂不支持的工具、依赖过滤掉的工具
182+
const filteredStep: any = [];
183+
clipboardData.forEach((element: any) => {
184+
const { id = uuid(), tool, type, dataSourceStep, step, config } = element;
185+
if (
186+
type === 2 ||
187+
type === 3 ||
188+
!toolNames.includes(tool) ||
189+
filteredStep.includes(dataSourceStep)
190+
) {
191+
filteredStep.push(step);
192+
} else {
193+
newData.push({
194+
id,
195+
tool,
196+
step,
197+
config,
198+
dataSourceStep,
199+
});
200+
}
201+
});
202+
203+
setStepList((pre) => {
204+
return [...pre, ...newData];
205+
});
206+
} catch (error) {
207+
message.error(t('PleaseCopyTheCorrectStepList'));
208+
}
209+
});
210+
};
211+
174212
return (
175213
<div>
176214
<Modal
@@ -219,7 +257,19 @@ const CreateProjectModal: React.FC<IProps> = ({ type, visible, onCancel }) => {
219257
setStepLIst={setStepList}
220258
setStepId={setStepId}
221259
changeTaskVisible={changeTaskVisible}
222-
footer={<Button onClick={changeTaskVisible}>{t('New')}</Button>}
260+
footer={
261+
<>
262+
<Button
263+
onClick={importFromClipboard}
264+
style={{
265+
marginRight: 16,
266+
}}
267+
>
268+
{t('ImportFromClipboard')}
269+
</Button>
270+
<Button onClick={changeTaskVisible}>{t('New')}</Button>
271+
</>
272+
}
223273
/>
224274
<Modal
225275
destroyOnClose={true}

src/ProjectPlatform/ProjectList/index.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
// cl 2021/8/5 19:12
22
import React, { useEffect, useState } from 'react';
33
import { IFileInfo, IProjectInfo, IStepInfo, useAnnotation } from '@/store';
4-
import { message, Popconfirm, Tag, Spin } from 'antd';
4+
import { message, Popconfirm, Tag, Spin, Tooltip } from 'antd';
55
import { EToolName, TOOL_NAME } from '@/constant/store';
66
import {
77
DeleteOutlined,
88
QuestionCircleOutlined,
99
EditOutlined,
1010
FolderOpenOutlined,
1111
DeliveredProcedureOutlined,
12+
CopyOutlined,
1213
} from '@ant-design/icons';
1314
import SelectFolder from '@/ProjectPlatform/CreateProjectModal/SelectFolder';
1415
import ExportData from './ExportData';
1516
import styles from '../index.module.scss';
1617
import { EIpcEvent } from '@/constant/event';
17-
import { formatDate, jsonParser } from '@/utils/tool/common';
18+
import { copyText, formatDate, jsonParser } from '@/utils/tool/common';
1819
import { IProjectType } from '@/ProjectPlatform';
1920
import IconRect from '@/assets/toolIcon/icon_rect.svg';
2021
import IconLine from '@/assets/toolIcon/icon_line.svg';
@@ -254,22 +255,37 @@ const ProjectList: React.FC<IProps> = ({ createProject }) => {
254255
</div>
255256
{hoverIndex === i && (
256257
<div className={styles.deleteButton}>
257-
<DeliveredProcedureOutlined
258-
onClick={(e) => {
259-
e.stopPropagation();
260-
setProjectInfo(info);
261-
}}
262-
className={styles.icon}
263-
style={{ marginRight: 12 }}
264-
/>
265-
<EditOutlined
266-
onClick={(e) => {
267-
e.stopPropagation();
268-
editProject(info);
269-
}}
270-
className={styles.icon}
271-
style={{ marginRight: 12 }}
272-
/>
258+
<Tooltip title={t('CopyProjectConfig')}>
259+
<CopyOutlined
260+
onClick={(e) => {
261+
e.stopPropagation();
262+
copyText(JSON.stringify(info.stepList));
263+
message.success(t('CopyConfigSuccessfully'));
264+
}}
265+
className={styles.icon}
266+
style={{ marginRight: 12 }}
267+
/>
268+
</Tooltip>
269+
<Tooltip title={t('ExportAnnotationResults')}>
270+
<DeliveredProcedureOutlined
271+
onClick={(e) => {
272+
e.stopPropagation();
273+
setProjectInfo(info);
274+
}}
275+
className={styles.icon}
276+
style={{ marginRight: 12 }}
277+
/>
278+
</Tooltip>
279+
<Tooltip title={t('ModifyConfig')}>
280+
<EditOutlined
281+
onClick={(e) => {
282+
e.stopPropagation();
283+
editProject(info);
284+
}}
285+
className={styles.icon}
286+
style={{ marginRight: 12 }}
287+
/>
288+
</Tooltip>
273289
<span
274290
onClick={(e) => {
275291
e.stopPropagation();

src/i18n.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ const resources = {
9090
MultiSelect: 'multi-select',
9191
DefaultOption: 'Default Option',
9292
MessageBeforeExport: 'Exporting, please wait',
93+
ImportFromClipboard: 'Import from clipboard',
94+
PleaseCopyTheCorrectStepList: 'Please copy the correct step list',
95+
CopyConfigSuccessfully: 'Copy project config Successfully',
96+
97+
// Project Operation
98+
CopyProjectConfig: 'Copy project config',
99+
ExportAnnotationResults: 'Export annotation results',
100+
ModifyConfig: 'Modify config',
93101
},
94102
},
95103
cn: {
@@ -177,6 +185,14 @@ const resources = {
177185
MultiSelect: '多选',
178186
DefaultOption: '默认选择',
179187
MessageBeforeExport: '导出中,请稍后',
188+
ImportFromClipboard: '剪切板导入',
189+
PleaseCopyTheCorrectStepList: '请复制正确的步骤列表',
190+
CopyConfigSuccessfully: '复制项目配置成功',
191+
192+
// Project Operation
193+
CopyProjectConfig: '复制项目配置',
194+
ExportAnnotationResults: '导出标注结果',
195+
ModifyConfig: '修改配置',
180196
},
181197
},
182198
};

src/utils/DataTransfer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ export default class DataTransfer {
215215
category_id,
216216
};
217217

218+
let area = 0;
219+
if (rect.width && rect.height) {
220+
area = rect.width * rect.height;
221+
}
222+
Object.assign(defaultData, { area });
223+
218224
if (rect.textAttribute) {
219225
Object.assign(defaultData, { textAttribute: rect.textAttribute });
220226
}

src/utils/tool/common.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,33 @@ export function checkNumber(v: string) {
1010
return false;
1111
}
1212

13-
export function formatDate(date: Date, fmt: string){
14-
if(/(y+)/.test(fmt)){
15-
fmt = fmt.replace(RegExp.$1, (date.getFullYear()+'').substr(4-RegExp.$1.length));
13+
export function formatDate(date: Date, fmt: string) {
14+
if (/(y+)/.test(fmt)) {
15+
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
1616
}
1717
let o = {
18-
'M+': date.getMonth()+1,
18+
'M+': date.getMonth() + 1,
1919
'd+': date.getDate(),
2020
'h+': date.getHours(),
2121
'm+': date.getMinutes(),
22-
's+': date.getSeconds()
23-
}
24-
for(let k in o){
22+
's+': date.getSeconds(),
23+
};
24+
for (let k in o) {
2525
// @ts-ignore
26-
let str = o[k]+'';
27-
if(new RegExp(`(${k})`).test(fmt)){
28-
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length===1)?str:padLeftZero(str));
26+
let str = o[k] + '';
27+
if (new RegExp(`(${k})`).test(fmt)) {
28+
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str));
2929
}
3030
}
3131
return fmt;
32-
};
32+
}
3333

34-
function padLeftZero(str: string){
35-
return ('00'+str).substr(str.length);
34+
function padLeftZero(str: string) {
35+
return ('00' + str).substr(str.length);
3636
}
3737

3838
export function getCreateProjectCmt(showBase: boolean, Base: ReactNode, Step: ReactNode) {
39-
return showBase ? Base : Step
39+
return showBase ? Base : Step;
4040
}
4141

4242
export const jsonParser = (content: any, defaultValue: any = {}) => {
@@ -49,4 +49,27 @@ export const jsonParser = (content: any, defaultValue: any = {}) => {
4949
} catch (e) {
5050
return defaultValue;
5151
}
52-
};
52+
};
53+
54+
/**
55+
* 复制文本
56+
* @param text
57+
* @param element
58+
*/
59+
export const copyText = (text: string, element: 'input' | 'textarea' = 'input') => {
60+
const copyInput = document.createElement(element);
61+
copyInput.setAttribute(
62+
'style',
63+
`
64+
display: 'none'
65+
`,
66+
);
67+
68+
document.body.appendChild(copyInput);
69+
70+
copyInput.value = text;
71+
copyInput.select();
72+
73+
document.execCommand('copy');
74+
document.body.removeChild(copyInput);
75+
};

src/utils/tool/task.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export function deleteStep(step: number, stepList: IStepInfo[]) {
7676
const deleteStepList: any = stepList
7777
.filter((item) => deleteList.some((i) => i === item.step))
7878
.map(
79-
(item: any) => `${i18n.t('NStep')}
79+
(item: any) => `${i18n.t('NStep', { step: item.step })}
8080
${i18n.t(TOOL_NAME[item.tool])}`,
8181
);
8282

0 commit comments

Comments
 (0)