Skip to content

Commit fc49c1d

Browse files
committed
feat: import & export with tasks
1 parent 4390b12 commit fc49c1d

12 files changed

Lines changed: 156 additions & 107 deletions

File tree

src/pages/background/request-handler/dnr-handler/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { prefs } from '@/share/core/prefs';
77
import { detectRunner } from '@/share/core/rule-utils';
88
import SessionMessage from '@/share/core/session-message';
99
import { getSession, readStorage } from '@/share/core/storage';
10+
import { getRuleUsedTasks } from '@/share/core/tasks';
1011
import type { Rule, Task } from '@/share/core/types';
1112
import {
1213
getVirtualKey,
@@ -15,7 +16,7 @@ import {
1516
t,
1617
} from '@/share/core/utils';
1718
import { getAll, get as getRules, waitLoad } from '../../core/rules';
18-
import { createDNR, getRuleId, getRuleUsedTasks } from './utils';
19+
import { createDNR, getRuleId } from './utils';
1920

2021
type DNRRule = DeclarativeNetRequest.Rule;
2122

src/pages/background/request-handler/dnr-handler/utils.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,6 @@ import { parseJSONPath } from '../utils';
1111

1212
export type DNRRule = DeclarativeNetRequest.Rule;
1313

14-
function getTaskUsage(text: string) {
15-
if (!text.includes('{$TASK.')) {
16-
return [];
17-
}
18-
// 形似 {$TASK.task_key.PATH}
19-
const matches = text.match(/\{\$TASK\.([^}]+)\}/g);
20-
if (!matches) {
21-
return [];
22-
}
23-
return matches.map(x => x.substring(7, x.indexOf('.')));
24-
}
25-
26-
export function getRuleUsedTasks(rule: Rule): Set<string> {
27-
switch (rule.ruleType) {
28-
case RULE_TYPE.CANCEL:
29-
return new Set();
30-
case RULE_TYPE.MODIFY_SEND_HEADER:
31-
case RULE_TYPE.MODIFY_RECV_HEADER:
32-
return new Set(
33-
Object.values(rule.headers || {}).flatMap(x => getTaskUsage(x)),
34-
);
35-
case RULE_TYPE.REDIRECT:
36-
return new Set(getTaskUsage(rule.to || ''));
37-
case RULE_TYPE.MODIFY_RECV_BODY:
38-
return new Set(getTaskUsage(rule.body?.value || ''));
39-
}
40-
}
41-
4214
export function createDNR(rule: Rule, id: number) {
4315
const res: DNRRule = {
4416
id,

src/pages/options/sections/import-and-export/cloud/index.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import { IconDownload, IconUpload, IconExternalOpen } from '@douyinfe/semi-icons';
1+
import {
2+
IconDownload,
3+
IconExternalOpen,
4+
IconUpload,
5+
} from '@douyinfe/semi-icons';
26
import { Button, Modal, Tag, Toast } from '@douyinfe/semi-ui';
37
import { css } from '@emotion/css';
48
import dayjs from 'dayjs';
5-
import * as React from 'react';
69
import localizedFormat from 'dayjs/plugin/localizedFormat';
10+
import * as React from 'react';
11+
import { createExport } from '@/pages/options/utils';
12+
import type { BasicRule } from '@/share/core/types';
13+
import { t } from '@/share/core/utils';
714
import Api from '@/share/pages/api';
815
import browserSync from '@/share/pages/browser-sync';
9-
import { createExport } from '@/share/core/rule-utils';
10-
import { t } from '@/share/core/utils';
11-
import type { BasicRule } from '@/share/core/types';
1216

1317
dayjs.extend(localizedFormat);
1418

@@ -38,8 +42,8 @@ export default class Cloud extends React.Component<CloudProps, CloudState> {
3842
}
3943

4044
private refresh() {
41-
browserSync.getMeta().then((r) => {
42-
if (r && r.time) {
45+
browserSync.getMeta().then(r => {
46+
if (r?.time) {
4347
this.setState({
4448
has: true,
4549
time: r.time,
@@ -54,25 +58,27 @@ export default class Cloud extends React.Component<CloudProps, CloudState> {
5458

5559
handleUpload() {
5660
Api.getAllRules()
57-
.then((result) => browserSync.save(createExport(result)))
61+
.then(result => createExport(result))
62+
.then(result => browserSync.save(result))
5863
.then(() => browserSync.getMeta())
5964
.then(() => this.refresh())
6065
.catch(() => Toast.error('cloud_over_limit'));
6166
}
6267

6368
handleDownload() {
6469
this.props.onClose();
65-
browserSync.getContent().then((r) => {
70+
browserSync.getContent().then(r => {
6671
this.props.onImport(r);
6772
});
6873
}
6974

70-
handleDelete(from: string) {
75+
handleDelete() {
7176
browserSync.clear().then(() =>
7277
this.setState({
7378
has: false,
7479
time: 0,
75-
}));
80+
}),
81+
);
7682
return true;
7783
}
7884

@@ -98,13 +104,28 @@ export default class Cloud extends React.Component<CloudProps, CloudState> {
98104
title={t('cloud_backup')}
99105
footer={
100106
<div className="buttons">
101-
<Button type="secondary" onClick={this.handleHelp} icon={<IconExternalOpen />}>
107+
<Button
108+
type="secondary"
109+
onClick={this.handleHelp}
110+
icon={<IconExternalOpen />}
111+
>
102112
{t('help')}
103113
</Button>
104-
<Button theme="solid" type="primary" onClick={this.handleDownload} disabled={!this.state.has} icon={<IconDownload />}>
114+
<Button
115+
theme="solid"
116+
type="primary"
117+
onClick={this.handleDownload}
118+
disabled={!this.state.has}
119+
icon={<IconDownload />}
120+
>
105121
{t('download')}
106122
</Button>
107-
<Button theme="solid" type="primary" onClick={this.handleUpload} icon={<IconUpload />}>
123+
<Button
124+
theme="solid"
125+
type="primary"
126+
onClick={this.handleUpload}
127+
icon={<IconUpload />}
128+
>
108129
{t('upload')}
109130
</Button>
110131
</div>

src/pages/options/sections/import-and-export/import-drawer/index.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { selectGroup } from '@/pages/options/utils';
66
import BoolRadioGroup from '@/share/components/bool-radio';
77
import { TABLE_NAMES_ARR } from '@/share/core/constant';
88
import { fromJson } from '@/share/core/rule-utils';
9-
import type { BasicRule, ImportRule } from '@/share/core/types';
9+
import { getRuleUsedTasks } from '@/share/core/tasks';
10+
import type { BasicRule, ImportRule, Rule, Task } from '@/share/core/types';
1011
import { t } from '@/share/core/utils';
1112
import Api from '@/share/pages/api';
1213

@@ -26,6 +27,8 @@ export default class ImportDrawer extends React.Component<
2627
ImportDrawerProps,
2728
ImportDrawerState
2829
> {
30+
tasks?: Record<string, Task>;
31+
2932
constructor(props: any) {
3033
super(props);
3134

@@ -42,7 +45,7 @@ export default class ImportDrawer extends React.Component<
4245
};
4346
}
4447

45-
show(content: { [key: string]: BasicRule[] }) {
48+
show(content: any) {
4649
this.setState({
4750
...this.state,
4851
list: [],
@@ -57,7 +60,7 @@ export default class ImportDrawer extends React.Component<
5760
if (!list[tableName]) {
5861
return;
5962
}
60-
list[tableName].forEach(e => {
63+
list[tableName].forEach((e: Rule) => {
6164
totalCount++;
6265
Api.getRules(tableName, { name: e.name }).then(rule => {
6366
const it: ImportRule = {
@@ -79,15 +82,18 @@ export default class ImportDrawer extends React.Component<
7982
});
8083
});
8184
});
85+
if (content.tasks) {
86+
this.tasks = content.tasks;
87+
}
8288
} catch (e) {
8389
console.error(e);
8490
}
8591
}
8692

8793
handleConfirm() {
88-
// TODO: 处理 task 导入
8994
// 确认导入
9095
const queue: any[] = [];
96+
const tasks = new Set<string>();
9197
this.state.list.forEach((e: any) => {
9298
// 不导入
9399
if (e.importAction === 3) {
@@ -106,8 +112,15 @@ export default class ImportDrawer extends React.Component<
106112
if (typeof e.enable === 'undefined') {
107113
e.enable = true;
108114
}
115+
getRuleUsedTasks(e).forEach(task => tasks.add(task));
109116
queue.push(Api.saveRule(e));
110117
});
118+
// 处理 task 导入
119+
if (tasks.size > 0) {
120+
Array.from(tasks)
121+
.map(x => this.tasks?.[x])
122+
.forEach(t => queue.push(t ? Api.saveTask(t) : Promise.resolve()));
123+
}
111124
Promise.all(queue).then(() => {
112125
// this.imports.status = 0;
113126
Toast.success(t('import_success'));
@@ -222,8 +235,8 @@ export default class ImportDrawer extends React.Component<
222235
render: (_v: any, item: ImportRule) => (
223236
<Select
224237
value={item.importAction}
225-
onChange={(value: string) =>
226-
this.handleActionChange(item, value)
238+
onChange={value =>
239+
this.handleActionChange(item, value as string)
227240
}
228241
optionList={[
229242
{ label: t('import_new'), value: 1 },

src/pages/options/sections/import-and-export/index.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import {
88
import { Button, Card, Input, Space, Table, Toast } from '@douyinfe/semi-ui';
99
import * as React from 'react';
1010
import { openURL } from '@/pages/background/utils';
11-
import { getExportName } from '@/pages/options/utils';
12-
import { createExport } from '@/share/core/rule-utils';
1311
import { getLocal, readStorage } from '@/share/core/storage';
1412
import type { BasicRule } from '@/share/core/types';
1513
import { fetchUrl, t } from '@/share/core/utils';
1614
import Api from '@/share/pages/api';
1715
import file from '@/share/pages/file';
1816
import { Layout } from '../layout';
17+
import { batchShare } from '../rules/utils';
1918
import Cloud from './cloud';
2019
import ImportDrawer from './import-drawer';
2120

@@ -101,10 +100,7 @@ export default class ImportAndExport extends React.Component<{}, IEState> {
101100

102101
async handleExport() {
103102
const result = await Api.getAllRules();
104-
file.save(
105-
JSON.stringify(createExport(result), null, '\t'),
106-
getExportName(),
107-
);
103+
batchShare(Object.values(result).flat());
108104
}
109105

110106
handleOpenThird() {

src/pages/options/sections/rules/rule-group-card.tsx

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,18 @@ import type {
2828
} from '@douyinfe/semi-ui/lib/es/table';
2929
import { css } from '@emotion/css';
3030
import { useResponsive } from 'ahooks';
31-
import { getExportName, selectGroup } from '@/pages/options/utils';
31+
import { selectGroup } from '@/pages/options/utils';
3232
import Modal from '@/share/components/modal';
3333
import RuleContentSwitcher from '@/share/components/rule-content-switcher';
3434
import RuleDetail from '@/share/components/rule-detail';
35-
import { TABLE_NAMES_ARR, VIRTUAL_KEY } from '@/share/core/constant';
36-
import { convertToBasicRule, createExport } from '@/share/core/rule-utils';
35+
import { VIRTUAL_KEY } from '@/share/core/constant';
36+
import { convertToBasicRule } from '@/share/core/rule-utils';
3737
import type { RuleWithVirtualKey } from '@/share/core/types';
38-
import { getTableName, t } from '@/share/core/utils';
38+
import { t } from '@/share/core/utils';
3939
import useMarkCommon from '@/share/hooks/use-mark-common';
4040
import Api from '@/share/pages/api';
41-
import file from '@/share/pages/file';
4241
import { textEllipsis } from '@/share/pages/styles';
43-
import { remove, toggleRule } from './utils';
42+
import { batchShare, remove, toggleRule } from './utils';
4443

4544
interface RuleCardProps {
4645
name: string;
@@ -291,17 +290,7 @@ const RuleGroupCard = (props: RuleCardProps) => {
291290
{
292291
node: 'item',
293292
name: t('share'),
294-
onClick: () => {
295-
const result: any = {};
296-
TABLE_NAMES_ARR.forEach(tb => {
297-
result[tb] = [];
298-
});
299-
rules.forEach(e => result[getTableName(e.ruleType)].push(e));
300-
file.save(
301-
JSON.stringify(createExport(result), null, '\t'),
302-
getExportName(),
303-
);
304-
},
293+
onClick: () => batchShare(rules),
305294
icon: <IconSend />,
306295
},
307296
{
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import Api from '@/share/pages/api';
21
import { TABLE_NAMES_ARR } from '@/share/core/constant';
3-
import file from '@/share/pages/file';
4-
import { createExport } from '@/share/core/rule-utils';
5-
import { getTableName } from '@/share/core/utils';
62
import type { Rule } from '@/share/core/types';
7-
import { getExportName } from '../../utils';
3+
import { getTableName } from '@/share/core/utils';
4+
import Api from '@/share/pages/api';
5+
import file from '@/share/pages/file';
6+
import { createExport, getExportName } from '../../utils';
87

98
export function toggleRule(rule: Rule, enable: boolean) {
109
rule.enable = enable;
@@ -20,11 +19,14 @@ export function save(rule: Rule) {
2019
return Api.saveRule(rule);
2120
}
2221

23-
export function batchShare(rules: Rule[]) {
22+
export async function batchShare(rules: Rule[]) {
2423
const result: any = {};
25-
TABLE_NAMES_ARR.forEach((tb) => {
24+
TABLE_NAMES_ARR.forEach(tb => {
2625
result[tb] = [];
2726
});
28-
rules.forEach((e) => result[getTableName(e.ruleType)].push(e));
29-
file.save(JSON.stringify(createExport(result), null, '\t'), getExportName());
27+
rules.forEach(e => result[getTableName(e.ruleType)].push(e));
28+
file.save(
29+
JSON.stringify(await createExport(result), null, '\t'),
30+
getExportName(),
31+
);
3032
}

src/pages/options/utils.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)