diff options
Diffstat (limited to 'src/client/views/FilterPanel.tsx')
-rw-r--r-- | src/client/views/FilterPanel.tsx | 173 |
1 files changed, 88 insertions, 85 deletions
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 0521c4a4b..c97edd7f0 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -1,19 +1,22 @@ +/* eslint-disable react/jsx-props-no-spreading */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, makeObservable, observable, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai'; import { CiCircleRemove } from 'react-icons/ci'; -import { Doc, DocListCast, Field, LinkedTo, StrListCast } from '../../fields/Doc'; +import { Doc, DocListCast, Field, FieldType, LinkedTo, StrListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; -import { DocumentManager } from '../util/DocumentManager'; import { SearchUtil } from '../util/SearchUtil'; -import { SettingsManager } from '../util/SettingsManager'; +import { SnappingManager } from '../util/SnappingManager'; import { undoable } from '../util/UndoManager'; import { FieldsDropdown } from './FieldsDropdown'; import './FilterPanel.scss'; +import { DocumentView } from './nodes/DocumentView'; import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components'; import { ObservableReactComponent } from './ObservableReactComponent'; @@ -37,7 +40,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { return this._props.Document; } @computed get targetDocChildKey() { - const targetView = DocumentManager.Instance.getFirstDocumentView(this.Document); + const targetView = DocumentView.getFirstDocumentView(this.Document); return targetView?.ComponentView?.annotationKey ?? targetView?.ComponentView?.fieldKey ?? 'data'; } @computed get targetDocChildren() { @@ -58,7 +61,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { @computed get mapActiveFiltersToFacets() { const filters = new Map<string, string>(); - //this.targetDoc.docFilters + // this.targetDoc.docFilters this.activeFilters.map(filter => filters.set(filter.split(Doc.FilterSep)[1], filter.split(Doc.FilterSep)[0])); return filters; } @@ -73,7 +76,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { // ["#tags", "width", "height"] // @computed get activeFacetHeaders() { - const activeHeaders = new Array(); + const activeHeaders = [] as string[]; this.activeFilters.map(filter => activeHeaders.push(filter.split(Doc.FilterSep)[0])); return activeHeaders; @@ -83,19 +86,20 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { const valueSet = new Set<string>(childFilters.map(filter => filter.split(Doc.FilterSep)[1])); let rtFields = 0; let subDocs = childDocs; - let gatheredDocs = [] as Doc[]; + const gatheredDocs = [] as Doc[]; if (subDocs.length > 0) { let newarray: Doc[] = []; while (subDocs.length > 0) { newarray = []; + // eslint-disable-next-line no-loop-func subDocs.forEach(t => { gatheredDocs.push(t); const facetVal = t[facetKey]; if (facetVal instanceof RichTextField || typeof facetVal === 'string') rtFields++; - facetVal !== undefined && valueSet.add(Field.toString(facetVal as Field)); - (facetVal === true || facetVal == false) && valueSet.add(Field.toString(!facetVal)); + facetVal !== undefined && valueSet.add(Field.toString(facetVal as FieldType)); + (facetVal === true || facetVal === false) && valueSet.add(Field.toString(!facetVal)); const fieldKey = Doc.LayoutFieldKey(t); - const annos = !Field.toString(Doc.LayoutField(t) as Field).includes('CollectionView'); + const annos = !Field.toString(Doc.LayoutField(t) as FieldType).includes('CollectionView'); DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc)); }); @@ -115,7 +119,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { // @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>(); @observable _chosenFacetsCollapse = new ObservableMap<string, boolean>(); - @observable _collapseReturnKeys = new Array(); + @observable _collapseReturnKeys = [] as string[]; // this computed function gets the active filters and maps them to their headers // @@ -130,11 +134,11 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { const facetValues = FilterPanel.gatherFieldValues(this.targetDocChildren, facetHeader, StrListCast(this.Document.childFilters)); let nonNumbers = 0; - let minVal = Number.MAX_VALUE, - maxVal = -Number.MAX_VALUE; - facetValues.strings.map(val => { + let minVal = Number.MAX_VALUE; + let maxVal = -Number.MAX_VALUE; + facetValues.strings.forEach(val => { const num = val ? Number(val) : Number.NaN; - if (Number.isNaN(num)) { + if (isNaN(num)) { val && nonNumbers++; } else { minVal = Math.min(num, minVal); @@ -144,14 +148,14 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { if (facetHeader === 'text') { return { facetHeader, renderType: 'text' }; - } else if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) { + } + if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) { const extendedMinVal = minVal - Math.min(1, Math.floor(Math.abs(maxVal - minVal) * 0.1)); const extendedMaxVal = Math.max(minVal + 1, maxVal + Math.min(1, Math.ceil(Math.abs(maxVal - minVal) * 0.05))); - const ranged = Doc.readDocRangeFilter(this.Document, facetHeader); // not the filter range, but the zooomed in range on the filter - return { facetHeader, renderType: 'range', domain: [extendedMinVal, extendedMaxVal], range: ranged ? ranged : [extendedMinVal, extendedMaxVal] }; - } else { - return { facetHeader, renderType: 'checkbox' }; + const ranged: number[] | undefined = Doc.readDocRangeFilter(this.Document, facetHeader); // not the filter range, but the zooomed in range on the filter + return { facetHeader, renderType: 'range', domain: [extendedMinVal, extendedMaxVal], range: ranged || [extendedMinVal, extendedMaxVal] }; } + return { facetHeader, renderType: 'checkbox' }; }) ); } @@ -171,17 +175,17 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { sortingCurrentFacetValues = (facetHeader: string) => { this._collapseReturnKeys.splice(0); - Array.from(this.activeRenderedFacetInfos.keys()).map(renderInfo => { + Array.from(this.activeRenderedFacetInfos.keys()).forEach(renderInfo => { if (renderInfo.renderType === 'range' && renderInfo.facetHeader === facetHeader && renderInfo.range) { - this._collapseReturnKeys.push(renderInfo.range.map(number => number.toFixed(2))); + this._collapseReturnKeys.push(...renderInfo.range.map(number => number.toFixed(2))); } }); - for (var key of this.facetValues(facetHeader)) { + this.facetValues(facetHeader).forEach(key => { if (this.mapActiveFiltersToFacets.get(key)) { this._collapseReturnKeys.push(key); } - } + }); return <div className=" filterbox-collpasedAndActive">{this._collapseReturnKeys.join(', ')}</div>; }; @@ -198,7 +202,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { ); else allCollectionDocs.forEach(child => { - const fieldVal = child[facetHeader] as Field; + const fieldVal = child[facetHeader] as FieldType; if (!(fieldVal instanceof List)) { // currently we have no good way of filtering based on a field that is a list set.add(Field.toString(fieldVal)); @@ -209,7 +213,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { let nonNumbers = 0; - facetValues.map(val => Number.isNaN(Number(val)) && nonNumbers++); + facetValues.map(val => isNaN(Number(val)) && nonNumbers++); return nonNumbers / facetValues.length > 0.1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2)); }; @@ -218,7 +222,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { <div className="filterBox-treeView"> <div className="filterBox-select"> <div style={{ width: '100%' }}> - <FieldsDropdown Document={this.Document} selectFunc={this.facetClick} showPlaceholder={true} placeholder="add a filter" addedFields={['acl-Guest', LinkedTo]} /> + <FieldsDropdown Document={this.Document} selectFunc={this.facetClick} showPlaceholder placeholder="add a filter" addedFields={['acl_Guest', LinkedTo]} /> </div> {/* THE FOLLOWING CODE SHOULD BE DEVELOPER FOR BOOLEAN EXPRESSION (AND / OR) */} {/* <div className="filterBox-select-bool"> @@ -234,34 +238,31 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { <div className="filterBox-tree" key="tree"> {Array.from(this.activeRenderedFacetInfos.keys()).map( - ( - renderInfo // iterato over activeFacetRenderInfos ==> renderInfo which you can renderInfo.facetHeader - ) => ( + // iterate over activeFacetRenderInfos ==> renderInfo which you can renderInfo.facetHeader + renderInfo => ( <div> <div className="filterBox-facetHeader"> <div className="filterBox-facetHeader-Header"> </div> {renderInfo.facetHeader.charAt(0).toUpperCase() + renderInfo.facetHeader.slice(1)} - <div className="filterBox-facetHeader-collapse" - onClick={action(e => { + onClick={action(() => { const collapseBoolValue = this._chosenFacetsCollapse.get(renderInfo.facetHeader); this._chosenFacetsCollapse.set(renderInfo.facetHeader, !collapseBoolValue); })}> {this._chosenFacetsCollapse.get(renderInfo.facetHeader) ? <AiOutlinePlusSquare /> : <AiOutlineMinusSquare />} </div> - <div className="filterBox-facetHeader-remove" - onClick={action(e => { + onClick={action(() => { if (renderInfo.facetHeader === 'text') { Doc.setDocFilter(this.Document, renderInfo.facetHeader, 'match', 'remove'); } else { - for (var key of this.facetValues(renderInfo.facetHeader)) { + this.facetValues(renderInfo.facetHeader).forEach((key: string) => { if (this.mapActiveFiltersToFacets.get(key)) { Doc.setDocFilter(this.Document, renderInfo.facetHeader, key, 'remove'); } - } + }); } this._selectedFacetHeaders.delete(renderInfo.facetHeader); this._chosenFacetsCollapse.delete(renderInfo.facetHeader); @@ -292,15 +293,15 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { return ( <input key={this.Document[Id]} - placeholder={'enter text to match'} + placeholder="enter text to match" defaultValue={ StrListCast(this.Document._childFilters) .find(filter => filter.split(Doc.FilterSep)[0] === facetHeader) ?.split(Doc.FilterSep)[1] } - style={{ color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }} + style={{ color: SnappingManager.userColor, background: SnappingManager.userBackgroundColor }} onBlur={undoable(e => Doc.setDocFilter(this.Document, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')} - onKeyDown={e => e.key === 'Enter' && undoable(e => Doc.setDocFilter(this.Document, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')(e)} + onKeyDown={e => e.key === 'Enter' && undoable(() => Doc.setDocFilter(this.Document, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')()} /> ); case 'checkbox': @@ -312,7 +313,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { style={{ width: 20, marginLeft: 20 }} checked={['check', 'exists'].includes( StrListCast(this.Document._childFilters) - .find(filter => filter.split(Doc.FilterSep)[0] === facetHeader && filter.split(Doc.FilterSep)[1] == facetValue) + .find(filter => filter.split(Doc.FilterSep)[0] === facetHeader && filter.split(Doc.FilterSep)[1] === facetValue) ?.split(Doc.FilterSep)[2] ?? '' )} type={type} @@ -324,55 +325,56 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { }); case 'range': - const domain = renderInfoDomain; - const range = renderInfoRange; - if (domain) { - return ( - <div className="sliderBox-outerDiv" style={{ width: '95%', height: 45, float: 'right' }}> - <Slider - mode={2} - step={Math.min(1, 0.1 * (domain[1] - domain[0]))} - domain={[domain[0], domain[1]]} // -1000, 1000 - rootStyle={{ position: 'relative', width: '100%' }} - onChange={values => Doc.setDocRangeFilter(this.Document, facetHeader, values)} - values={renderInfoRange!}> - <Rail>{railProps => <TooltipRail {...railProps} />}</Rail> - <Handles> - {({ handles, activeHandleID, getHandleProps }) => ( - <div className="slider-handles"> - {handles.map((handle, i) => { - // const value = i === 0 ? defaultValues[0] : defaultValues[1]; - return ( + { + const domain = renderInfoDomain; + if (domain) { + return ( + <div className="sliderBox-outerDiv" style={{ width: '95%', height: 45, float: 'right' }}> + <Slider + mode={2} + step={Math.min(1, 0.1 * (domain[1] - domain[0]))} + domain={[domain[0], domain[1]]} // -1000, 1000 + rootStyle={{ position: 'relative', width: '100%' }} + onChange={values => Doc.setDocRangeFilter(this.Document, facetHeader, values)} + values={renderInfoRange!}> + <Rail>{railProps => <TooltipRail {...railProps} />}</Rail> + <Handles> + {({ handles, activeHandleID, getHandleProps }) => ( + <div className="slider-handles"> + {handles.map(handle => ( + // const value = i === 0 ? defaultValues[0] : defaultValues[1]; <div> <Handle key={handle.id} handle={handle} domain={domain} isActive={handle.id === activeHandleID} getHandleProps={getHandleProps} /> </div> - ); - })} - </div> - )} - </Handles> - <Tracks left={false} right={false}> - {({ tracks, getTrackProps }) => ( - <div className="slider-tracks"> - {tracks.map(({ id, source, target }) => ( - <Track key={id} source={source} target={target} disabled={false} getTrackProps={getTrackProps} /> - ))} - </div> - )} - </Tracks> - <Ticks count={5}> - {({ ticks }) => ( - <div className="slider-ticks"> - {ticks.map(tick => ( - <Tick key={tick.id} tick={tick} count={ticks.length} format={(val: number) => val.toString()} /> - ))} - </div> - )} - </Ticks> - </Slider> - </div> - ); + ))} + </div> + )} + </Handles> + <Tracks left={false} right={false}> + {({ tracks, getTrackProps }) => ( + <div className="slider-tracks"> + {tracks.map(({ id, source, target }) => ( + <Track key={id} source={source} target={target} disabled={false} getTrackProps={getTrackProps} /> + ))} + </div> + )} + </Tracks> + <Ticks count={5}> + {({ ticks }) => ( + <div className="slider-ticks"> + {ticks.map(tick => ( + <Tick key={tick.id} tick={tick} count={ticks.length} format={(val: number) => val.toString()} /> + ))} + </div> + )} + </Ticks> + </Slider> + </div> + ); + } } + break; + default: // case 'range' // return <Slider ... @@ -386,5 +388,6 @@ export class FilterPanel extends ObservableReactComponent<filterProps> { // <dimain changing handles > // <?div } + return undefined; } } |