diff --git a/app/protos/grpc.proto b/app/protos/grpc.proto index 600d7c9081..649ded3b07 100644 --- a/app/protos/grpc.proto +++ b/app/protos/grpc.proto @@ -1975,10 +1975,22 @@ message YaklangInspectInformationRequest { message YaklangLanguageSuggestionRequest { string InspectType = 1;// completion(补全) / hover(提示) / signature(签名) / definition(找定义) / reference(找引用) + + // { + // from source code : support all InspectType string YakScriptType = 2; string YakScriptCode = 3; - Range Range = 4; - string ModelID = 5; + // } + + Range Range = 4; // selected range + string ModelID = 5; // monaco model id + + // { + // from database : support getReference + // if set this progranName will use this from database + string ProgramName = 6; + string FileName = 7; + // } } diff --git a/app/renderer/src/main/src/pages/YakRunner/AuditCode/AuditCode.tsx b/app/renderer/src/main/src/pages/YakRunner/AuditCode/AuditCode.tsx index 91907930a2..006373299c 100644 --- a/app/renderer/src/main/src/pages/YakRunner/AuditCode/AuditCode.tsx +++ b/app/renderer/src/main/src/pages/YakRunner/AuditCode/AuditCode.tsx @@ -168,7 +168,7 @@ export const AuditTreeNode: React.FC = memo((props) => { {getDetail && ( - +
{`${getDetail.fileName}:${getDetail.start_line}`}
diff --git a/app/renderer/src/main/src/pages/YakRunner/CollapseList/CollapseList.tsx b/app/renderer/src/main/src/pages/YakRunner/CollapseList/CollapseList.tsx index e150d804a1..8a822c349e 100644 --- a/app/renderer/src/main/src/pages/YakRunner/CollapseList/CollapseList.tsx +++ b/app/renderer/src/main/src/pages/YakRunner/CollapseList/CollapseList.tsx @@ -23,7 +23,7 @@ const {ipcRenderer} = window.require("electron") const {Panel} = Collapse export const CollapseList: (props: CollapseListProp) => ReactElement | null = memo((props) => { - const {type = "sideBar", onlyKey, list, titleRender, renderItem, collapseProps, isShowBottom} = props + const {type = "sideBar", panelKey, onlyKey = "", list, titleRender, renderItem, collapseProps, isShowBottom} = props const wrapperClassName = useMemo(() => { if (type === "sideBar") return styles["collapse-list-side-bar"] @@ -48,7 +48,10 @@ export const CollapseList: (props: CollapseListProp) => ReactElement | nul > {list.map((item, index) => { return ( - +
{ /** @@ -9,7 +9,8 @@ export interface CollapseListProp { * @default sideBar */ type?: "sideBar" | "output" - onlyKey: string + panelKey?: string + onlyKey?: string list: T[] titleRender: (info: T) => ReactNode renderItem: (info: T) => ReactNode diff --git a/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/GraphInfoMap.ts b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/GraphInfoMap.ts new file mode 100644 index 0000000000..2b0c78ebbc --- /dev/null +++ b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/GraphInfoMap.ts @@ -0,0 +1,33 @@ +import {v4 as uuidv4} from "uuid" +import { GraphInfoProps } from "./RightAuditDetail" +export const GraphInfoMap: Map = new Map() + +export const setMapGraphInfoDetail = (nodeId: string, info: GraphInfoProps) => { + GraphInfoMap.set(nodeId, info) +} + +export const getMapGraphInfoDetail = (nodeId: string) => { + return ( + GraphInfoMap.get(nodeId) + ) +} + +export const getMapAllGraphInfoValue = () => { + return Array.from(GraphInfoMap.values()) +} + +export const getMapAllGraphInfoKey = () => { + return Array.from(GraphInfoMap.keys()) +} + +export const getMapAllGraphInfoSize = () => { + return GraphInfoMap.size +} + +export const clearMapGraphInfoDetail = () => { + GraphInfoMap.clear() +} + +export const removeMapGraphInfoDetail = (nodeId: string) => { + GraphInfoMap.delete(nodeId) +} \ No newline at end of file diff --git a/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.module.scss b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.module.scss index 7f6546b5f0..37984fd8cf 100644 --- a/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.module.scss +++ b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.module.scss @@ -28,40 +28,83 @@ align-items: center; gap: 4px; } + .extra { + display: flex; + flex-direction: row; + gap: 4px; + } } } } .main { flex: 1; overflow: hidden; - .content { + .audit-result-box { height: 100%; overflow: auto; - padding: 12px; display: flex; flex-direction: column; gap: 8px; - .url-box { - color: rgb(136, 99, 247); - font-size: 12px; - font-weight: 400; - line-height: 16px; - &:hover { - cursor: pointer; - text-decoration: underline; - } - } .message-box { color: #31343f; font-size: 12px; font-weight: 400; line-height: 18px; } - .ir-code-box { - padding: 8px; - border-radius: 4px; - background: #f0f1f3; - overflow: auto; + .title-render { + color: #31343f; + font-size: 12px; + font-weight: 600; + line-height: 16px; + } + + .audit-result-item { + .result-render { + width: 100%; + overflow: hidden; + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 8px; + .title { + color: #31343f; + font-size: 12px; + font-weight: 500; + line-height: 16px; + overflow: hidden; + flex: 1; + } + .url-box { + width: 60px; + text-align: right; + color: #f28b44; + font-size: 12px; + font-weight: 400; + line-height: 16px; + overflow: hidden; + &:hover { + text-decoration: underline; + } + } + .active-url-box{ + color: rgb(136, 99, 247); + } + } + .ir-code-box { + padding: 8px; + border-radius: 4px; + background: #f0f1f3; + white-space: pre; + overflow: auto; + } + :global { + .ant-collapse-item > .ant-collapse-header { + padding: 3px 0px 3px 0px !important; + } + .ant-collapse-header-text{ + flex: 1; + } + } } } } @@ -130,7 +173,7 @@ width: 100%; display: flex; flex-direction: column; - border-top: 1px solid #EAECF3; + border-top: 1px solid #eaecf3; .header { display: flex; flex-direction: row; @@ -141,6 +184,8 @@ flex: 1; display: flex; flex-direction: column; + padding: 0px 12px 12px; + gap: 8px; .url-box { color: #f28b44; font-size: 12px; diff --git a/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.tsx b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.tsx index 7dd6c04af3..b01584239e 100644 --- a/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.tsx +++ b/app/renderer/src/main/src/pages/YakRunner/RightAuditDetail/RightAuditDetail.tsx @@ -5,7 +5,13 @@ import {useMemoizedFn, useThrottleFn, useUpdate, useUpdateEffect} from "ahooks" import {AuditEmiterYakUrlProps, OpenFileByPathProps} from "../YakRunnerType" import {StringToUint8Array} from "@/utils/str" import {getNameByPath, loadAuditFromYakURLRaw} from "../utils" -import {OutlineHandIcon, OutlineXIcon, OutlineZoominIcon, OutlineZoomoutIcon} from "@/assets/icon/outline" +import { + OutlineCollectionIcon, + OutlineHandIcon, + OutlineXIcon, + OutlineZoominIcon, + OutlineZoomoutIcon +} from "@/assets/icon/outline" import {YakitResizeBox} from "@/components/yakitUI/YakitResizeBox/YakitResizeBox" import {YakitButton} from "@/components/yakitUI/YakitButton/YakitButton" import {Tooltip} from "antd" @@ -14,15 +20,167 @@ import {failed} from "@/utils/notification" import emiter from "@/utils/eventBus/eventBus" import {JumpToEditorProps} from "../BottomEditorDetails/BottomEditorDetailsType" import {QuestionMarkCircleIcon} from "@/assets/newIcon" +import {clearMapGraphInfoDetail, getMapGraphInfoDetail, setMapGraphInfoDetail} from "./GraphInfoMap" +import {CollapseList} from "../CollapseList/CollapseList" + +interface AuditResultItemProps { + onDetail: (data: CodeRangeProps) => void + nodeId?: string + data: GraphInfoProps[] + title: string + resultKey?: string | string[] + setResultKey: (v: string | string[]) => void +} + +export const AuditResultItem: React.FC = (props) => { + const {onDetail, nodeId, data, title, resultKey,setResultKey} = props + + const titleRender = (info: GraphInfoProps) => { + const {ir_code, code_range, node_id} = info + const lastSlashIndex = code_range.url.lastIndexOf("/") + const fileName = code_range.url.substring(lastSlashIndex + 1) + return ( +
+
{ir_code}
+ +
{ + e.stopPropagation() + onDetail(code_range) + }} + > + {fileName}:{code_range.start_line} +
+
+
+ ) + } + + const renderItem = (info: GraphInfoProps) => { + return
{info.source_code}
+ } + + return ( +
+ { + setResultKey(v) + } + }} + /> +
+ ) +} + +interface AuditResultBoxProps { + onDetail: (data: CodeRangeProps) => void + nodeId?: string + graphLine?: string[][] + message: string + activeKey?: string | string[] + setActiveKey: (v: string | string[]) => void +} + +interface InitDataProps { + title: string + children: GraphInfoProps[] + nodeId?: string +} + +export const AuditResultBox: React.FC = (props) => { + const {onDetail, nodeId, graphLine, message, activeKey, setActiveKey} = props + const [resultKey, setResultKey] = useState() + + useUpdateEffect(()=>{ + if(activeKey === undefined){ + setResultKey(undefined) + } + },[activeKey]) + + const getChildren = useMemoizedFn((data: string[]) => { + const children = data + .map((itemIn) => { + const detail = getMapGraphInfoDetail(itemIn) + if (detail) { + return { + ...detail + } + } + return + }) + .filter((item) => item !== undefined) as GraphInfoProps[] + return children + }) + + const initData: InitDataProps[] = useMemo(() => { + if (graphLine) { + return graphLine.map((item, index) => { + return { + title: `路径${index + 1}`, + children: getChildren(item) + } + }) + } + return [] + }, [graphLine]) + + const titleRender = (info: InitDataProps) => { + return
{info.title}
+ } + + const renderItem = (info: InitDataProps) => { + return ( + + ) + } + + return ( +
+ {message &&
{message}
} + {/* 以下为折叠面板 */} + { + setActiveKey(v) + } + }} + /> +
+ ) +} + interface FlowChartBoxProps { onDetail: (data: CodeRangeProps) => void graph?: string - graphInfo?: GraphInfoProps[] + refresh: boolean node_id?: string } export const FlowChartBox: React.FC = (props) => { - const {onDetail, graph, graphInfo, node_id} = props + const {onDetail, graph, refresh, node_id} = props const svgBoxRef = useRef(null) const svgRef = useRef(null) const [nodeId, setNodeId] = useState() @@ -105,7 +263,7 @@ export const FlowChartBox: React.FC = (props) => { } }) - const onRefreshAuditDetailFun = useMemoizedFn(()=>{ + const onRefreshAuditDetailFun = useMemoizedFn(() => { setNodeId(undefined) }) @@ -138,13 +296,11 @@ export const FlowChartBox: React.FC = (props) => { }, [graph]) const contentInfo = useMemo(() => { - if (graphInfo && nodeId) { - const arr = graphInfo.filter((item) => item.node_id === nodeId) - if (arr.length > 0) { - return arr[0] - } + if (nodeId) { + const result = getMapGraphInfoDetail(nodeId) + return result } - }, [graphInfo, nodeId]) + }, [refresh, nodeId]) const firstOffsetRef = useRef<{x: number; y: number}>() const [scale, setScale] = useState(1) // 初始缩放比例为1 @@ -232,7 +388,7 @@ export const FlowChartBox: React.FC = (props) => {
= (props) => { const {auditRightParams, isShowAuditDetail, setShowAuditDetail} = props const [graph, setGraph] = useState() - const [graphInfo, setGraphInfo] = useState() + const [graphLine, setGraphLine] = useState() const [message, setMessage] = useState("") const [nodeId, setNodeId] = useState() + const [refresh, setRefresh] = useState(false) + const [activeKey, setActiveKey] = useState() useEffect(() => { if (isShowAuditDetail && auditRightParams) { @@ -308,6 +467,8 @@ export const RightAuditDetail: React.FC = (props) => { }, [isShowAuditDetail, auditRightParams]) const initData = useMemoizedFn(async (params: AuditEmiterYakUrlProps) => { + clearMapGraphInfoDetail() + setActiveKey(undefined) const {Schema, Location, Path, Body} = params const body = StringToUint8Array(Body) const result = await loadAuditFromYakURLRaw({Schema, Location, Path}, body) @@ -319,8 +480,10 @@ export const RightAuditDetail: React.FC = (props) => { } if (item.Key === "graph_info") { try { - let graph_info = JSON.parse(item.Value) - setGraphInfo(graph_info) + let graph_info: GraphInfoProps[] = JSON.parse(item.Value) + graph_info.forEach((item) => { + setMapGraphInfoDetail(item.node_id, item) + }) } catch (error) {} } if (item.Key === "message") { @@ -329,19 +492,17 @@ export const RightAuditDetail: React.FC = (props) => { if (item.Key === "node_id") { setNodeId(item.Value) } + if (item.Key === "graph_line") { + try { + let graph_info = JSON.parse(item.Value) + setGraphLine(graph_info) + } catch (error) {} + } }) + setRefresh(!refresh) } }) - const contentInfo = useMemo(() => { - if (graphInfo && nodeId) { - const arr = graphInfo.filter((item) => item.node_id === nodeId) - if (arr.length > 0) { - return arr[0] - } - } - }, [graphInfo, nodeId]) - // 跳转详情 const onDetail = useMemoizedFn(async (data: CodeRangeProps) => { const {url, start_line, start_column, end_line, end_column} = data @@ -359,6 +520,8 @@ export const RightAuditDetail: React.FC = (props) => { highLightRange } } + console.log("跳转详情",OpenFileByPathParams); + emiter.emit("onOpenFileByPath", JSON.stringify(OpenFileByPathParams)) // 纯跳转行号 setTimeout(() => { @@ -378,6 +541,14 @@ export const RightAuditDetail: React.FC = (props) => {
审计结果
+ } + disabled={(graphLine || []).length === 0} + onClick={() => { + setActiveKey(undefined) + }} + /> } @@ -400,24 +571,16 @@ export const RightAuditDetail: React.FC = (props) => { secondNodeStyle={{padding: 0}} secondMinSize={350} firstNode={ -
- {contentInfo && ( - -
onDetail(contentInfo.code_range)} - > - {contentInfo.code_range.url} -
-
- )} - {message &&
{message}
} - {contentInfo &&
{contentInfo?.ir_code}
} -
- } - secondNode={ - + } + secondNode={} />
diff --git a/app/renderer/src/main/src/pages/YakRunner/RunnerTabs/RunnerTabs.tsx b/app/renderer/src/main/src/pages/YakRunner/RunnerTabs/RunnerTabs.tsx index 99684056a7..92a5ba3c61 100644 --- a/app/renderer/src/main/src/pages/YakRunner/RunnerTabs/RunnerTabs.tsx +++ b/app/renderer/src/main/src/pages/YakRunner/RunnerTabs/RunnerTabs.tsx @@ -949,8 +949,14 @@ const RunnerTabPane: React.FC = memo((props) => { item.elements.forEach((itemIn) => { if (itemIn.id === tabsId) { itemIn.files.forEach((file) => { - // 仅初次进入 或切换时更新详情 - if (file.isActive && (!editorInfo || (editorInfo && editorInfo.path !== file.path))) { + // 仅初次进入 或(切换/更新高亮显示区域)时更新详情 + if ( + file.isActive && + (!editorInfo || + (editorInfo && editorInfo.path !== file.path) || + (editorInfo && + JSON.stringify(editorInfo.highLightRange) !== JSON.stringify(file.highLightRange))) + ) { // 更新编辑器展示项 setEditorInfo(file) setAllowBinary(false) @@ -1126,9 +1132,9 @@ const RunnerTabPane: React.FC = memo((props) => { const onJumpEditorDetailFun = useMemoizedFn((data) => { try { const obj: JumpToEditorProps = JSON.parse(data) - const {id,isSelect = true, selections} = obj + const {id, isSelect = true, selections} = obj if (reqEditor && editorInfo?.path === id) { - if(isSelect){ + if (isSelect) { reqEditor.setSelection(selections) } reqEditor.revealLineInCenter(selections.startLineNumber) @@ -1179,7 +1185,7 @@ const RunnerTabPane: React.FC = memo((props) => { updateAreaInputInfo(content) }} highLightText={editorInfo?.highLightRange ? [editorInfo?.highLightRange] : undefined} - highLightClass="hight-light-yak-runner-color" + highLightClass='hight-light-yak-runner-color' /> )}