From 89270a9a469dffe59618ab064aac4c1142fcf78d Mon Sep 17 00:00:00 2001 From: freyaLo Date: Wed, 31 Aug 2022 19:30:01 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E5=B7=A5=E5=85=B7=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=92=8C=E8=A7=84=E5=88=99=E5=90=8D=E7=A7=B0=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/react-highlight/index.tsx | 53 ++++ .../src/modules/projects/issues/index.tsx | 11 +- .../projects/issues/issue-detail-modal.tsx | 259 +++++++++++++----- .../modules/projects/issues/rule-detail.tsx | 111 ++++---- .../src/modules/projects/issues/search.tsx | 4 +- .../src/modules/projects/issues/style.scss | 78 +++++- .../schemes/code-lint/all-rules-search.tsx | 154 ++++++----- .../modules/schemes/code-lint/all-rules.tsx | 13 +- .../modules/schemes/code-lint/pkg-rules.tsx | 3 +- .../src/modules/schemes/code-lint/search.tsx | 113 ++++---- .../template/code-lint/all-rules-search.tsx | 149 +++++----- .../modules/template/code-lint/all-rules.tsx | 14 +- .../modules/template/code-lint/pkg-rules.tsx | 3 +- .../src/modules/template/code-lint/search.tsx | 114 ++++---- .../tca-analysis/src/services/schemes.ts | 17 ++ .../tca-analysis/src/utils/getRoutePath.ts | 9 + .../public/locales/en-US/translation.json | 2 - .../public/locales/zh-CN/translation.json | 2 - .../plat/open/modules/nodes/node-table.tsx | 4 +- .../open/modules/nodes/node-tasks-modal.tsx | 126 --------- 20 files changed, 737 insertions(+), 502 deletions(-) create mode 100644 web/packages/tca-analysis/src/components/react-highlight/index.tsx delete mode 100644 web/packages/tca-manage/src/plat/open/modules/nodes/node-tasks-modal.tsx diff --git a/web/packages/tca-analysis/src/components/react-highlight/index.tsx b/web/packages/tca-analysis/src/components/react-highlight/index.tsx new file mode 100644 index 000000000..72a3a9692 --- /dev/null +++ b/web/packages/tca-analysis/src/components/react-highlight/index.tsx @@ -0,0 +1,53 @@ +import React, { useRef, useEffect } from 'react'; +import hljs from 'highlight.js'; + + +interface HighlightProps { + children: React.ReactNode | React.ReactNode[]; + element?: React.ReactNode; + className: any; +} + +const Highlight = (props: HighlightProps) => { + const ele = useRef(null); + + useEffect(() => { + highlightCode(); + }); + + const highlightCode = () => { + const nodes = ele.current.querySelectorAll('pre code'); + + nodes?.forEach((element: any) => { + hljs.highlightBlock(element); + }); + + // for (let i = 0; i < nodes.length; i++) { + // hljs.highlightBlock(nodes[i]); + // } + }; + + const { + children, + className, + // element: Element = null, + // innerHTML = false, + } = props; + // const eleProps = { ref: ele, className }; + + // if (innerHTML) { + // eleProps.dangerouslySetInnerHTML = { __html: children }; + + // if (Element) { + // return ; + // } + // return
; + // } + + // if (Element) { + // return {children}; + // } + return
{children}
; +}; + +export default Highlight; diff --git a/web/packages/tca-analysis/src/modules/projects/issues/index.tsx b/web/packages/tca-analysis/src/modules/projects/issues/index.tsx index fae64ce09..9645b058f 100644 --- a/web/packages/tca-analysis/src/modules/projects/issues/index.tsx +++ b/web/packages/tca-analysis/src/modules/projects/issues/index.tsx @@ -355,10 +355,10 @@ const Issues = (props: IssuesProps) => { /> ( {name} @@ -440,11 +440,10 @@ const Issues = (props: IssuesProps) => {
void; nextIssue: () => void; onClose: () => void; @@ -45,11 +41,10 @@ interface IssueModalProps { const IssueModal = (props: IssueModalProps) => { const { params, - curSchemeId, issueId, visible, - isFirstIssue, - isLastIssue, + issuesData, + listLoading, prevIssue, nextIssue, onClose, @@ -62,23 +57,31 @@ const IssueModal = (props: IssueModalProps) => { const [detail, setDetail] = useState({}); const [loading, setLoading] = useState(false); const [codeFile, setCode] = useState({}); + const [isFirstIssue, setIsFirstIssue] = useState(false); + const [isLastIssue, setIsLastIssue] = useState(false); const [status, setStatus] = useState({ - severityPopVsb: false, - authorPopVsb: false, - issuePopVsb: false, - rulePopVsb: false, - issueLinePopVsb: false, + severityPopVsb: false, // 修改严重级别 popover + authorPopVsb: false, // 修改责任人 popover + issuePopVsb: false, // 处理问题 popover + issueLinePopVsb: false, // 查看问题行 popover + historyPopVsb: false, // 操作记录 popover }); - const [ruleDetail, setRuleDetail] = useState({}); - + const [expanded, setExpanded] = useState([]); // 标记问题行规则是否展开 + const [ruleDetail, setRuleDetail] = useState({}); + const { list, next, previous } = issuesData; const issueLines = detail.issue_details?.map((item: any) => item.line) ?? []; + const loadingStatus = loading || listLoading; useEffect(() => { + // 重置数据 + setExpanded([]); + setRuleDetail({}); + if (visible && issueId) { getIssueDetail(orgSid, teamName, repoId, projectId, issueId).then((res) => { const params: any = { path: res.file_path, - revision: get(res, 'issue_details[0].scan_revision'), + revision: res?.issue_details[0]?.scan_revision, }; if (res.is_external) { // 外部代码库需要传url @@ -88,23 +91,60 @@ const IssueModal = (props: IssueModalProps) => { setDetail(res); setLoading(true); getCodeFile(orgSid, teamName, repoId, projectId, params) - .then((file) => { - setCode(file); + .then((response) => { + setCode(response); }) .finally(() => { setLoading(false); - scrollToItem(res?.issue_details[0].line); + scrollToItem(res?.issue_details[0]?.line); }); + + getRuleDetailInfo(res); }); } }, [visible, issueId]); + useEffect(() => { + if (visible) { + getIssueBoundary(); + } + }, [visible, issueId, issuesData]); + + useEffect(() => { + // 重置数据, 防止在【上/下一个问题】列表需要翻页时出现脏数据展示 + if (listLoading) { + setCode({}); + setDetail({}); + } + }, [listLoading]); + + // 判断当前 Issue 是否为第一个/最后一个问题 + const getIssueBoundary = () => { + const index = findIndex(list, { id: issueId }); + // 如果路由中存在issueId,则index可能为-1,也视作第一个问题 + if (index <= 0 && !previous) { + // 第一个问题 + setIsFirstIssue(true); + } else if (isFirstIssue) { + setIsFirstIssue(false); + } + + if (index === list.length - 1 && !next) { + // 最后一个问题 + setIsLastIssue(true); + } else if (isLastIssue) { + setIsLastIssue(false); + } + }; + const scrollToItem = (line: number) => { - listRef.current?.scrollToItem(line, 'center'); + if (line && listRef.current && listRef.current.scrollToItem) { + listRef.current.scrollToItem(line, 'center'); + } }; const getRowHeight = (index: number) => { - const lineMinHeight = 30; + const lineMinHeight = 26; return rowHeights.current[index] || lineMinHeight; }; @@ -114,9 +154,11 @@ const IssueModal = (props: IssueModalProps) => { }; const rowRenderer = ({ index, style: rowStyle }: any) => { - const { lineNum: line, content = '' } = codeFile?.codeContents[index] || {}; + const { lineNum: line, content } = codeFile?.codeContents[index] ?? {}; const rowRef: any = useRef({}); const language = detail.language ?? codeFile.suffix?.split('.')[1] ?? 'plaintext'; + const issueIndex = issueLines.indexOf(line); + const fileError = line === 1 && issueLines[0] === 0; // 文件级警告 useEffect(() => { if (rowRef.current) { @@ -133,33 +175,84 @@ const IssueModal = (props: IssueModalProps) => { className={cn(style.codeContent, { [style[`status-${detail.severity}`]]: (line === 1 && issueLines[0] === 0) || issueLines.includes(line), + [style.fileError]: line === 1 && issueLines[0] === 0, })} > {// 本行有问题 || 问题行为0,即文件问题显示在第一行之前 - ((line === 1 && issueLines[0] === 0) - || issueLines.includes(line)) && ( + (fileError || issueLines.includes(line)) && (
-
- -   【{detail.checkrule_real_name}】规则描述: - {detail.checkrule_rule_title} - {false && ( - - )} +
{ + if (issueIndex > -1) { + const list = cloneDeep(expanded); + list[issueIndex] = !expanded[issueIndex]; + setExpanded(list); + } + }} + > + + {expanded[issueIndex] || fileError ? ( + + ) : ( + + )} + 【{detail.checkrule_real_name}】规则描述: + {ruleDetail.rule_title} + + + {issueIndex !== 0 && !fileError && ( + document.body} + > +
-
{detail.msg}
+
错误原因:{detail.msg}
+ {(expanded[issueIndex] || fileError) + && ruleDetail.checkruledesc?.desc && ( +
+

规则详细说明

+ + {ruleDetail.checkruledesc?.desc} + +
+ )}
)} {content.length > CODE_MAX_CHAR_LENGTH ? `${content.substring(0, CODE_MAX_CHAR_LENGTH)}...` - : content} + : content} 
@@ -178,15 +271,9 @@ const IssueModal = (props: IssueModalProps) => { setStatus(obj); }; - const getRuleDetailInfo = () => { + const getRuleDetailInfo = (issueDetail: any) => { if (isEmpty(ruleDetail)) { - getRuleDetail( - orgSid, - teamName, - repoId, - curSchemeId, - detail.checkrule_gid, - ).then((res: any) => { + getRuleDetail(orgSid, teamName, repoId, projectId, issueDetail.checkrule_gid).then((res: any) => { setRuleDetail(res); }); } @@ -210,16 +297,17 @@ const IssueModal = (props: IssueModalProps) => { centered title={
-

{detail.file_path?.split('/').pop()}

- - - - - +

+ {detail.file_path?.split('/').pop()} + + 文件路径:{detail.file_path} + + +

+ {/* todo: 全屏查看issue */} + {/* + + */}
} width={1000} @@ -231,8 +319,6 @@ const IssueModal = (props: IssueModalProps) => { >
@@ -253,9 +339,8 @@ const IssueModal = (props: IssueModalProps) => { }} />
- {loading ? ( - - ) : ( + {loadingStatus && } + {!loadingStatus && codeFile.codeContents && ( {({ height, width }: any) => ( { )} )} + {!loadingStatus && codeFile.code === -1 && codeFile.cd_error && ( +
+

问题所在行

+ {issueLines?.map((line: number) => ( + + 第 {line} 行 + + ))} + +

错误原因

+

{detail.msg}

+ +

+ 代码拉取失败, + {codeFile.cd_error} +

+

处理建议

+

1. 代码库帐号密码问题。

+

2. 文件格式无法展示 —— 不支持展示.jar等二进制文件。

+

+ 3. 代码文件不存在 —— + 可能为本地分析中间代码,请在本地环境下查看代码或者联系管理员定位问题。{' '} +

+
+ )}
diff --git a/web/packages/tca-analysis/src/modules/projects/issues/rule-detail.tsx b/web/packages/tca-analysis/src/modules/projects/issues/rule-detail.tsx index 719bc038e..9715be659 100644 --- a/web/packages/tca-analysis/src/modules/projects/issues/rule-detail.tsx +++ b/web/packages/tca-analysis/src/modules/projects/issues/rule-detail.tsx @@ -9,10 +9,12 @@ */ import React from 'react'; import cn from 'classnames'; +import { Link, useParams } from 'react-router-dom'; import ReactMarkdown from 'react-markdown'; import { get } from 'lodash'; import { Drawer } from 'coding-oa-uikit'; +import { getToolsRouter } from '@src/utils/getRoutePath'; import style from './style.scss'; @@ -24,58 +26,69 @@ interface RuleDetailProps { const RuleDetail = (props: RuleDetailProps) => { const { data, visible, onClose } = props; + const { orgSid } = useParams(); + console.log(data); return ( - -
- 展示名称 - {data.display_name || '--'} -
- {/*
- 实际名称 - {data.real_name || '--'} -
*/} + +
+ 规则名称 + {data.real_name || '--'} +
-
- 规则概述 - {data.rule_title || '--'} -
-
- 责任人 - {data.creator || '--'} -
-
- 规则状态 - {data.disable ? '禁用' : '活跃'} -
-
- 适用语言 - {(data.languages?.join(' | ')) || '--'} -
-
- 分类 - {data.category_name || '--'} -
-
- 严重级别 - {data.severity_name || '--'} -
-
- 详细描述 -
- {get(data, 'checkruledesc.desc') && ( -
- {/* eslint-disable-next-line */} - -
- )} -
+
+ 规则概述 + {data.rule_title || '--'} +
+
+ 所属工具 + {data?.checktool?.display_name ? ( + + {data?.checktool?.display_name} + + ) : ( + -- + )} +
+
+ 责任人 + {data.creator || '--'} +
+
+ 规则状态 + {data.disable ? '禁用' : '活跃'} +
+
+ 适用语言 + {data.languages?.join(' | ') || '--'} +
+
+ 分类 + {data.category_name || '--'} +
+
+ 严重级别 + {data.severity_name || '--'} +
+
+ 详细描述 +
+ {get(data, 'checkruledesc.desc') && ( +
+ {/* eslint-disable-next-line */} + +
+ )} +
); }; diff --git a/web/packages/tca-analysis/src/modules/projects/issues/search.tsx b/web/packages/tca-analysis/src/modules/projects/issues/search.tsx index 12179d4d2..323e9b548 100644 --- a/web/packages/tca-analysis/src/modules/projects/issues/search.tsx +++ b/web/packages/tca-analysis/src/modules/projects/issues/search.tsx @@ -156,12 +156,12 @@ const Search = (props: SearchProps) => { onChange={(value: any) => value && onChange('checkpackage', value)} /> - + onChange('checkrule_display_name', value)} + onSearch={(value: string) => onChange('checkrule_real_name', value)} /> diff --git a/web/packages/tca-analysis/src/modules/projects/issues/style.scss b/web/packages/tca-analysis/src/modules/projects/issues/style.scss index 2538af61d..8fddf3cf5 100644 --- a/web/packages/tca-analysis/src/modules/projects/issues/style.scss +++ b/web/packages/tca-analysis/src/modules/projects/issues/style.scss @@ -246,6 +246,27 @@ vertical-align: inherit !important; } } + + .modal-desc{ + margin-left: 8px; + } + + .modal-desc, .copy-icon{ + font-size: 12px; + color: #606c80; + } + } + + .code-error { + margin-top: 30px; + + p { + margin-bottom: 16px; + } + + .error-desc { + color: #eb333f; + } } .wrapper { @@ -285,6 +306,7 @@ .code-wrapper { height: 800px; + height: calc(100vh - 340px); padding-left: 20px; .row { @@ -301,19 +323,51 @@ .code-content { flex: 1; - padding-left: 10px; + // padding-left: 10px; + + pre { + padding-left: 10px; + } .rule-wrapper { padding-top: 6px; + padding-right: 10px; + padding-left: 10px; + + .rule { + display: flex; + justify-content: space-between; + cursor: pointer; + + button { + height: 26px; + } + + .rule-content { + color: #202d40; + } + } .rule-desc { + color: #606c80; + font-size: 13px; padding-left: 17px; margin-top: 2px; + line-height: 2; + max-height: 300px; + overflow: auto; + + h4 { + color: #606c80; + margin-top: 16px; + font-size: 14px; + } } - .rule-detail { - padding-left: 6px; - font-size: 13px; + .issue-msg { + padding-left: 20px; + margin: 6px 0; + // font-size: 13px; } } @@ -321,21 +375,37 @@ &-1 { background-color: $fatal-bg; color: $fatal-color; + + pre { + background-color: $fatal-bg; + } } &-2 { background-color: $error-bg; color: $error-color; + + pre { + background-color: $error-bg; + } } &-3 { background-color: $warging-bg; color: $warging-color; + + pre { + background-color: $warging-bg; + } } &-4 { background-color: $tip-bg; color: $tip-color; + + pre { + background-color: $tip-bg; + } } } } diff --git a/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules-search.tsx b/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules-search.tsx index a11822f1e..cf734c213 100644 --- a/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules-search.tsx +++ b/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules-search.tsx @@ -12,7 +12,7 @@ import SelectBorderless from '@src/components/select-borderless'; import Filter from '@src/components/filter'; import { SEVERITY, CATEGORY } from '../constants'; -const numberParams = ['checkpackage', 'severity', 'category']; +const numberParams = ['checkpackage', 'severity', 'category', 'checktool']; const arrayParams = ['language']; interface SearchProps { @@ -25,13 +25,15 @@ interface SearchProps { const Search = (props: SearchProps) => { const [form] = Form.useForm(); const { searchParams, loading, filters, callback } = props; - const { allPkgs = [], languages = [] }: any = filters; + const { allPkgs = [], languages = [], checkTools = [] }: any = filters; const initialValues = cloneDeep(searchParams); Object.entries(initialValues).forEach(([key, value]: [string, string]) => { if (numberParams.includes(key) && isString(value)) { - initialValues[key] = value.split(',').map((item: string) => toNumber(item)); + initialValues[key] = value + .split(',') + .map((item: string) => toNumber(item)); } if (arrayParams.includes(key) && isString(value)) { @@ -61,70 +63,88 @@ const Search = (props: SearchProps) => { }; return ( - - - value && onChange('checkpackage', value.join(','))} - /> - - - ({ - value: toNumber(key), - text: value, - }))} - onChange={(value: any) => value && onChange('severity', value.join(','))} - /> - - - ({ - value: toNumber(key), - text: value, - }))} - onChange={(value: any) => value && onChange('category', value.join(','))} - /> - - - ({ - value: item.name, - text: item.display_name, - })) - } - onChange={(value: any) => value && onChange('language', value.join(','))} - /> - - - onChange('display_name', value)} - /> - - {Object.keys(searchParams).some((key: string) => ( - isArray(searchParams[key]) - ? !isEmpty(searchParams[key]) - : searchParams[key])) && ( - - )} - + + + value && onChange('checkpackage', value.join(',')) + } + /> + + + ({ + value: toNumber(key), + text: value, + }))} + onChange={(value: any) => value && onChange('severity', value.join(',')) + } + /> + + + ({ + value: toNumber(key), + text: value, + }))} + onChange={(value: any) => value && onChange('category', value.join(',')) + } + /> + + + ({ + value: item.id, + text: item.display_name, + }))} + onChange={(value: any) => value && onChange('checktool', value.join(',')) + } + /> + + + ({ + value: item.name, + text: item.display_name, + }))} + onChange={(value: any) => value && onChange('language', value.join(',')) + } + /> + + + onChange('real_name', value)} + /> + + {Object.keys(searchParams).some((key: string) => (isArray(searchParams[key]) + ? !isEmpty(searchParams[key]) + : searchParams[key])) && ( + + )} + ); }; diff --git a/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules.tsx b/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules.tsx index 93256a8d3..bb3576705 100644 --- a/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules.tsx +++ b/web/packages/tca-analysis/src/modules/schemes/code-lint/all-rules.tsx @@ -24,6 +24,7 @@ import { getRuleDetail, getAllCheckPackages, getLanguages, + getCheckTools, } from '@src/services/schemes'; import RuleDetail from '../../projects/issues/rule-detail'; @@ -45,6 +46,7 @@ const AllRules = () => { const [selectedKeys, setSelectedKeys] = useState([]); const [ruleDetailVsb, setRuleDetailVsb] = useState(false); const [ruleDetail, setRuleDetail] = useState({}); + const [checkTools, setCheckTools] = useState([]); const [allPkgs, setAllPkgs] = useState([]); const [languages, setLanguages] = useState([]); @@ -97,6 +99,12 @@ const AllRules = () => { useEffect(() => { getListData(); getAllPkgs(); + getCheckTools(orgSid, { + limit: 1000, + checkprofile_id: checkProfileId, + }).then((res: any) => { + setCheckTools(res.results || []); + }); (async () => { const resLanguages = await getLanguages(); @@ -151,6 +159,7 @@ const AllRules = () => { filters={{ allPkgs, languages, + checkTools, }} searchParams={cloneDeep(searchParams)} loading={loading} @@ -188,7 +197,7 @@ const AllRules = () => { > (

{ )} /> - + diff --git a/web/packages/tca-analysis/src/modules/schemes/code-lint/pkg-rules.tsx b/web/packages/tca-analysis/src/modules/schemes/code-lint/pkg-rules.tsx index 28586fc29..d3e6608f8 100644 --- a/web/packages/tca-analysis/src/modules/schemes/code-lint/pkg-rules.tsx +++ b/web/packages/tca-analysis/src/modules/schemes/code-lint/pkg-rules.tsx @@ -298,7 +298,7 @@ const PkgRules = () => { (

{ width="36%" dataIndex={['checkrule', 'rule_title']} /> + { checkrule_category: category = [], checkrule_language: language = [], severity = [], + checktool = [], } = filters as any; const initialValues = cloneDeep(searchParams); Object.entries(initialValues).forEach(([key, value]: [string, string]) => { if (numberParams.includes(key) && isString(value)) { - initialValues[key] = value.split(',').map((item: string) => toNumber(item)); + initialValues[key] = value + .split(',') + .map((item: string) => toNumber(item)); } if (arrayParams.includes(key) && isString(value)) { @@ -64,52 +67,66 @@ const Search = (props: SearchProps) => { }; return ( - - - value && onChange('severity', value.join(','))} - /> - - - value && onChange('checkrule_category', value.join(',')) - } - /> - - - value && onChange('checkrule_language', value.join(',')) - } - /> - - - onChange('checkrule_name', value)} - /> - - {Object.keys(searchParams).some((key: string) => ( - isArray(searchParams[key]) - ? !isEmpty(searchParams[key]) - : searchParams[key])) && ( - - )} - + + + value && onChange('severity', value.join(',')) + } + /> + + + value && onChange('checkrule_category', value.join(',')) + } + /> + + + value && onChange('checktool', value.join(',')) + } + /> + + + value && onChange('checkrule_language', value.join(',')) + } + /> + + + onChange('checkrule_name', value)} + /> + + {Object.keys(searchParams).some((key: string) => (isArray(searchParams[key]) + ? !isEmpty(searchParams[key]) + : searchParams[key])) && ( + + )} + ); }; diff --git a/web/packages/tca-analysis/src/modules/template/code-lint/all-rules-search.tsx b/web/packages/tca-analysis/src/modules/template/code-lint/all-rules-search.tsx index 0b1a880b9..3146b05c9 100644 --- a/web/packages/tca-analysis/src/modules/template/code-lint/all-rules-search.tsx +++ b/web/packages/tca-analysis/src/modules/template/code-lint/all-rules-search.tsx @@ -12,7 +12,7 @@ import SelectBorderless from '@src/components/select-borderless'; import Filter from '@src/components/filter'; import { SEVERITY } from '../../schemes/constants'; -const numberParams = ['checkpackage', 'severity', 'category']; +const numberParams = ['checkpackage', 'severity', 'category', 'checktool']; const arrayParams = ['language_name']; interface SearchProps { @@ -25,13 +25,15 @@ interface SearchProps { const Search = (props: SearchProps) => { const [form] = Form.useForm(); const { searchParams, loading, filters, callback } = props; - const { allPkgs = [], labels = [], languages = [] } = filters as any; + const { allPkgs = [], labels = [], languages = [], checkTools = [] } = filters as any; const initialValues = cloneDeep(searchParams); Object.entries(initialValues).forEach(([key, value]: [string, string]) => { if (numberParams.includes(key) && isString(value)) { - initialValues[key] = value.split(',').map((item: string) => toNumber(item)); + initialValues[key] = value + .split(',') + .map((item: string) => toNumber(item)); } if (arrayParams.includes(key) && isString(value)) { @@ -61,68 +63,85 @@ const Search = (props: SearchProps) => { }; return ( - - - value && onChange('checkpackage', value.join(','))} - /> - - - ({ - value: toNumber(key), - text: value, - }))} - onChange={(value: any) => value && onChange('severity', value.join(','))} - /> - - - value && onChange('category', value.join(','))} - /> - - - ({ - value: item.name, - text: item.display_name, - })) - } - onChange={(value: any) => value && onChange('language_name', value.join(','))} - /> - - - onChange('display_name', value)} - /> - - { - Object.keys(searchParams).some((key: string) => ( - isArray(searchParams[key]) - ? !isEmpty(searchParams[key]) - : searchParams[key])) && ( - - )} - + + + value && onChange('checkpackage', value.join(',')) + } + /> + + + ({ + value: toNumber(key), + text: value, + }))} + onChange={(value: any) => value && onChange('severity', value.join(',')) + } + /> + + + value && onChange('category', value.join(',')) + } + /> + + + ({ + value: item.id, + text: item.display_name, + }))} + onChange={(value: any) => value && onChange('checktool', value.join(',')) + } + /> + + + ({ + value: item.name, + text: item.display_name, + }))} + onChange={(value: any) => value && onChange('language_name', value.join(',')) + } + /> + + + onChange('real_name', value)} + /> + + {Object.keys(searchParams).some((key: string) => (isArray(searchParams[key]) + ? !isEmpty(searchParams[key]) + : searchParams[key])) && ( + + )} + ); }; diff --git a/web/packages/tca-analysis/src/modules/template/code-lint/all-rules.tsx b/web/packages/tca-analysis/src/modules/template/code-lint/all-rules.tsx index c9f72220c..116d26160 100644 --- a/web/packages/tca-analysis/src/modules/template/code-lint/all-rules.tsx +++ b/web/packages/tca-analysis/src/modules/template/code-lint/all-rules.tsx @@ -24,7 +24,7 @@ import { getRuleDetail, getAllCheckPackages, } from '@src/services/template'; -import { getLabels, getLanguages } from '@src/services/schemes'; +import { getLabels, getLanguages, getCheckTools } from '@src/services/schemes'; import RuleDetail from '../../projects/issues/rule-detail'; import Search from './all-rules-search'; @@ -44,6 +44,7 @@ const AllRules = () => { const [selectedKeys, setSelectedKeys] = useState([]); const [ruleDetailVsb, setRuleDetailVsb] = useState(false); const [ruleDetail, setRuleDetail] = useState({}); + const [checkTools, setCheckTools] = useState([]); const [allPkgs, setAllPkgs] = useState([]); const [labels, setLabels] = useState([]); @@ -61,6 +62,12 @@ const AllRules = () => { useEffect(() => { getListData(); getAllPkgs(); + getCheckTools(orgSid, { + limit: 1000, + checkprofile_id: checkProfileId, + }).then((res: any) => { + setCheckTools(res.results || []); + }); (async () => { const labels = await getLabels(); @@ -152,6 +159,7 @@ const AllRules = () => { allPkgs, labels, languages, + checkTools, }} searchParams={cloneDeep(searchParams)} loading={loading} @@ -189,7 +197,7 @@ const AllRules = () => { > (

{ )} /> - + diff --git a/web/packages/tca-analysis/src/modules/template/code-lint/pkg-rules.tsx b/web/packages/tca-analysis/src/modules/template/code-lint/pkg-rules.tsx index ee9248d54..a1fc2b59b 100644 --- a/web/packages/tca-analysis/src/modules/template/code-lint/pkg-rules.tsx +++ b/web/packages/tca-analysis/src/modules/template/code-lint/pkg-rules.tsx @@ -304,7 +304,7 @@ const PkgRules = () => { (

{ width="36%" dataIndex={['checkrule', 'rule_title']} /> + { checkrule_category: category = [], checkrule_language: language = [], severity = [], + checktool = [], } = filters as any; const initialValues = cloneDeep(searchParams); Object.entries(initialValues).forEach(([key, value]: [string, string]) => { if (numberParams.includes(key) && isString(value)) { - initialValues[key] = value.split(',').map((item: string) => toNumber(item)); + initialValues[key] = value + .split(',') + .map((item: string) => toNumber(item)); } if (arrayParams.includes(key) && isString(value)) { @@ -64,53 +67,66 @@ const Search = (props: SearchProps) => { }; return ( - - - value && onChange('severity', value.join(','))} - /> - - - value && onChange('checkrule_category', value.join(',')) - } - /> - - - value && onChange('checkrule_language', value.join(',')) - } - /> - - - onChange('checkrule_name', value)} - /> - - { - Object.keys(searchParams).some((key: string) => ( - isArray(searchParams[key]) - ? !isEmpty(searchParams[key]) - : searchParams[key])) && ( - - )} - + + + value && onChange('severity', value.join(',')) + } + /> + + + value && onChange('checkrule_category', value.join(',')) + } + /> + + + value && onChange('checktool', value.join(',')) + } + /> + + + value && onChange('checkrule_language', value.join(',')) + } + /> + + + onChange('checkrule_name', value)} + /> + + {Object.keys(searchParams).some((key: string) => (isArray(searchParams[key]) + ? !isEmpty(searchParams[key]) + : searchParams[key])) && ( + + )} + ); }; diff --git a/web/packages/tca-analysis/src/services/schemes.ts b/web/packages/tca-analysis/src/services/schemes.ts index cc10ff2b8..165c69db0 100644 --- a/web/packages/tca-analysis/src/services/schemes.ts +++ b/web/packages/tca-analysis/src/services/schemes.ts @@ -274,6 +274,17 @@ export const addRule = (orgSid: string, teamName: string, repoId: string | numbe */ export const getRuleDetail = (orgSid: string, teamName: string, repoId: string | number, schemeId: string | number, ruleId: number) => get(`${getMainBaseURL(orgSid, teamName)}/repos/${repoId}/schemes/${schemeId}/allrules/${ruleId}/`); +/** + * 代码检查 - 获取指定规则的详细信息 + * @param {*} toolName - 工具名称 + * @param {*} ruleRealName - 规则真实名称 + * @returns + */ +export const getRuleDetailByName = (toolName: string, ruleRealName: string) => get(`${MAIN_SERVER_API}/conf/checkrules/byname/}`, { + checktool_name: toolName, + checkrule_real_name: ruleRealName, +}); + // ============================================ 分析方案 - 代码度量 ============================================ /** @@ -412,3 +423,9 @@ export const importScanDir = (orgSid: string, teamName: string, repoId: number, * @returns */ export const getBranchs = (orgSid: string, teamName: string, repoId: number, schemeId: number, query: any) => get(`${getMainBaseURL(orgSid, teamName)}/repos/${repoId}/schemes/${schemeId}/branchs/`, query); + +/** + * 获取工具列表 + * @param {*} query + */ +export const getCheckTools = (orgId: string, query: any) => get(`${MAIN_SERVER_API}/orgs/${orgId}/checktools/`, query); diff --git a/web/packages/tca-analysis/src/utils/getRoutePath.ts b/web/packages/tca-analysis/src/utils/getRoutePath.ts index fce8010bc..5c56f41da 100644 --- a/web/packages/tca-analysis/src/utils/getRoutePath.ts +++ b/web/packages/tca-analysis/src/utils/getRoutePath.ts @@ -55,4 +55,13 @@ export const getSchemeRouter = ( export const getTmplRouter = (orgSid: string, teamName: string) => `${getBaseRouter(orgSid, teamName)}/template`; +/** + * 工具管理路由 + * @param orgSid + * @param teamName + * @param tab + * @returns + */ +export const getToolsRouter = (orgSid: string, toolId: number, tab: string) => `/t/${orgSid}/tools/${toolId}/${tab}`; + export const getTeamMemberRouter = (orgSid: string) => `/t/${orgSid}/members`; diff --git a/web/packages/tca-manage/public/locales/en-US/translation.json b/web/packages/tca-manage/public/locales/en-US/translation.json index 86cda91e1..f14058408 100644 --- a/web/packages/tca-manage/public/locales/en-US/translation.json +++ b/web/packages/tca-manage/public/locales/en-US/translation.json @@ -157,8 +157,6 @@ "任务列表": "任务列表", "批量编辑节点": "批量编辑节点", "批量配置工具": "批量配置工具", - "子任务": "子任务", - "执行任务列表": "执行任务列表", "已添加标签": "已添加标签", "展示名称": "展示名称", "展示名称为必填项": "展示名称为必填项", diff --git a/web/packages/tca-manage/public/locales/zh-CN/translation.json b/web/packages/tca-manage/public/locales/zh-CN/translation.json index 86cda91e1..f14058408 100644 --- a/web/packages/tca-manage/public/locales/zh-CN/translation.json +++ b/web/packages/tca-manage/public/locales/zh-CN/translation.json @@ -157,8 +157,6 @@ "任务列表": "任务列表", "批量编辑节点": "批量编辑节点", "批量配置工具": "批量配置工具", - "子任务": "子任务", - "执行任务列表": "执行任务列表", "已添加标签": "已添加标签", "展示名称": "展示名称", "展示名称为必填项": "展示名称为必填项", diff --git a/web/packages/tca-manage/src/plat/open/modules/nodes/node-table.tsx b/web/packages/tca-manage/src/plat/open/modules/nodes/node-table.tsx index 30f3be9b4..79edcf7cd 100644 --- a/web/packages/tca-manage/src/plat/open/modules/nodes/node-table.tsx +++ b/web/packages/tca-manage/src/plat/open/modules/nodes/node-table.tsx @@ -8,11 +8,12 @@ import Table from '@tencent/micro-frontend-shared/tdesign-component/table'; import { useURLParams, useFetch } from '@tencent/micro-frontend-shared/hooks'; import { formatDateTime } from '@tencent/micro-frontend-shared/util/time'; import NodeStatus from '@tencent/micro-frontend-shared/tdesign-component/node-status'; -import NodeTag from '@src/modules/components/node-tag'; // 项目内 import OrgInfo from '../components/org-info'; import { nodeAPI } from '@src/services/nodes'; +import NodeTag from '@src/modules/components/node-tag'; +import NodeTaskModal from '@src/modules/nodes/node-tasks-modal'; import { userAPI } from '../../api'; // 模块内 @@ -20,7 +21,6 @@ import { getNodeSearchFields } from './constants'; import NodeModal from './node-modal'; import MultiNodeModal from './multi-edit-node-modal'; import MultiProcessModal from './multi-edit-process-modal'; -import NodeTaskModal from './node-tasks-modal'; interface NodeTableProps { tagOptions: any[] diff --git a/web/packages/tca-manage/src/plat/open/modules/nodes/node-tasks-modal.tsx b/web/packages/tca-manage/src/plat/open/modules/nodes/node-tasks-modal.tsx deleted file mode 100644 index ef9c462be..000000000 --- a/web/packages/tca-manage/src/plat/open/modules/nodes/node-tasks-modal.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Table, Dialog, PageInfo, Tag } from 'tdesign-react'; -import { get } from 'lodash'; - -// 项目内 -import { t } from '@tencent/micro-frontend-shared/i18n'; -import { getNodeTask } from '@src/services/nodes'; -import { STATE_CHOICES } from '@src/modules/jobs/constants'; -import EllipsisTemplate from '@tencent/micro-frontend-shared/tdesign-component/ellipsis'; - -export const DEFAULT_PAGER = { - count: 0, - pageSize: 10, - currentPage: 1, -}; - -interface NodeTaskModalProps { - visible: boolean; - nodeId: string; - onCancel: () => void; -} - -const NodeTaskModal = ({ visible, nodeId, onCancel }: NodeTaskModalProps) => { - const [listData, setListData] = useState>([]); - const [loading, setLoading] = useState(false); - const [pager, setPager] = useState(DEFAULT_PAGER); - const { count, pageSize, currentPage } = pager; - - useEffect(() => { - if (visible && nodeId) { - getTaskList(DEFAULT_PAGER.currentPage, DEFAULT_PAGER.pageSize); - } - }, [nodeId]); - - const getTaskList = (page: number, pageSize: number) => { - setLoading(true); - getNodeTask(nodeId, { - limit: pageSize, - offset: (page - 1) * pageSize, - }).then((res: any) => { - setListData(res.results); - setPager({ - count: res.count, - pageSize, - currentPage: page, - }); - setLoading(false); - }); - }; - - const onChangePage = ({ current, pageSize }: PageInfo) => { - setLoading(true); - getTaskList(current, pageSize); - }; - - const columns = [ - { - colKey: 'job', - title: t('分析任务'), - width: 300, - cell: ({ row }: any) => (<> - - {get(row, ['project', 'scm_url'])} - -

- 分支:{get(row, ['project', 'branch'])} -
- ), - }, - { - colKey: 'task_name', - title: t('子任务'), - width: 100, - }, - { - colKey: 'state', - title: t('执行状态'), - width: 100, - cell: ({ row }: any) =>
{STATE_CHOICES[get(row, 'state')]}
, - }, - { - colKey: 'result_msg', - title: t('执行结果'), - width: 200, - cell: ({ row }: any) => ( - <> - {get(row, 'result_code') !== null && ( - - {get(row, 'result_code_msg')} - - )} - {get(row, 'result_msg') && ( -
{get(row, 'result_msg')}
- )} - - ), - }, - ]; - - return ( - - - - ); -}; - -export default NodeTaskModal;