Skip to content

Commit

Permalink
Merge pull request #886 from silx-kit/cancel-on-change
Browse files Browse the repository at this point in the history
Cancel on-going requests when changing entity or vis
  • Loading branch information
loichuder authored Dec 1, 2021
2 parents a6480f8 + 012aae4 commit 130cef2
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 7 deletions.
18 changes: 13 additions & 5 deletions packages/app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertAbsolutePath } from '@h5web/shared';
import { useState, Suspense } from 'react';
import { Suspense, useContext, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex';

import styles from './App.module.css';
import ErrorFallback from './ErrorFallback';
Expand All @@ -10,6 +10,7 @@ import VisConfigProvider from './VisConfigProvider';
import BreadcrumbsBar from './breadcrumbs/BreadcrumbsBar';
import Explorer from './explorer/Explorer';
import MetadataViewer from './metadata-viewer/MetadataViewer';
import { ProviderContext } from './providers/context';
import Visualizer from './visualizer/Visualizer';

const DEFAULT_PATH = process.env.REACT_APP_DEFAULT_PATH || '/';
Expand All @@ -25,6 +26,13 @@ function App(props: Props) {
const [isExplorerOpen, setExplorerOpen] = useState(!startFullscreen);
const [isInspecting, setInspecting] = useState(false);

const { valuesStore } = useContext(ProviderContext);
function onSelectPath(path: string) {
setSelectedPath(path);
valuesStore.cancelOngoing();
valuesStore.evictCancelled();
}

return (
<ReflexContainer className={styles.root} orientation="vertical">
<ErrorBoundary FallbackComponent={ErrorFallback}>
Expand All @@ -34,7 +42,7 @@ function App(props: Props) {
flex={25}
minSize={150}
>
<Explorer selectedPath={selectedPath} onSelect={setSelectedPath} />
<Explorer selectedPath={selectedPath} onSelect={onSelectPath} />
</ReflexElement>

<ReflexSplitter
Expand All @@ -49,7 +57,7 @@ function App(props: Props) {
isInspecting={isInspecting}
onToggleExplorer={() => setExplorerOpen(!isExplorerOpen)}
onChangeInspecting={setInspecting}
onSelectPath={setSelectedPath}
onSelectPath={onSelectPath}
/>
<VisConfigProvider>
<ErrorBoundary
Expand All @@ -62,7 +70,7 @@ function App(props: Props) {
{isInspecting ? (
<MetadataViewer
path={selectedPath}
onSelectPath={setSelectedPath}
onSelectPath={onSelectPath}
/>
) : (
<Visualizer path={selectedPath} />
Expand Down
57 changes: 57 additions & 0 deletions packages/app/src/__tests__/Visualizer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,60 @@ test('retry fetching dataset slice automatically when re-selecting slice', async
jest.runOnlyPendingTimers();
jest.useRealTimers();
});

test('cancel fetching dataset slice when changing entity', async () => {
jest.useFakeTimers('modern');
await renderApp();

// Select dataset and start fetching first slice
await selectExplorerNode('resilience/slow_slicing');
expect(await screen.findByText(/Loading current slice/)).toBeVisible();

// Switch to another entity to cancel the fetch
await selectExplorerNode('resilience/slow_value');
expect(await screen.findByText(/Loading data/)).toBeVisible();

// Let pending requests succeed
jest.runAllTimers();

// Reselect dataset and check that it refetches the first slice
await selectExplorerNode('resilience/slow_slicing');
// The slice request was cancelled so it should be pending once again
expect(await screen.findByText(/Loading current slice/)).toBeVisible();

// Let fetch of first slice succeed
jest.runAllTimers();
expect(await screen.findByRole('figure')).toBeVisible();

jest.runOnlyPendingTimers();
jest.useRealTimers();
});

test('cancel fetching dataset slice when changing vis', async () => {
jest.useFakeTimers('modern');
await renderApp();

// Select dataset and start fetching the slice
await selectExplorerNode('resilience/slow_slicing');
expect(await screen.findByText(/Loading current slice/)).toBeVisible();

// Switch to the Line vis to cancel the fetch
userEvent.click(screen.getByRole('tab', { name: 'Line' }));
expect(await screen.findByText(/Loading current slice/)).toBeVisible();

// Let pending requests succeed
jest.runAllTimers();
expect(await screen.findByRole('figure')).toBeVisible();

// Switch back to Heatmap and check that it refetches the slice
userEvent.click(screen.getByRole('tab', { name: 'Heatmap' }));
// The slice request was cancelled so it should be pending once again
expect(await screen.findByText(/Loading current slice/)).toBeVisible();

// Let fetch of the slice succeed
jest.runAllTimers();
expect(await screen.findByRole('figure')).toBeVisible();

jest.runOnlyPendingTimers();
jest.useRealTimers();
});
12 changes: 10 additions & 2 deletions packages/app/src/visualizer/VisManager.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { Entity } from '@h5web/shared';
import { assertDefined } from '@h5web/shared';
import { useState } from 'react';
import { useContext, useState } from 'react';

import Profiler from '../Profiler';
import { ProviderContext } from '../providers/context';
import type { VisDef } from '../vis-packs/models';
import VisSelector from './VisSelector';
import styles from './Visualizer.module.css';
Expand All @@ -28,6 +29,13 @@ function VisManager(props: Props) {

const [visBarElem, setVisBarElem] = useState<HTMLDivElement>();

const { valuesStore } = useContext(ProviderContext);
function onVisChange(vis: VisDef) {
setActiveVis(vis);
valuesStore.cancelOngoing();
valuesStore.evictCancelled();
}

return (
<div className={styles.visManager}>
<div
Expand All @@ -37,7 +45,7 @@ function VisManager(props: Props) {
<VisSelector
activeVis={activeVis}
choices={supportedVis}
onChange={setActiveVis}
onChange={onVisChange}
/>
</div>

Expand Down

0 comments on commit 130cef2

Please sign in to comment.