Skip to content

Commit d82bff4

Browse files
authored
fix: prevent deletion of predefined operators and improve error handling (#192)
* fix: prevent deletion of predefined operators and improve error handling * fix: prevent deletion of predefined operators and improve error handling
1 parent c1516c8 commit d82bff4

File tree

15 files changed

+99
-56
lines changed

15 files changed

+99
-56
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ endef
155155
# ========== Build Targets ==========
156156

157157
# Valid build targets
158-
VALID_BUILD_TARGETS := backend database frontend runtime backend-python deer-flow mineru mineru-npu
158+
VALID_BUILD_TARGETS := backend database frontend runtime backend-python deer-flow mineru mineru-npu gateway
159159

160160
# Generic docker build target with service name as parameter
161161
# Automatically prefixes image names with "datamate-" unless it's deer-flow

backend/services/operator-market-service/src/main/java/com/datamate/operator/application/OperatorService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ public void deleteOperator(String id) {
9595
if (operatorRepo.operatorInTemplateOrRunning(id)) {
9696
throw BusinessException.of(OperatorErrorCode.OPERATOR_IN_INSTANCE);
9797
}
98+
if (relationRepo.operatorIsPredefined(id)) {
99+
throw BusinessException.of(OperatorErrorCode.CANT_DELETE_PREDEFINED_OPERATOR);
100+
}
98101
operatorRepo.deleteOperator(id);
99102
relationRepo.deleteByOperatorId(id);
100103
}

backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/contants/OperatorConstant.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public class OperatorConstant {
3030

3131
public static String CATEGORY_STAR_ID = "51847c24-bba9-11f0-888b-5b143cb738aa";
3232

33+
public static String CATEGORY_PREDEFINED_ID = "96a3b07a-3439-4557-a835-525faad60ca3";
34+
3335
public static Map<String, String> CATEGORY_MAP = new HashMap<>();
3436

3537
static {

backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/CategoryRelationRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ public interface CategoryRelationRepository extends IRepository<CategoryRelation
1515
void batchUpdate(String operatorId, List<String> categories);
1616

1717
void deleteByOperatorId(String operatorId);
18+
19+
boolean operatorIsPredefined(String operatorId);
1820
}

backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/exception/OperatorErrorCode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public enum OperatorErrorCode implements ErrorCode {
1818

1919
SETTINGS_PARSE_FAILED("op.0004", "settings字段解析失败"),
2020

21-
OPERATOR_IN_INSTANCE("op.0005", "算子已被编排在模板或未完成的任务中");
21+
OPERATOR_IN_INSTANCE("op.0005", "算子已被编排在模板或未完成的任务中"),
22+
23+
CANT_DELETE_PREDEFINED_OPERATOR("op.0006", "预置算子无法删除");
2224

2325
private final String code;
2426
private final String message;

backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/CategoryRelationRepositoryImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
44
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
5+
import com.datamate.operator.domain.contants.OperatorConstant;
56
import com.datamate.operator.domain.model.CategoryRelation;
67
import com.datamate.operator.domain.repository.CategoryRelationRepository;
78
import com.datamate.operator.infrastructure.converter.CategoryRelationConverter;
@@ -48,4 +49,12 @@ public void deleteByOperatorId(String operatorId) {
4849
queryWrapper.eq(CategoryRelation::getOperatorId, operatorId);
4950
mapper.delete(queryWrapper);
5051
}
52+
53+
@Override
54+
public boolean operatorIsPredefined(String operatorId) {
55+
LambdaQueryWrapper<CategoryRelation> queryWrapper = new LambdaQueryWrapper<>();
56+
queryWrapper.eq(CategoryRelation::getOperatorId, operatorId)
57+
.eq(CategoryRelation::getCategoryId, OperatorConstant.CATEGORY_PREDEFINED_ID);
58+
return this.exists(queryWrapper);
59+
}
5160
}

backend/services/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
</exclusions>
6565
</dependency>
6666

67+
<dependency>
68+
<groupId>org.springframework.boot</groupId>
69+
<artifactId>spring-boot-starter-log4j2</artifactId>
70+
<version>${spring-boot.version}</version>
71+
</dependency>
72+
6773
<dependency>
6874
<groupId>com.baomidou</groupId>
6975
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>

frontend/src/components/ActionDropdown.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const ActionDropdown = ({
6868
<Button
6969
type="text"
7070
size="small"
71+
disabled={action.disabled || false}
7172
className="w-full text-left"
7273
danger={action.danger}
7374
icon={action.icon}
@@ -84,6 +85,7 @@ const ActionDropdown = ({
8485
className="w-full"
8586
size="small"
8687
type="text"
88+
disabled={action.disabled || false}
8789
danger={action.danger}
8890
icon={action.icon}
8991
onClick={() => handleActionClick(action)}

frontend/src/pages/DataCleansing/Detail/components/FileTable.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export default function FileTable({result, fetchTaskResult}) {
7878
title: "文件名",
7979
dataIndex: "srcName",
8080
key: "srcName",
81+
width: 200,
8182
filterDropdown: ({
8283
setSelectedKeys,
8384
selectedKeys,
@@ -110,6 +111,43 @@ export default function FileTable({result, fetchTaskResult}) {
110111
<span>{text?.replace(/\.[^/.]+$/, "")}</span>
111112
),
112113
},
114+
{
115+
title: "清洗后文件名",
116+
dataIndex: "destName",
117+
key: "destName",
118+
width: 200,
119+
filterDropdown: ({
120+
setSelectedKeys,
121+
selectedKeys,
122+
confirm,
123+
clearFilters,
124+
}: any) => (
125+
<div className="p-4 w-64">
126+
<Input
127+
placeholder="搜索文件名"
128+
value={selectedKeys[0]}
129+
onChange={(e) =>
130+
setSelectedKeys(e.target.value ? [e.target.value] : [])
131+
}
132+
onPressEnter={() => confirm()}
133+
className="mb-2"
134+
/>
135+
<div className="flex gap-2">
136+
<Button size="small" onClick={() => confirm()}>
137+
搜索
138+
</Button>
139+
<Button size="small" onClick={() => clearFilters()}>
140+
重置
141+
</Button>
142+
</div>
143+
</div>
144+
),
145+
onFilter: (value: string, record: any) =>
146+
record.destName.toLowerCase().includes(value.toLowerCase()),
147+
render: (text: string) => (
148+
<span>{text?.replace(/\.[^/.]+$/, "")}</span>
149+
),
150+
},
113151
{
114152
title: "文件类型",
115153
dataIndex: "srcType",

frontend/src/pages/OperatorMarket/Home/components/List.tsx

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,13 @@
1-
import { Button, List, Tag, Badge } from "antd";
2-
import { StarFilled } from "@ant-design/icons";
3-
import { Zap, Settings, X } from "lucide-react";
4-
import { useState } from "react";
1+
import { Button, List, Tag } from "antd";
52
import { useNavigate } from "react-router";
63
import { Operator } from "../../operator.model";
74

85
export function ListView({ operators = [], pagination, operations }) {
96
const navigate = useNavigate();
10-
const [favoriteOperators, setFavoriteOperators] = useState<Set<number>>(
11-
new Set([1, 3, 6])
12-
);
13-
const handleUpdateOperator = (operator: Operator) => {
14-
navigate(`/data/operator-market/create/${operator.id}`);
15-
};
7+
168
const handleViewOperator = (operator: Operator) => {
179
navigate(`/data/operator-market/plugin-detail/${operator.id}`);
1810
};
19-
const handleToggleFavorite = (operatorId: number) => {
20-
setFavoriteOperators((prev) => {
21-
const newFavorites = new Set(prev);
22-
if (newFavorites.has(operatorId)) {
23-
newFavorites.delete(operatorId);
24-
} else {
25-
newFavorites.add(operatorId);
26-
}
27-
return newFavorites;
28-
});
29-
};
30-
const getStatusBadge = (status: string) => {
31-
const statusConfig = {
32-
active: {
33-
label: "活跃",
34-
color: "green",
35-
icon: <Zap className="w-3 h-3" />,
36-
},
37-
beta: {
38-
label: "测试版",
39-
color: "blue",
40-
icon: <Settings className="w-3 h-3" />,
41-
},
42-
deprecated: {
43-
label: "已弃用",
44-
color: "gray",
45-
icon: <X className="w-3 h-3" />,
46-
},
47-
};
48-
return (
49-
statusConfig[status as keyof typeof statusConfig] || statusConfig.active
50-
);
51-
};
5211

5312
return (
5413
<List

0 commit comments

Comments
 (0)