From fcbf9128bda52e5160381b1fa00f04186693153c Mon Sep 17 00:00:00 2001 From: wiedld Date: Tue, 17 Jan 2023 18:52:28 -0800 Subject: [PATCH 1/6] feat(6496): viewOptions to modify query by groupby tagKeys --- src/dataExplorer/components/Results.tsx | 41 +++++++++---- .../components/SqlViewOptions.scss | 11 ++++ .../components/SqlViewOptions.tsx | 58 +++++++++++++++++++ .../context/results/childResults.tsx | 36 +++++++++--- src/dataExplorer/context/resultsView.tsx | 41 +++++++++++-- src/dataExplorer/context/tags.tsx | 3 + 6 files changed, 163 insertions(+), 27 deletions(-) create mode 100644 src/dataExplorer/components/SqlViewOptions.scss create mode 100644 src/dataExplorer/components/SqlViewOptions.tsx diff --git a/src/dataExplorer/components/Results.tsx b/src/dataExplorer/components/Results.tsx index d17cccba09..b914fba9ad 100644 --- a/src/dataExplorer/components/Results.tsx +++ b/src/dataExplorer/components/Results.tsx @@ -9,7 +9,17 @@ import { ComponentColor, } from '@influxdata/clockface' -import {RemoteDataState, SimpleTableViewProperties} from 'src/types' +// Components +import {SearchWidget} from 'src/shared/components/search_widget/SearchWidget' +import { + View, + ViewTypeDropdown, + ViewOptions, + SUPPORTED_VISUALIZATIONS, +} from 'src/visualization' +import {SqlViewOptions} from 'src/dataExplorer/components/SqlViewOptions' + +// Contexts import {ResultsContext} from 'src/dataExplorer/context/results' import { ResultsViewContext, @@ -18,18 +28,17 @@ import { import {ChildResultsContext} from 'src/dataExplorer/context/results/childResults' import {SidebarContext} from 'src/dataExplorer/context/sidebar' import {PersistanceContext} from 'src/dataExplorer/context/persistance' -import {SearchWidget} from 'src/shared/components/search_widget/SearchWidget' -import { - View, - ViewTypeDropdown, - ViewOptions, - SUPPORTED_VISUALIZATIONS, -} from 'src/visualization' + +// Types import {FluxResult} from 'src/types/flows' +import {RemoteDataState, SimpleTableViewProperties} from 'src/types' -import './Results.scss' +// Utils import {bytesFormatter} from 'src/shared/copy/notifications' +import './Results.scss' +import {LanguageType} from './resources' + const QueryStat: FC = () => { const {result} = useContext(ResultsContext) @@ -169,7 +178,9 @@ const WrappedOptions: FC = () => { // use parent `results` so all metadata is present for the viz options const {result} = useContext(ResultsContext) const {setResult, setStatus} = useContext(ChildResultsContext) - const {view, setView /* setViewOptions*/} = useContext(ResultsViewContext) + const {view, setView, selectViewOptions, viewOptions, selectedViewOptions} = + useContext(ResultsViewContext) + const {resource} = useContext(PersistanceContext) const updateChildResults = useCallback( update => { @@ -184,8 +195,14 @@ const WrappedOptions: FC = () => { [setStatus, setResult] ) - // TODO: make component with `update={setViewOptions}`, for QxBuilder-specific graph subquery options - const subQueryOptions = null + const subQueryOptions = + resource?.language === LanguageType.SQL ? ( + + ) : null return ( <> diff --git a/src/dataExplorer/components/SqlViewOptions.scss b/src/dataExplorer/components/SqlViewOptions.scss new file mode 100644 index 0000000000..961b43fe5c --- /dev/null +++ b/src/dataExplorer/components/SqlViewOptions.scss @@ -0,0 +1,11 @@ +@import '@influxdata/clockface/dist/variables.scss'; + +.sql-view-options { + .cf-list { + flex: 1 0 !important; + + .selector-list--item { + height: $cf-form-xs-height; + } + } +} diff --git a/src/dataExplorer/components/SqlViewOptions.tsx b/src/dataExplorer/components/SqlViewOptions.tsx new file mode 100644 index 0000000000..01d5623d87 --- /dev/null +++ b/src/dataExplorer/components/SqlViewOptions.tsx @@ -0,0 +1,58 @@ +import React, {FC} from 'react' +import {Columns, Form, Grid} from '@influxdata/clockface' + +import SelectorList from 'src/timeMachine/components/SelectorList' +import {ViewOptions} from 'src/dataExplorer/context/resultsView' + +import './SqlViewOptions.scss' + +interface SqlViewOptionsT { + selectViewOptions: (_: Partial) => void + allViewOptions: ViewOptions + selectedViewOptions: ViewOptions +} + +export const SqlViewOptions: FC = ({ + selectViewOptions, + allViewOptions, + selectedViewOptions, +}) => { + const handleSelectedListItem = (propKey, value) => { + if ((selectedViewOptions[propKey] ?? []).includes(value)) { + selectViewOptions({ + [propKey]: selectedViewOptions[propKey].filter(v => v !== value), + }) + } else { + selectViewOptions({ + [propKey]: (selectedViewOptions[propKey] ?? []).concat([value]), + }) + } + } + + return ( +
+ + + +
Query Modifier
+ + + handleSelectedListItem('groupby', tagKey) + } + multiSelect={true} + /> + +
+
+
+
+ ) +} diff --git a/src/dataExplorer/context/results/childResults.tsx b/src/dataExplorer/context/results/childResults.tsx index 5942bfb04b..3b36ec6833 100644 --- a/src/dataExplorer/context/results/childResults.tsx +++ b/src/dataExplorer/context/results/childResults.tsx @@ -17,17 +17,33 @@ import {LanguageType} from 'src/dataExplorer/components/resources' // Utils import {rangeToParam} from 'src/dataExplorer/shared/utils' -const modifiersToApply = (_viewOptions: ViewOptions): SqlQueryModifiers => { +const modifiersToApply = (viewOptions: ViewOptions): SqlQueryModifiers => { + const prepend = [] + const append = [] + + // 1. groupby first + if (viewOptions.groupby?.length) { + append.push( + `|> group(columns: [${viewOptions.groupby + .map(columnName => `"${columnName}"`) + .join(',')}])` + ) + } + + // 2. smoothing transformation next // e.g. to smooth by selected column foo. Rough example. const shouldSmooth = false if (shouldSmooth) { - return { - prepend: `import "experimental/polyline"`, - append: `|> polyline.rdp(valColumn: "foo", timeColumn: "time")`, - } + prepend.push(`import "experimental/polyline"`) + // append.push(`|> polyline.rdp(valColumn: "foo", timeColumn: "time")`) // TODO } - return null + return Boolean(prepend.length + append.length) + ? { + prepend: prepend.join('\n'), + append: append.join('\n'), + } + : null } interface ChildResultsContextType { @@ -51,12 +67,13 @@ export const ChildResultsContext = export const ChildResultsProvider: FC = ({children}) => { const [result, setResult] = useState({} as FluxResult) + const [queryModifers, setQueryModifiers] = useState(null) const [status, setStatus] = useState( RemoteDataState.NotStarted ) const {status: statusFromParent, result: resultFromParent} = useContext(ResultsContext) - const {viewOptions} = useContext(ResultsViewContext) + const {selectedViewOptions: viewOptions} = useContext(ResultsViewContext) const { query: queryText, selection, @@ -78,10 +95,11 @@ export const ChildResultsProvider: FC = ({children}) => { return } - // TODO: tranform functions, based on viewOptions change const sqlQueryModifiers = modifiersToApply(viewOptions) + const previousQueryModifiers = queryModifers + setQueryModifiers(sqlQueryModifiers) - if (!sqlQueryModifiers) { + if (sqlQueryModifiers === previousQueryModifiers) { return } diff --git a/src/dataExplorer/context/resultsView.tsx b/src/dataExplorer/context/resultsView.tsx index 2de208f88f..a72bc7f60f 100644 --- a/src/dataExplorer/context/resultsView.tsx +++ b/src/dataExplorer/context/resultsView.tsx @@ -1,4 +1,4 @@ -import React, {FC, createContext} from 'react' +import React, {FC, createContext, useCallback} from 'react' import {useSessionStorage} from 'src/dataExplorer/shared/utils' import {ViewProperties, SimpleTableViewProperties} from 'src/types' @@ -14,25 +14,33 @@ interface View { properties: ViewProperties } -export interface ViewOptions {} +export interface ViewOptions { + groupby: string[] +} interface ResultsViewContextType { view: View viewOptions: ViewOptions + selectedViewOptions: ViewOptions setView: (view: View) => void - setViewOptions: (viewOptions: Object) => void + setViewOptions: (viewOptions: Partial) => void + selectViewOptions: (viewOptions: Partial) => void } +const DEFAULT_VIEW_OPTIONS = {groupby: []} + const DEFAULT_STATE: ResultsViewContextType = { view: { state: ViewStateType.Table, properties: SUPPORTED_VISUALIZATIONS['xy'].initial, }, - viewOptions: {}, // TODO -- set default options. Such as all tagKeys for `|> group()` + viewOptions: JSON.parse(JSON.stringify(DEFAULT_VIEW_OPTIONS)), + selectedViewOptions: JSON.parse(JSON.stringify(DEFAULT_VIEW_OPTIONS)), setView: _ => {}, setViewOptions: _ => {}, + selectViewOptions: _ => {}, } export const ResultsViewContext = @@ -47,9 +55,28 @@ export const ResultsViewProvider: FC = ({children}) => { } as SimpleTableViewProperties, }) - const [viewOptions, setViewOptions] = useSessionStorage( + // what can be chosen (e.g. the list of all options) + const [viewOptions, saveViewOptions] = useSessionStorage( + 'dataExplorer.resultsOptions.all', + DEFAULT_VIEW_OPTIONS + ) + const setViewOptions = useCallback( + (updatedOptions: Partial) => { + saveViewOptions({...viewOptions, ...updatedOptions}) + }, + [viewOptions] + ) + + // what was chosen (e.g. sublist chosen) + const [selectedViewOptions, saveSelectedViewOptions] = useSessionStorage( 'dataExplorer.resultsOptions', - {} + DEFAULT_VIEW_OPTIONS + ) + const selectViewOptions = useCallback( + (updatedOptions: Partial) => { + saveSelectedViewOptions({...viewOptions, ...updatedOptions}) + }, + [viewOptions] ) return ( @@ -57,9 +84,11 @@ export const ResultsViewProvider: FC = ({children}) => { value={{ view, viewOptions, + selectedViewOptions, setView, setViewOptions, + selectViewOptions, }} > {children} diff --git a/src/dataExplorer/context/tags.tsx b/src/dataExplorer/context/tags.tsx index 4f88703859..6749e95532 100644 --- a/src/dataExplorer/context/tags.tsx +++ b/src/dataExplorer/context/tags.tsx @@ -11,6 +11,7 @@ import {DEFAULT_LIMIT} from 'src/shared/constants/queryBuilder' // Contexts import {QueryContext, QueryScope} from 'src/shared/contexts/query' +import {ResultsViewContext} from 'src/dataExplorer/context/resultsView' // Utils import { @@ -57,6 +58,7 @@ interface Prop { export const TagsProvider: FC = ({children, scope}) => { // Contexts const {query: queryAPI} = useContext(QueryContext) + const {setViewOptions} = useContext(ResultsViewContext) // States const [tags, setTags] = useState( @@ -132,6 +134,7 @@ export const TagsProvider: FC = ({children, scope}) => { setTags(newTags) setLoadingTagKeys(RemoteDataState.Done) setLoadingTagValues(tagValueStatuses) + setViewOptions({groupby: Object.keys(newTags)}) } catch (e) { console.error( `Failed to get tags for measurement: "${measurement}"\n`, From c6a335f4b2c8bdaa22af814aede2ef58d031a84a Mon Sep 17 00:00:00 2001 From: wiedld Date: Wed, 18 Jan 2023 10:46:16 -0800 Subject: [PATCH 2/6] fix(6496): Cannot run subquery if no bucket is selected. Show spinner when graph subquery is loading. --- src/dataExplorer/components/Results.tsx | 18 +++++++++++------- .../context/results/childResults.tsx | 5 +++++ src/dataExplorer/context/tags.tsx | 3 ++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/dataExplorer/components/Results.tsx b/src/dataExplorer/components/Results.tsx index b914fba9ad..59c3e9a1ef 100644 --- a/src/dataExplorer/components/Results.tsx +++ b/src/dataExplorer/components/Results.tsx @@ -7,6 +7,8 @@ import { IconFont, ComponentStatus, ComponentColor, + SpinnerContainer, + TechnoSpinner, } from '@influxdata/clockface' // Components @@ -163,13 +165,15 @@ const GraphResults: FC = () => { return (
- + }> + +
) } diff --git a/src/dataExplorer/context/results/childResults.tsx b/src/dataExplorer/context/results/childResults.tsx index 3b36ec6833..9f8b14c4b9 100644 --- a/src/dataExplorer/context/results/childResults.tsx +++ b/src/dataExplorer/context/results/childResults.tsx @@ -95,6 +95,11 @@ export const ChildResultsProvider: FC = ({children}) => { return } + const cannotRunIoxSqlMethod = !selection?.bucket + if (cannotRunIoxSqlMethod) { + return + } + const sqlQueryModifiers = modifiersToApply(viewOptions) const previousQueryModifiers = queryModifers setQueryModifiers(sqlQueryModifiers) diff --git a/src/dataExplorer/context/tags.tsx b/src/dataExplorer/context/tags.tsx index 6749e95532..f62d232bef 100644 --- a/src/dataExplorer/context/tags.tsx +++ b/src/dataExplorer/context/tags.tsx @@ -58,7 +58,7 @@ interface Prop { export const TagsProvider: FC = ({children, scope}) => { // Contexts const {query: queryAPI} = useContext(QueryContext) - const {setViewOptions} = useContext(ResultsViewContext) + const {setViewOptions, selectViewOptions} = useContext(ResultsViewContext) // States const [tags, setTags] = useState( @@ -135,6 +135,7 @@ export const TagsProvider: FC = ({children, scope}) => { setLoadingTagKeys(RemoteDataState.Done) setLoadingTagValues(tagValueStatuses) setViewOptions({groupby: Object.keys(newTags)}) + selectViewOptions({groupby: Object.keys(newTags)}) // groupby all tagKeys, as default } catch (e) { console.error( `Failed to get tags for measurement: "${measurement}"\n`, From 5f5ae5b1e6093c204d11a0a1ad7a3bff8cefd724 Mon Sep 17 00:00:00 2001 From: wiedld Date: Wed, 18 Jan 2023 13:31:20 -0800 Subject: [PATCH 3/6] feat(6496): have groupby options be a based upon returned results, with the default groupby determined via the tagKeys in the schema --- .../components/SqlViewOptions.tsx | 41 +++++++++---- src/dataExplorer/context/resultsView.tsx | 59 +++++++++++++++---- src/dataExplorer/context/tags.tsx | 5 +- 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/dataExplorer/components/SqlViewOptions.tsx b/src/dataExplorer/components/SqlViewOptions.tsx index 01d5623d87..83d93cc54a 100644 --- a/src/dataExplorer/components/SqlViewOptions.tsx +++ b/src/dataExplorer/components/SqlViewOptions.tsx @@ -1,7 +1,8 @@ import React, {FC} from 'react' -import {Columns, Form, Grid} from '@influxdata/clockface' +import {Columns, Grid} from '@influxdata/clockface' import SelectorList from 'src/timeMachine/components/SelectorList' +import SelectorTitle from 'src/dataExplorer/components/SelectorTitle' import {ViewOptions} from 'src/dataExplorer/context/resultsView' import './SqlViewOptions.scss' @@ -29,6 +30,24 @@ export const SqlViewOptions: FC = ({ } } + const groupbyTooltipContents = ( +
+ Select the GROUPBY used for the graph subquery. +
+
+ + Options are based on returned data results (refer to your table + columns). + +
+
+ + By default, the GROUPBY is done on all tagKeys in order to produce a + dataseries. + +
+ ) + return (
@@ -40,16 +59,16 @@ export const SqlViewOptions: FC = ({ className="view-options-container" >
Query Modifier
- - - handleSelectedListItem('groupby', tagKey) - } - multiSelect={true} - /> - + + handleSelectedListItem('groupby', tagKey)} + multiSelect={true} + />
diff --git a/src/dataExplorer/context/resultsView.tsx b/src/dataExplorer/context/resultsView.tsx index a72bc7f60f..1313196237 100644 --- a/src/dataExplorer/context/resultsView.tsx +++ b/src/dataExplorer/context/resultsView.tsx @@ -1,8 +1,17 @@ -import React, {FC, createContext, useCallback} from 'react' +import React, { + FC, + createContext, + useCallback, + useContext, + useEffect, +} from 'react' import {useSessionStorage} from 'src/dataExplorer/shared/utils' import {ViewProperties, SimpleTableViewProperties} from 'src/types' import {SUPPORTED_VISUALIZATIONS} from 'src/visualization' +import {ResultsContext} from 'src/dataExplorer/context/results' + +const NOT_PERMITTED_GROUPBY = ['_result', 'result', '_time', 'time', 'table'] export enum ViewStateType { Table = 'table', @@ -24,7 +33,7 @@ interface ResultsViewContextType { selectedViewOptions: ViewOptions setView: (view: View) => void - setViewOptions: (viewOptions: Partial) => void + setDefaultViewOptions: (viewOptions: Partial) => void selectViewOptions: (viewOptions: Partial) => void } @@ -39,7 +48,7 @@ const DEFAULT_STATE: ResultsViewContextType = { selectedViewOptions: JSON.parse(JSON.stringify(DEFAULT_VIEW_OPTIONS)), setView: _ => {}, - setViewOptions: _ => {}, + setDefaultViewOptions: _ => {}, selectViewOptions: _ => {}, } @@ -47,6 +56,7 @@ export const ResultsViewContext = createContext(DEFAULT_STATE) export const ResultsViewProvider: FC = ({children}) => { + const {result: resultFromParent} = useContext(ResultsContext) const [view, setView] = useSessionStorage('dataExplorer.results', { state: ViewStateType.Table, properties: { @@ -56,15 +66,27 @@ export const ResultsViewProvider: FC = ({children}) => { }) // what can be chosen (e.g. the list of all options) - const [viewOptions, saveViewOptions] = useSessionStorage( + const [viewOptionsAll, saveViewOptionsAll] = useSessionStorage( 'dataExplorer.resultsOptions.all', DEFAULT_VIEW_OPTIONS ) - const setViewOptions = useCallback( + const setViewOptionsAll = useCallback( (updatedOptions: Partial) => { - saveViewOptions({...viewOptions, ...updatedOptions}) + saveViewOptionsAll({...viewOptionsAll, ...updatedOptions}) }, - [viewOptions] + [viewOptionsAll] + ) + + // default options (a.k.a. based on schema) + const [defaultViewOptions, saveDefaultViewOptions] = useSessionStorage( + 'dataExplorer.resultsOptions.default', + DEFAULT_VIEW_OPTIONS + ) + const setDefaultViewOptions = useCallback( + (updatedOptions: Partial) => { + saveDefaultViewOptions({...defaultViewOptions, ...updatedOptions}) + }, + [defaultViewOptions] ) // what was chosen (e.g. sublist chosen) @@ -74,20 +96,35 @@ export const ResultsViewProvider: FC = ({children}) => { ) const selectViewOptions = useCallback( (updatedOptions: Partial) => { - saveSelectedViewOptions({...viewOptions, ...updatedOptions}) + saveSelectedViewOptions({...selectedViewOptions, ...updatedOptions}) }, - [viewOptions] + [selectedViewOptions] ) + useEffect(() => { + // if parent query is re-run => decide what to reset in subquery viewOptions + + // reset groupby + const excludeFromGroupby = NOT_PERMITTED_GROUPBY + const groupby = Object.keys( + resultFromParent?.parsed?.table?.columns || {} + ).filter(g => !excludeFromGroupby.includes(g)) + setViewOptionsAll({groupby}) + const defaultsWhichExist = defaultViewOptions.groupby.filter(g => + groupby.includes(g) + ) + selectViewOptions({groupby: defaultsWhichExist}) + }, [resultFromParent, defaultViewOptions]) + return ( diff --git a/src/dataExplorer/context/tags.tsx b/src/dataExplorer/context/tags.tsx index f62d232bef..ebfadd601d 100644 --- a/src/dataExplorer/context/tags.tsx +++ b/src/dataExplorer/context/tags.tsx @@ -58,7 +58,7 @@ interface Prop { export const TagsProvider: FC = ({children, scope}) => { // Contexts const {query: queryAPI} = useContext(QueryContext) - const {setViewOptions, selectViewOptions} = useContext(ResultsViewContext) + const {setDefaultViewOptions} = useContext(ResultsViewContext) // States const [tags, setTags] = useState( @@ -134,8 +134,7 @@ export const TagsProvider: FC = ({children, scope}) => { setTags(newTags) setLoadingTagKeys(RemoteDataState.Done) setLoadingTagValues(tagValueStatuses) - setViewOptions({groupby: Object.keys(newTags)}) - selectViewOptions({groupby: Object.keys(newTags)}) // groupby all tagKeys, as default + setDefaultViewOptions({groupby: Object.keys(newTags)}) } catch (e) { console.error( `Failed to get tags for measurement: "${measurement}"\n`, From 1e3630eac64ace840bd00f043dd1a3499dd8d426 Mon Sep 17 00:00:00 2001 From: wiedld Date: Wed, 18 Jan 2023 13:32:39 -0800 Subject: [PATCH 4/6] feat(6482): when choosing graph --> auto-open the Customize options in right hand panel. --- src/dataExplorer/components/Results.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/dataExplorer/components/Results.tsx b/src/dataExplorer/components/Results.tsx index 59c3e9a1ef..2bfe962f10 100644 --- a/src/dataExplorer/components/Results.tsx +++ b/src/dataExplorer/components/Results.tsx @@ -1,4 +1,11 @@ -import React, {FC, useState, useContext, useMemo, useCallback} from 'react' +import React, { + FC, + useState, + useContext, + useMemo, + useCallback, + useEffect, +} from 'react' import { FlexBox, FlexDirection, @@ -221,14 +228,21 @@ const WrappedOptions: FC = () => { } const GraphHeader: FC = () => { - const {view, setView} = useContext(ResultsViewContext) + const {view, setView, viewOptions} = useContext(ResultsViewContext) const {result} = useContext(ResultsContext) const {result: subQueryResult} = useContext(ChildResultsContext) const {launch} = useContext(SidebarContext) + const dataExists = !!result?.parsed + const launcher = () => { launch() } + useEffect(() => { + if (dataExists) { + launcher() + } + }, [viewOptions]) const updateType = viewType => { setView({ @@ -237,7 +251,6 @@ const GraphHeader: FC = () => { }) } - const dataExists = !!result?.parsed const subqueryReturnsData = !!subQueryResult?.parsed let titleText = 'Configure Visualization' if (!dataExists) { From 28a1ed527cde663e0875040cea42cdf369f3560d Mon Sep 17 00:00:00 2001 From: wiedld Date: Wed, 18 Jan 2023 15:32:58 -0800 Subject: [PATCH 5/6] chore(6496): use better naming conventions --- src/dataExplorer/components/Results.tsx | 6 +++--- src/dataExplorer/context/resultsView.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dataExplorer/components/Results.tsx b/src/dataExplorer/components/Results.tsx index 2bfe962f10..8fb404fb72 100644 --- a/src/dataExplorer/components/Results.tsx +++ b/src/dataExplorer/components/Results.tsx @@ -1,10 +1,10 @@ import React, { FC, - useState, - useContext, - useMemo, useCallback, + useContext, useEffect, + useMemo, + useState, } from 'react' import { FlexBox, diff --git a/src/dataExplorer/context/resultsView.tsx b/src/dataExplorer/context/resultsView.tsx index 1313196237..5eb138ae4f 100644 --- a/src/dataExplorer/context/resultsView.tsx +++ b/src/dataExplorer/context/resultsView.tsx @@ -108,10 +108,10 @@ export const ResultsViewProvider: FC = ({children}) => { const excludeFromGroupby = NOT_PERMITTED_GROUPBY const groupby = Object.keys( resultFromParent?.parsed?.table?.columns || {} - ).filter(g => !excludeFromGroupby.includes(g)) + ).filter(columnName => !excludeFromGroupby.includes(columnName)) setViewOptionsAll({groupby}) - const defaultsWhichExist = defaultViewOptions.groupby.filter(g => - groupby.includes(g) + const defaultsWhichExist = defaultViewOptions.groupby.filter(defaultGroup => + groupby.includes(defaultGroup) ) selectViewOptions({groupby: defaultsWhichExist}) }, [resultFromParent, defaultViewOptions]) From ce788abd96873b6a7c7932c7a372f9d38f239780 Mon Sep 17 00:00:00 2001 From: wiedld Date: Wed, 18 Jan 2023 15:44:49 -0800 Subject: [PATCH 6/6] feat(6496): make explicit what is persisted, and determine when it's cleared --- src/dataExplorer/components/DeleteScript.tsx | 3 +++ src/dataExplorer/components/Results.tsx | 15 +++++++++++-- src/dataExplorer/components/SaveAsScript.tsx | 3 +++ .../components/ScriptQueryBuilder.tsx | 7 ++++++- src/dataExplorer/context/resultsView.tsx | 21 +++++++++++++------ 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/dataExplorer/components/DeleteScript.tsx b/src/dataExplorer/components/DeleteScript.tsx index 9decbeb42d..421a0857ec 100644 --- a/src/dataExplorer/components/DeleteScript.tsx +++ b/src/dataExplorer/components/DeleteScript.tsx @@ -12,6 +12,7 @@ import {ResultsContext} from 'src/dataExplorer/context/results' import {RemoteDataState} from 'src/types' import {QueryContext} from 'src/shared/contexts/query' import {SCRIPT_EDITOR_PARAMS} from 'src/dataExplorer/components/resources' +import {ResultsViewContext} from 'src/dataExplorer/context/resultsView' let deleteScript @@ -28,6 +29,7 @@ const DeleteScript: FC = ({onBack, onClose}) => { const {resource} = useContext(PersistanceContext) const {cancel} = useContext(QueryContext) const {setStatus, setResult} = useContext(ResultsContext) + const {clear: clearViewOptions} = useContext(ResultsViewContext) const history = useHistory() const dispatch = useDispatch() const org = useSelector(getOrg) @@ -43,6 +45,7 @@ const DeleteScript: FC = ({onBack, onClose}) => { setStatus(RemoteDataState.NotStarted) setResult(null) + clearViewOptions() cancel() history.replace( `/orgs/${org.id}/data-explorer/from/script${SCRIPT_EDITOR_PARAMS}` diff --git a/src/dataExplorer/components/Results.tsx b/src/dataExplorer/components/Results.tsx index 8fb404fb72..c4bcc8b983 100644 --- a/src/dataExplorer/components/Results.tsx +++ b/src/dataExplorer/components/Results.tsx @@ -192,6 +192,7 @@ const WrappedOptions: FC = () => { const {view, setView, selectViewOptions, viewOptions, selectedViewOptions} = useContext(ResultsViewContext) const {resource} = useContext(PersistanceContext) + const dataExists = !!result?.parsed const updateChildResults = useCallback( update => { @@ -206,8 +207,13 @@ const WrappedOptions: FC = () => { [setStatus, setResult] ) + if (!dataExists) { + return null + } + const subQueryOptions = - resource?.language === LanguageType.SQL ? ( + resource?.language === LanguageType.SQL && + view.state == ViewStateType.Graph ? ( { const {view, setView, viewOptions} = useContext(ResultsViewContext) const {result} = useContext(ResultsContext) const {result: subQueryResult} = useContext(ChildResultsContext) - const {launch} = useContext(SidebarContext) + const {launch, clear: closeSidebar} = useContext(SidebarContext) const dataExists = !!result?.parsed @@ -243,6 +249,11 @@ const GraphHeader: FC = () => { launcher() } }, [viewOptions]) + useEffect(() => { + if (!dataExists) { + closeSidebar() + } + }, [dataExists]) const updateType = viewType => { setView({ diff --git a/src/dataExplorer/components/SaveAsScript.tsx b/src/dataExplorer/components/SaveAsScript.tsx index 9a3604a95d..9835e449ac 100644 --- a/src/dataExplorer/components/SaveAsScript.tsx +++ b/src/dataExplorer/components/SaveAsScript.tsx @@ -37,6 +37,7 @@ import { copyToClipboardFailed, copyToClipboardSuccess, } from 'src/shared/copy/notifications' +import {ResultsViewContext} from 'src/dataExplorer/context/resultsView' interface Props { language: LanguageType onClose: () => void @@ -52,6 +53,7 @@ const SaveAsScript: FC = ({language, onClose, setOverlayType, type}) => { const isIoxOrg = useSelector(isOrgIOx) const {cancel} = useContext(QueryContext) const {setStatus, setResult} = useContext(ResultsContext) + const {clear: clearViewOptions} = useContext(ResultsViewContext) const [error, setError] = useState() // Setting the name to state rather than persisting it to session storage // so that we can cancel out of a name change if needed @@ -96,6 +98,7 @@ const SaveAsScript: FC = ({language, onClose, setOverlayType, type}) => { cancel() setStatus(RemoteDataState.NotStarted) setResult(null) + clearViewOptions() if (isIoxOrg) { history.replace( diff --git a/src/dataExplorer/components/ScriptQueryBuilder.tsx b/src/dataExplorer/components/ScriptQueryBuilder.tsx index a5590e0b0d..65b78068dc 100644 --- a/src/dataExplorer/components/ScriptQueryBuilder.tsx +++ b/src/dataExplorer/components/ScriptQueryBuilder.tsx @@ -21,7 +21,10 @@ import {QueryProvider} from 'src/shared/contexts/query' import {EditorProvider} from 'src/shared/contexts/editor' import {ResultsProvider, ResultsContext} from 'src/dataExplorer/context/results' import {ChildResultsProvider} from 'src/dataExplorer/context/results/childResults' -import {ResultsViewProvider} from 'src/dataExplorer/context/resultsView' +import { + ResultsViewProvider, + ResultsViewContext, +} from 'src/dataExplorer/context/resultsView' import {SidebarProvider} from 'src/dataExplorer/context/sidebar' import { PersistanceProvider, @@ -59,12 +62,14 @@ const ScriptQueryBuilder: FC = () => { const isIoxOrg = useSelector(isOrgIOx) const {cancel} = useContext(QueryContext) const {setStatus, setResult} = useContext(ResultsContext) + const {clear: clearViewOptions} = useContext(ResultsViewContext) const org = useSelector(getOrg) const handleClear = useCallback(() => { cancel() setStatus(RemoteDataState.NotStarted) setResult(null) + clearViewOptions() if (isIoxOrg) { history.replace( diff --git a/src/dataExplorer/context/resultsView.tsx b/src/dataExplorer/context/resultsView.tsx index 5eb138ae4f..ca65025aa5 100644 --- a/src/dataExplorer/context/resultsView.tsx +++ b/src/dataExplorer/context/resultsView.tsx @@ -35,6 +35,7 @@ interface ResultsViewContextType { setView: (view: View) => void setDefaultViewOptions: (viewOptions: Partial) => void selectViewOptions: (viewOptions: Partial) => void + clear: () => void } const DEFAULT_VIEW_OPTIONS = {groupby: []} @@ -50,6 +51,7 @@ const DEFAULT_STATE: ResultsViewContextType = { setView: _ => {}, setDefaultViewOptions: _ => {}, selectViewOptions: _ => {}, + clear: () => {}, } export const ResultsViewContext = @@ -66,41 +68,47 @@ export const ResultsViewProvider: FC = ({children}) => { }) // what can be chosen (e.g. the list of all options) - const [viewOptionsAll, saveViewOptionsAll] = useSessionStorage( + const [viewOptionsAll, persistViewOptionsAll] = useSessionStorage( 'dataExplorer.resultsOptions.all', DEFAULT_VIEW_OPTIONS ) const setViewOptionsAll = useCallback( (updatedOptions: Partial) => { - saveViewOptionsAll({...viewOptionsAll, ...updatedOptions}) + persistViewOptionsAll({...viewOptionsAll, ...updatedOptions}) }, [viewOptionsAll] ) // default options (a.k.a. based on schema) - const [defaultViewOptions, saveDefaultViewOptions] = useSessionStorage( + const [defaultViewOptions, persistDefaultViewOptions] = useSessionStorage( 'dataExplorer.resultsOptions.default', DEFAULT_VIEW_OPTIONS ) const setDefaultViewOptions = useCallback( (updatedOptions: Partial) => { - saveDefaultViewOptions({...defaultViewOptions, ...updatedOptions}) + persistDefaultViewOptions({...defaultViewOptions, ...updatedOptions}) }, [defaultViewOptions] ) // what was chosen (e.g. sublist chosen) - const [selectedViewOptions, saveSelectedViewOptions] = useSessionStorage( + const [selectedViewOptions, persistSelectedViewOptions] = useSessionStorage( 'dataExplorer.resultsOptions', DEFAULT_VIEW_OPTIONS ) const selectViewOptions = useCallback( (updatedOptions: Partial) => { - saveSelectedViewOptions({...selectedViewOptions, ...updatedOptions}) + persistSelectedViewOptions({...selectedViewOptions, ...updatedOptions}) }, [selectedViewOptions] ) + const clear = () => { + persistViewOptionsAll(DEFAULT_VIEW_OPTIONS) + persistDefaultViewOptions(DEFAULT_VIEW_OPTIONS) + persistSelectedViewOptions(DEFAULT_VIEW_OPTIONS) + } + useEffect(() => { // if parent query is re-run => decide what to reset in subquery viewOptions @@ -126,6 +134,7 @@ export const ResultsViewProvider: FC = ({children}) => { setView, setDefaultViewOptions, selectViewOptions, + clear, }} > {children}