From d93b4441c47df621c3b69f5a2a0f7f0802f89cd7 Mon Sep 17 00:00:00 2001 From: Oskar Hane Date: Tue, 12 Mar 2019 10:05:32 +0100 Subject: [PATCH] Better UX when closing frame with running query --- src/browser/hooks/useTimedReveal.js | 29 +++++++++ src/browser/hooks/useTimedReveal.test.js | 59 +++++++++++++++++++ .../modules/Stream/CypherFrame/CancelView.jsx | 40 +++++++++++++ .../modules/Stream/CypherFrame/index.jsx | 28 +++------ 4 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 src/browser/hooks/useTimedReveal.js create mode 100644 src/browser/hooks/useTimedReveal.test.js create mode 100644 src/browser/modules/Stream/CypherFrame/CancelView.jsx diff --git a/src/browser/hooks/useTimedReveal.js b/src/browser/hooks/useTimedReveal.js new file mode 100644 index 00000000000..7eb78be106f --- /dev/null +++ b/src/browser/hooks/useTimedReveal.js @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import { useState, useEffect } from 'react' + +export default function useTimedReveal (ms) { + const [reveal, setReveal] = useState(false) + useEffect(() => { + setTimeout(() => setReveal(true), ms) + }, []) + return reveal +} diff --git a/src/browser/hooks/useTimedReveal.test.js b/src/browser/hooks/useTimedReveal.test.js new file mode 100644 index 00000000000..d2a4a0d20c0 --- /dev/null +++ b/src/browser/hooks/useTimedReveal.test.js @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global test, expect, jest */ +import React from 'react' +import { render, act } from 'react-testing-library' +import useTimedReveal from './useTimedReveal' + +jest.useFakeTimers() + +describe('useTimedReveal', () => { + test('children are revealed after the specified time', () => { + // Given + const MyComp = ({ delay, children }) => { + const show = useTimedReveal(delay) + return show ? children : null + } + const delay = 1000 + const text = 'test text' + const children =
{text}
+ + // When + const { queryByText, getByText } = render( + {children} + ) + + // Then + expect(queryByText(text)).toBeNull() + + // When moving timer not enough + act(() => jest.advanceTimersByTime(delay - 1)) + + // Then, still nothing + expect(queryByText(text)).toBeNull() + + // When moving to match the delay + act(() => jest.advanceTimersByTime(1)) + + // Then we should see something + expect(getByText(text)).not.toBeNull() + }) +}) diff --git a/src/browser/modules/Stream/CypherFrame/CancelView.jsx b/src/browser/modules/Stream/CypherFrame/CancelView.jsx new file mode 100644 index 00000000000..91bc797839e --- /dev/null +++ b/src/browser/modules/Stream/CypherFrame/CancelView.jsx @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import React from 'react' +import Centered from 'browser-components/Centered' +import { SpinnerContainer, StyledBodyMessage } from '../styled' +import { Spinner } from 'browser-components/icons/Icons' +import useTimedReveal from 'browser/hooks/useTimedReveal' + +export function CancelView () { + const showClosingMessage = useTimedReveal(1500) + return ( + + + + + +
Terminating active query...
+ {showClosingMessage &&
and closing frame
} +
+
+ ) +} diff --git a/src/browser/modules/Stream/CypherFrame/index.jsx b/src/browser/modules/Stream/CypherFrame/index.jsx index d580b2586cd..df024f63142 100644 --- a/src/browser/modules/Stream/CypherFrame/index.jsx +++ b/src/browser/modules/Stream/CypherFrame/index.jsx @@ -69,7 +69,7 @@ import { shouldAutoComplete } from 'shared/modules/settings/settingsDuck' import { setRecentView, getRecentView } from 'shared/modules/stream/streamDuck' -import { InfoView } from '../InfoView' +import { CancelView } from './CancelView' export class CypherFrame extends Component { visElement = null @@ -359,31 +359,19 @@ export class CypherFrame extends Component { ) } - getCancelingView = () => { - return ( - - The query that was running in this frame is being terminated. -
- This frame will self close soon. - - } - /> - ) - } render () { const { frame = {}, request = {} } = this.props const { cmd: query = '' } = frame const { result = {}, status: requestStatus } = request const frameContents = - requestStatus === REQUEST_STATUS_PENDING - ? this.getSpinner() - : isCancelStatus(requestStatus) - ? this.getCancelingView() - : this.getFrameContents(request, result, query) + requestStatus === REQUEST_STATUS_PENDING ? ( + this.getSpinner() + ) : isCancelStatus(requestStatus) ? ( + + ) : ( + this.getFrameContents(request, result, query) + ) const statusBar = this.state.openView !== viewTypes.VISUALIZATION ? this.getStatusbar(result)