11import React , { useEffect , useMemo , useState } from "react" ;
22// import { Field } from '@grafana/data';
3- import { CollapsableSection } from '@grafana/ui' ;
3+ import { useTheme2 , CollapsableSection , Icon } from '@grafana/ui' ;
44import { LogContextProps } from "./LogContextUI" ;
5- import { css } from "@emotion/css" ;
5+ import { css , cx } from "@emotion/css" ;
66import { QuickwitQuery } from 'LogContext/QueryBuilder' ;
77
88
@@ -21,24 +21,25 @@ const excludedFields = [
2121type FieldContingency = { [ value : string ] : {
2222 count : number , pinned : boolean , active ?: boolean
2323} } ;
24+ type Field = {
25+ name :string ,
26+ contingency : FieldContingency
27+ }
2428
2529
26- const lcAttributeItemStyle = css `
27- display : flex;
28- justify-content : space-between;
29- font-size : 0.8rem ;
30- padding-left : 10px ;
31- & [data-active = true ] {
32- background-color : rgba (127 , 127 , 255 , 0.1 );
33- }
34- & : hover {
35- background-color : rgba (255 , 255 , 255 , 0.1 );
36- background-opacity : 0.2 ;
37- }
38- ` ;
3930
31+ function LogContextFieldSection ( field : Field ) {
32+ const theme = useTheme2 ( )
33+ const hasActiveFilters = Object . entries ( field . contingency ) . map ( ( [ _ , entry ] ) => ! ! entry . active ) . reduce ( ( a , b ) => a || b , false ) ;
34+ return (
35+ < span className = { css ( { fontSize :theme . typography . body . fontSize , display :"flex" , alignItems : "baseline" , gap :"0.5rem" , width :"100%" } ) } >
36+ { hasActiveFilters && < Icon name = { "filter" } className = { css ( { color :theme . colors . primary . text } ) } /> }
37+ < span > { field . name } </ span >
38+ </ span >
39+ )
40+ }
4041
41- type AttrbuteItemsProps = {
42+ type FieldItemProps = {
4243 label : string ,
4344 contingency : {
4445 count : number ,
@@ -47,11 +48,25 @@ type AttrbuteItemsProps = {
4748 active ?: boolean ,
4849 onClick : ( ) => void
4950}
50- function LogContextAttributeItem ( props : AttrbuteItemsProps ) {
51+ function LogContextFieldItem ( props : FieldItemProps ) {
52+ const theme = useTheme2 ( )
53+ const lcAttributeItemStyle = css ( {
54+ display : "flex" ,
55+ justifyContent : "space-between" ,
56+ paddingLeft : "10px" ,
57+ fontSize : theme . typography . bodySmall . fontSize ,
58+ "&[data-active=true]" : {
59+ backgroundColor : theme . colors . primary . transparent ,
60+ } ,
61+ "&:hover" : {
62+ backgroundColor : theme . colors . secondary . shade ,
63+ }
64+ } ) ;
65+
5166 return (
5267 < a className = { lcAttributeItemStyle } onClick = { props . onClick } data-active = { props . active } >
5368 < span className = { css `text-overflow : ellipsis; min-width : 0 ; flex : 0 1 ` } > { props . label } </ span >
54- < span className = { css `flex-grow:0` } > { props . contingency . pinned && "* " } { props . contingency . count } </ span >
69+ < span className = { css `flex-grow:0` } > { props . contingency . pinned && < Icon name = { "crosshair" } /> } { props . contingency . count } </ span >
5570 </ a >
5671 )
5772}
@@ -72,7 +87,7 @@ type QueryBuilderProps = {
7287export function LogContextQueryBuilderSidebar ( props : LogContextProps & QueryBuilderProps ) {
7388
7489 const { row, parsedQuery, updateQuery} = props ;
75- const [ fields , setFields ] = useState < Array < { name : string ; contingency : FieldContingency ; } > > ( [ ] ) ;
90+ const [ fields , setFields ] = useState < Array < Field > > ( [ ] ) ;
7691
7792
7893 const filteredFields = useMemo ( ( ) => (
@@ -88,7 +103,7 @@ export function LogContextQueryBuilderSidebar(props: LogContextProps & QueryBuil
88103 const fields = filteredFields
89104 . map ( ( f ) => {
90105 const contingency : FieldContingency = { } ;
91- f . values . toArray ( ) . forEach ( ( attrName , i ) => {
106+ f . values . forEach ( ( attrName , i ) => {
92107 if ( ! contingency [ attrName ] ) {
93108 contingency [ attrName ] = {
94109 count : 0 ,
@@ -115,23 +130,34 @@ export function LogContextQueryBuilderSidebar(props: LogContextProps & QueryBuil
115130 }
116131 }
117132
133+ const renderFieldSection = ( field :Field ) => {
134+ return (
135+ < CollapsableSection
136+ label = { LogContextFieldSection ( field ) }
137+ className = { css `& > div { flex-grow : 1 ; }` }
138+ isOpen = { false } key = "log-attribute-field-{field.name}"
139+ contentClassName = { cx ( css `margin : 0 ; padding : 0 ` ) } >
140+ < div className = { css `display:flex; flex-direction : column; gap : 5px ` } >
141+
142+ { field . contingency && Object . entries ( field . contingency ) . map ( ( [ fieldValue , contingency ] , i ) => (
143+
144+ < LogContextFieldItem
145+ label = { fieldValue } contingency = { contingency } key = { `field-opt${ i } ` }
146+ onClick = { ( ) => { selectQueryFilter ( field . name , fieldValue ) } }
147+ active = { contingency . active }
148+ />
149+ ) ) }
150+ </ div >
151+ </ CollapsableSection >
152+ )
153+ }
154+
155+
118156 return (
119157 < div className = { lcSidebarStyle } >
120- { fields && fields . map ( ( field ) => (
121- < CollapsableSection label = { ( < h6 > { field . name } </ h6 > ) } isOpen = { false } key = "log-attribute-field-{field.name}" contentClassName = { css `margin : 0 ; padding : 0 ` } >
122- < div className = { css `display:flex; flex-direction : column; gap : 5px ` } >
123-
124- { field . contingency && Object . entries ( field . contingency ) . map ( ( [ fieldValue , contingency ] , i ) => (
125-
126- < LogContextAttributeItem
127- label = { fieldValue } contingency = { contingency } key = { `field-opt${ i } ` }
128- onClick = { ( ) => { selectQueryFilter ( field . name , fieldValue ) } }
129- active = { contingency . active }
130- />
131- ) ) }
132- </ div >
133- </ CollapsableSection >
134- ) ) }
135- </ div >
158+ { fields && fields . map ( ( field ) => {
159+
160+ return ( renderFieldSection ( field ) ) ;
161+ } ) } </ div >
136162 ) ;
137163}
0 commit comments