Skip to content

Commit

Permalink
fix: garden group crashing
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustav-Eikaas committed Nov 20, 2023
1 parent a505f11 commit e086e44
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 93 deletions.
20 changes: 12 additions & 8 deletions packages/garden/src/lib/components/Garden.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ export type GardenMetaRequest = {
dateVariant?: string | null;
};

export type GardenDataSource<TContext> = {
getGardenMeta: (request: GardenMetaRequest, context: TContext, signal?: AbortSignal) => Promise<GardenMeta>;
getBlockAsync: (args: GetBlockRequestArgs, context: TContext, signal?: AbortSignal) => Promise<GardenGroup<any>[]>;
getHeader: (args: GetHeaderBlockRequestArgs, context: TContext, signal?: AbortSignal) => Promise<GardenHeaderGroup[]>;
getSubgroupItems: (args: GetSubgroupItemsArgs, context: TContext, signal?: AbortSignal) => Promise<any[]>;
export type GardenDataSource<TContext = undefined> = {
getGardenMeta: (request: GardenMetaRequest, context?: TContext, signal?: AbortSignal) => Promise<GardenMeta>;
getBlockAsync: (args: GetBlockRequestArgs, context?: TContext, signal?: AbortSignal) => Promise<GardenGroup<any>[]>;
getHeader: (
args: GetHeaderBlockRequestArgs,
context?: TContext,
signal?: AbortSignal
) => Promise<GardenHeaderGroup[]>;
getSubgroupItems: (args: GetSubgroupItemsArgs, context?: TContext, signal?: AbortSignal) => Promise<any[]>;
};

interface GardenProps<TData extends Record<PropertyKey, unknown>, TContext = undefined> {
Expand Down Expand Up @@ -96,11 +100,13 @@ export function Garden<TData extends Record<PropertyKey, unknown>, TContext = un

return (
<QueryClientProvider client={client.current}>
<ErrorBoundary FallbackComponent={GardenError}>
<ErrorBoundary FallbackComponent={() => <GardenError />}>
<Suspense fallback={<SplashScreen />}>
<GardenContextProvider
getIdentifier={getIdentifier}
timeInterval={timeInterval}
context={context}
dataSource={dataSource}
dateVariant={dateVariant}
initialGrouping={groupingKeys}
selected={selected}
Expand All @@ -121,11 +127,9 @@ export function Garden<TData extends Record<PropertyKey, unknown>, TContext = un
// Hides ViewSettings sidebar when sidesheet is open
selected ? null : (
<ViewSettings
dataSource={dataSource}
dateVariant={dateVariant}
groupingKeys={groupingKeys}
timeInterval={timeInterval}
context={context}
onChangeDateVariant={onChangeDateVariant}
onChangeTimeInterval={onChangetimeInterval}
setGroupingKeys={setGroupingKeys}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const GardenItemContainer = <TData extends Record<PropertyKey, unknown>,
props: PackageContainerProps<TData, TContext>
): JSX.Element => {
const {
selectionService: { selection, selectNode },
selectionService: { selection },
} = useGarden();

const {
Expand Down Expand Up @@ -193,7 +193,7 @@ export const GardenItemContainer = <TData extends Record<PropertyKey, unknown>,

const flatIndex = calculatedIndex;

if (flatIndex.isSubgroupItem) {
if (flatIndex.isSubgroupItem && groupingKeys.length > 1) {
const query = queries[calculateActualIndex(expandedIndexes, flatIndex.parent.index).actualIndex];
return (
<SubGroupItem
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Autocomplete, Divider, EdsProvider, Label, Radio } from '@equinor/eds-core-react';
import { useQuery } from '@tanstack/react-query';
import { Fragment, useRef } from 'react';
import { Autocomplete, CircularProgress, Divider, EdsProvider, Label, Radio } from '@equinor/eds-core-react';
import { Fragment, startTransition, useRef } from 'react';
import { GroupingOption } from '../../types';
import { GardenDataSource } from '../Garden';
import {
RadioButtonWrapper,
RadioCategoryWrapper,
Expand All @@ -12,10 +10,9 @@ import {
StyledGroupHeader,
StyledSubGroupHeader,
} from './groupingSelector.styles';
import { useGarden } from '../../hooks/useGarden';

type GroupingSelectorProps<TContext> = {
dataSource: GardenDataSource<TContext>;
context: TContext;
setGroupingKeys: (keys: string[]) => void;
groupingKeys: string[];
timeInterval: string | null;
Expand All @@ -25,63 +22,58 @@ type GroupingSelectorProps<TContext> = {
};

export function GroupingSelector<TContext>({
dataSource,
context,
timeInterval,
dateVariant,
setGroupingKeys,
onChangeTimeInterval,
onChangeDateVarient,
groupingKeys,
}: GroupingSelectorProps<TContext>): JSX.Element | null {
const { data } = useQuery(['garden', ...groupingKeys, timeInterval, dateVariant, context], {
refetchOnWindowFocus: false,
suspense: true,
useErrorBoundary: true,
keepPreviousData: false,
cacheTime: Infinity,
staleTime: Infinity,
queryFn: ({ signal }) =>
dataSource.getGardenMeta({ groupingKeys, timeInterval, dateVariant }, context, signal ?? new AbortSignal()),
});

const selectorRef = useRef(null);

const setGardenKey = (key: string) => {
const foundGroupingOption = data?.allGroupingOptions.find((option) => option.groupingKey === key);
if (!foundGroupingOption) {
throw new Error('Invalid grouping option');
}

if (!foundGroupingOption?.timeInterval?.includes(timeInterval ?? '')) {
onChangeTimeInterval(foundGroupingOption.timeInterval?.at(0) ?? null);
}

if (!foundGroupingOption?.dateVariant?.includes(dateVariant ?? '')) {
onChangeDateVarient(foundGroupingOption.dateVariant?.at(0) ?? null);
}

setGroupingKeys([key]);
};
const { gardenMetaQuery } = useGarden();

const handleExistingSelectionChange = (newValue: string | null | undefined) => {
const gardenKey = groupingKeys.at(0);
if (!gardenKey) {
throw new Error('');
}
const newKeys = newValue == null ? [gardenKey] : [gardenKey, newValue];
setGroupingKeys(newKeys);
startTransition(() => {
setGroupingKeys(newKeys);
});
};

const handleGardenKeyChange = (newValue: string | null | undefined) => {
const keyFromLabel = newValue;
keyFromLabel && setGardenKey(keyFromLabel);
};

if (!data) {
if (gardenMetaQuery.isLoading) {
return <CircularProgress size={48} />;
}

if (!gardenMetaQuery.data) {
throw new Error('An error occurred while fetching grouping selections');
}

const setGardenKey = (key: string) => {
const foundGroupingOption = gardenMetaQuery.data.allGroupingOptions.find((option) => option.groupingKey === key);
if (!foundGroupingOption) {
throw new Error('Invalid grouping option');
}

if (!foundGroupingOption?.timeInterval?.includes(timeInterval ?? '')) {
onChangeTimeInterval(foundGroupingOption.timeInterval?.at(0) ?? null);
}

if (!foundGroupingOption?.dateVariant?.includes(dateVariant ?? '')) {
onChangeDateVarient(foundGroupingOption.dateVariant?.at(0) ?? null);
}

setGroupingKeys([key]);
};

return (
<EdsProvider density="compact">
<SelectorBody>
Expand All @@ -91,22 +83,22 @@ export function GroupingSelector<TContext>({
<Autocomplete
ref={selectorRef}
key={groupingKeys[0]}
options={data.allGroupingOptions.map((option: GroupingOption) => option.groupingKey)}
options={gardenMetaQuery.data.allGroupingOptions.map((option: GroupingOption) => option.groupingKey)}
label={'Group by'}
hideClearButton
multiple={false}
selectedOptions={[groupingKeys[0]]}
onOptionsChange={(changes) => handleGardenKeyChange(changes.selectedItems[0])}
/>
<Autocomplete
options={data.validGroupingOptions}
options={gardenMetaQuery.data.validGroupingOptions}
label={'Then Group by'}
selectedOptions={[groupingKeys.at(1)]}
onOptionsChange={(changes) => handleExistingSelectionChange(changes.selectedItems[0])}
/>
</StyledAutoCompleteWrapper>

{data.allGroupingOptions.map((groupingOption) => {
{gardenMetaQuery.data.allGroupingOptions.map((groupingOption) => {
// Check if dateVariant or timeInterval is defined
const hasDateVariant = !!groupingOption.dateVariant;
const hasTimeInterval = !!groupingOption.timeInterval;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { Button, Icon } from '@equinor/eds-core-react';
import { expand, collapse } from '@equinor/eds-icons';
import { useState } from 'react';
import { GardenDataSource } from '../Garden';
import { GroupingSelector } from '../GroupingSelector/GroupingSelector';
import { StyledViewSettings } from './viewSettings.styles';

const LOCAL_STORAGE_KEY = 'WorkspaceSidebarToggleState';

interface ViewSettingsProps<TData extends Record<PropertyKey, unknown>, TContext = undefined> {
dataSource: GardenDataSource<TContext>;
context?: TContext;
groupingKeys: string[];
timeInterval: string | null;
dateVariant: string | null;
Expand All @@ -21,8 +18,6 @@ interface ViewSettingsProps<TData extends Record<PropertyKey, unknown>, TContext
Icon.add({ expand, collapse });

export function ViewSettings<TData extends Record<PropertyKey, unknown>, TContext = undefined>({
dataSource,
context,
groupingKeys,
timeInterval,
dateVariant,
Expand Down Expand Up @@ -57,8 +52,6 @@ export function ViewSettings<TData extends Record<PropertyKey, unknown>, TContex
onChangeTimeInterval={onChangeTimeInterval}
dateVariant={dateVariant}
onChangeDateVarient={onChangeDateVariant}
context={context as any}
dataSource={dataSource}
/>
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useQuery } from '@tanstack/react-query';
import { useItemWidths } from '../../hooks';
import { useGarden } from '../../hooks/useGarden';
import { useGardenConfig } from '../../hooks/useGardenConfig';
Expand All @@ -9,6 +8,7 @@ import { StyledVirtualContainer } from './virtualContainer.styles';
import { info_circle } from '@equinor/eds-icons';
import { Icon } from '@equinor/eds-core-react';
import styled from 'styled-components';
import { SplashScreen } from '../splashScreen/SplashScreen';
Icon.add({ info_circle });

type VirtualContainerProps<TContext = undefined> = {
Expand All @@ -21,33 +21,17 @@ export const VirtualContainer = <TContext,>({
context,
}: VirtualContainerProps<TContext>): JSX.Element | null => {
const { onClickItem } = useGardenConfig();
const {
groupingService: { groupingKeys, timeInterval, dateVariant },
} = useGarden();
const { gardenMetaQuery } = useGarden();

const { data, isFetching } = useQuery(['garden', ...groupingKeys, timeInterval, dateVariant, context], {
refetchOnWindowFocus: false,
suspense: true,
useErrorBoundary: true,
keepPreviousData: false,
cacheTime: Infinity,
staleTime: Infinity,
queryFn: ({ signal }) =>
dataSource.getGardenMeta(
{
timeInterval,
dateVariant,
groupingKeys,
},
context,
signal ?? new AbortSignal()
),
});
if (gardenMetaQuery.isLoading) {
return <SplashScreen />;
}

if (!data) {
if (!gardenMetaQuery.data) {
// Will never happen when suspense is true
throw new Error();
}
const { data } = gardenMetaQuery;

const amountOfColumns = data.columnCount;
const columnWidth = data.columnWidth || 300;
Expand All @@ -73,14 +57,8 @@ export const VirtualContainer = <TContext,>({
return null;
}

//TODO: temp fix, should show skeletons
if (isFetching) {
return null;
}

return (
<>
{/* <ReactQueryDevtools /> */}
<StyledVirtualContainer id={'garden_root'}>
<ExpandProvider initialWidths={widths} defaultColumnWidth={columnWidth}>
<VirtualGarden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ export const SubGroupItem = ({
itemIndex,
parentRef,
}: SubGroupItemProps) => {
const { isLoading, error, data, refetch } = query;

const {
selectionService: { selection },
} = useGarden();
Expand All @@ -47,6 +45,8 @@ export const SubGroupItem = ({
getDisplayName,
} = useGardenConfig();

const { isLoading, error, data, refetch } = query;

if (isLoading) {
/** Skeleton loading state */
return (
Expand Down
31 changes: 28 additions & 3 deletions packages/garden/src/lib/context/gardenContext.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { PropsWithChildren, createContext, useCallback, useEffect, useState } from 'react';
import { GetIdentifier } from '../types';
import { GardenMeta, GetIdentifier } from '../types';
import { UseQueryResult, useQuery } from '@tanstack/react-query';
import { GardenDataSource } from '../components';

type GardenState = {
selectionService: SelectionService;
groupingService: GroupingService;
gardenMetaQuery: UseQueryResult<GardenMeta, unknown>;
};

type GroupingService = {
Expand All @@ -20,20 +23,42 @@ type SelectionService = {

export const GardenContext = createContext<GardenState | null>(null);

export const GardenContextProvider = <T,>(
export const GardenContextProvider = <T, TContext = undefined>(
props: PropsWithChildren<{
getIdentifier: GetIdentifier<T>;
selected: string | null;
initialGrouping: string[];
timeInterval: string | null;
dateVariant: string | null;
dataSource: GardenDataSource<TContext>;
context: TContext | undefined;
}>
) => {
const gardenMetaQuery = useQuery(
['garden', ...props.initialGrouping, props.timeInterval, props.dateVariant, props.context],
{
refetchOnWindowFocus: false,
suspense: true,
useErrorBoundary: true,
keepPreviousData: false,
cacheTime: Infinity,
staleTime: Infinity,
queryFn: ({ signal }) =>
props.dataSource.getGardenMeta(
{ groupingKeys: props.initialGrouping, timeInterval: props.timeInterval, dateVariant: props.dateVariant },
props.context,
signal ?? new AbortSignal()
),
}
);

const selectionService = useSelectionService(props.getIdentifier, props.selected);
const groupingService = useGroupingService(props.initialGrouping, props.timeInterval, props.dateVariant);

return (
<GardenContext.Provider value={{ groupingService, selectionService }}>{props.children}</GardenContext.Provider>
<GardenContext.Provider value={{ groupingService, selectionService, gardenMetaQuery }}>
{props.children}
</GardenContext.Provider>
);
};

Expand Down
Loading

0 comments on commit e086e44

Please sign in to comment.