diff --git a/admin/src/components/molecules/DAGDefinition.tsx b/admin/src/components/molecules/DAGDefinition.tsx index 676ddaa30..cc2a7e813 100644 --- a/admin/src/components/molecules/DAGDefinition.tsx +++ b/admin/src/components/molecules/DAGDefinition.tsx @@ -4,6 +4,7 @@ import Prism from '../../assets/js/prism'; type Props = { value: string; lineNumbers?: boolean; + highlightLine?: number; startLine?: number; keyword?: string; noHighlight?: boolean; @@ -14,6 +15,7 @@ const language = 'yaml'; function DAGDefinition({ value, lineNumbers, + highlightLine, startLine, keyword, noHighlight, @@ -34,12 +36,7 @@ function DAGDefinition({ return classes.join(' '); }, [lineNumbers, keyword]); return ( -
+); diff --git a/admin/src/components/molecules/SearchResult.tsx b/admin/src/components/molecules/SearchResult.tsx index fb53b39bb..bbf6a428b 100644 --- a/admin/src/components/molecules/SearchResult.tsx +++ b/admin/src/components/molecules/SearchResult.tsx @@ -12,28 +12,31 @@ type Props = { function SearchResult({ results }: Props) { const elements = React.useMemo( () => - results.map((result) => { - const keys = Object.keys(result.Matched); + results.map((result, i) => { const ret = [] as ReactElement[]; - keys.forEach((k, i) => { - const m = result.Matched[k]; + result.Matches.forEach((m, j) => { ret.push( -{value}
+ ); }); + if (i < results.length - 1) { + ret.push( - - {result.Name} - + {j == 0 ? ( + +{result.Name} + + ) : null}); + } return ret; }), [results] diff --git a/admin/src/models/api.ts b/admin/src/models/api.ts index 8d27a5a66..ee5f11ce9 100644 --- a/admin/src/models/api.ts +++ b/admin/src/models/api.ts @@ -21,11 +21,13 @@ export type GetSearchResponse = { export type SearchResult = { Name: string; DAG?: DAG; - Matched: Matched; + Matches: Match[]; }; -export type Matched = { - [key: string]: string; +export type Match = { + Line: string; + LineNumber: number; + StartLine: number; }; export type LogData = { diff --git a/admin/src/pages/search/index.tsx b/admin/src/pages/search/index.tsx index 953135284..3ff8c1ef1 100644 --- a/admin/src/pages/search/index.tsx +++ b/admin/src/pages/search/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef } from 'react'; -import { Box, Button, Grid, Stack, TextField } from '@mui/material'; +import { Box, Button, Grid, Stack, TextField, Typography } from '@mui/material'; import useSWR from 'swr'; import { useSearchParams } from 'react-router-dom'; import Title from '../../components/atoms/Title'; @@ -12,7 +12,7 @@ function Search() { const [searchVal, setSearchVal] = React.useState(searchParams.get('q') || ''); const { data, error } = useSWR ( - `/search?q=${searchParams.get('q')}` + `/search?q=${searchParams.get('q') || ''}` ); const ref = useRef (null); @@ -74,7 +74,12 @@ function Search() { No results found ) : null} {data && data.Results.length > 0 ? ( -+ + ) : null} diff --git a/admin/src/styles/styles.css b/admin/src/styles/styles.css index 85ebb9159..bfcacb060 100644 --- a/admin/src/styles/styles.css +++ b/admin/src/styles/styles.css @@ -32,3 +32,8 @@ a { .MuiTableRow-root td { font-weight: 600; } + +.line-highlight { + margin-top: 1.4em !important; + background-color: rgba(255,255,0,0.2) !important; +} \ No newline at end of file diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 4abbb9590..0cc951d39 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -64,7 +64,7 @@ func GetDAGs(dir string) (dags []*DAGStatus, errs []string, err error) { type GrepResult struct { Name string DAG *dag.DAG - Matched map[int]string + Matches []*grep.Match } // GrepDAGs returns all DAGs that contain the given string. @@ -81,6 +81,8 @@ func GrepDAGs(dir string, pattern string) (ret []*GrepResult, errs []string, err dl := &dag.Loader{} opts := &grep.Options{ IsRegexp: true, + Before: 2, + After: 2, } utils.LogErr("read DAGs directory", err) for _, fi := range fis { @@ -102,7 +104,7 @@ func GrepDAGs(dir string, pattern string) (ret []*GrepResult, errs []string, err ret = append(ret, &GrepResult{ Name: strings.TrimSuffix(fi.Name(), path.Ext(fi.Name())), DAG: dag, - Matched: m, + Matches: m, }) } } diff --git a/internal/grep/grep.go b/internal/grep/grep.go index 5aa5f88a5..3d65fb26c 100644 --- a/internal/grep/grep.go +++ b/internal/grep/grep.go @@ -27,10 +27,17 @@ type Options struct { After int } +// Match contains matched line number and line content. +type Match struct { + Line string + LineNumber int + StartLine int +} + // Grep read file and return matched lines. // If opts is nil, default options will be used. // The result is a map, key is line number, value is line content. -func Grep(file string, pattern string, opts *Options) (map[int]string, error) { +func Grep(file string, pattern string, opts *Options) ([]*Match, error) { b, err := os.ReadFile(file) if err != nil { return nil, err @@ -48,7 +55,7 @@ func Grep(file string, pattern string, opts *Options) (map[int]string, error) { } } scanner := bufio.NewScanner(bytes.NewReader(b)) - ret := map[int]string{} + ret := []*Match{} lines := []string{} matched := []int{} i := 0 @@ -73,7 +80,11 @@ func Grep(file string, pattern string, opts *Options) (map[int]string, error) { l := lo.Max([]int{0, m - opts.Before}) h := lo.Min([]int{len(lines), m + opts.After + 1}) s := strings.Join(lines[l:h], "\n") - ret[m+1] = s + ret = append(ret, &Match{ + StartLine: l + 1, + LineNumber: m + 1, + Line: s, + }) } return ret, nil } diff --git a/internal/grep/grep_test.go b/internal/grep/grep_test.go index df38d7e36..76b4d2ce7 100644 --- a/internal/grep/grep_test.go +++ b/internal/grep/grep_test.go @@ -15,14 +15,19 @@ func TestGrep(t *testing.T) { File string Pattern string Opts *Options - Want map[int]string + Want []*Match IsErr bool }{ { Name: "simple", File: path.Join(dir, "test.txt"), Pattern: "b", - Want: map[int]string{2: "bb"}, + Want: []*Match{ + { + LineNumber: 2, + StartLine: 2, + Line: "bb", + }}, }, { Name: "regexp", @@ -31,7 +36,12 @@ func TestGrep(t *testing.T) { Opts: &Options{ IsRegexp: true, }, - Want: map[int]string{2: "bb"}, + Want: []*Match{ + { + LineNumber: 2, + StartLine: 2, + Line: "bb", + }}, }, { Name: "before", @@ -40,7 +50,12 @@ func TestGrep(t *testing.T) { Opts: &Options{ Before: 1, }, - Want: map[int]string{2: "aa\nbb"}, + Want: []*Match{ + { + LineNumber: 2, + StartLine: 1, + Line: "aa\nbb", + }}, }, { Name: "before+after", @@ -50,7 +65,12 @@ func TestGrep(t *testing.T) { Before: 2, After: 2, }, - Want: map[int]string{3: "aa\nbb\ncc\ndd\nee"}, + Want: []*Match{ + { + LineNumber: 3, + StartLine: 1, + Line: "aa\nbb\ncc\ndd\nee", + }}, }, { Name: "before+after,firstline", @@ -60,7 +80,12 @@ func TestGrep(t *testing.T) { Before: 1, After: 1, }, - Want: map[int]string{1: "aa\nbb"}, + Want: []*Match{ + { + LineNumber: 1, + StartLine: 1, + Line: "aa\nbb", + }}, }, { Name: "before+after,lastline", @@ -70,7 +95,12 @@ func TestGrep(t *testing.T) { Before: 1, After: 1, }, - Want: map[int]string{5: "dd\nee"}, + Want: []*Match{ + { + LineNumber: 5, + StartLine: 4, + Line: "dd\nee", + }}, }, { Name: "no match",+ {data.Results.length} results found + ++