statusbar - show query execution duration

This commit is contained in:
Jan Prochazka
2021-01-28 12:49:00 +01:00
parent 8396e726ec
commit 51ba9d3b5a
5 changed files with 128 additions and 53 deletions

View File

@@ -100,6 +100,7 @@ export default function Screen() {
? dimensions.widgetMenu.iconSize + leftPanelWidth + dimensions.splitter.thickness ? dimensions.widgetMenu.iconSize + leftPanelWidth + dimensions.splitter.thickness
: dimensions.widgetMenu.iconSize; : dimensions.widgetMenu.iconSize;
const toolbarPortalRef = React.useRef(); const toolbarPortalRef = React.useRef();
const statusbarPortalRef = React.useRef();
const onSplitDown = useSplitterDrag('clientX', diff => setLeftPanelWidth(v => v + diff)); const onSplitDown = useSplitterDrag('clientX', diff => setLeftPanelWidth(v => v + diff));
const { getRootProps, getInputProps, isDragActive } = useUploadsZone(); const { getRootProps, getInputProps, isDragActive } = useUploadsZone();
@@ -131,10 +132,10 @@ export default function Screen() {
<TabsPanel></TabsPanel> <TabsPanel></TabsPanel>
</TabsPanelContainer> </TabsPanelContainer>
<BodyDiv contentLeft={contentLeft} theme={theme}> <BodyDiv contentLeft={contentLeft} theme={theme}>
<TabContent toolbarPortalRef={toolbarPortalRef} /> <TabContent toolbarPortalRef={toolbarPortalRef} statusbarPortalRef={statusbarPortalRef} />
</BodyDiv> </BodyDiv>
<StausBarContainer theme={theme}> <StausBarContainer theme={theme}>
<StatusBar /> <StatusBar statusbarPortalRef={statusbarPortalRef} />
</StausBarContainer> </StausBarContainer>
<ModalLayer /> <ModalLayer />
<MenuLayer /> <MenuLayer />

View File

@@ -18,12 +18,18 @@ const TabContainerStyled = styled.div`
`; `;
function TabContainer({ TabComponent, ...props }) { function TabContainer({ TabComponent, ...props }) {
const { tabVisible, tabid, toolbarPortalRef } = props; const { tabVisible, tabid, toolbarPortalRef, statusbarPortalRef } = props;
return ( return (
// @ts-ignore // @ts-ignore
<TabContainerStyled tabVisible={tabVisible}> <TabContainerStyled tabVisible={tabVisible}>
<ErrorBoundary> <ErrorBoundary>
<TabComponent {...props} tabid={tabid} tabVisible={tabVisible} toolbarPortalRef={toolbarPortalRef} /> <TabComponent
{...props}
tabid={tabid}
tabVisible={tabVisible}
toolbarPortalRef={toolbarPortalRef}
statusbarPortalRef={statusbarPortalRef}
/>
</ErrorBoundary> </ErrorBoundary>
</TabContainerStyled> </TabContainerStyled>
); );
@@ -42,7 +48,7 @@ function createTabComponent(selectedTab) {
return null; return null;
} }
export default function TabContent({ toolbarPortalRef }) { export default function TabContent({ toolbarPortalRef, statusbarPortalRef }) {
const files = useOpenedTabs(); const files = useOpenedTabs();
const [mountedTabs, setMountedTabs] = React.useState({}); const [mountedTabs, setMountedTabs] = React.useState({});
@@ -84,6 +90,7 @@ export default function TabContent({ toolbarPortalRef }) {
tabid={tabid} tabid={tabid}
tabVisible={tabVisible} tabVisible={tabVisible}
toolbarPortalRef={toolbarPortalRef} toolbarPortalRef={toolbarPortalRef}
statusbarPortalRef={statusbarPortalRef}
TabComponent={TabComponent} TabComponent={TabComponent}
/> />
); );

View File

@@ -21,8 +21,19 @@ import useEditorData from '../utility/useEditorData';
import applySqlTemplate from '../utility/applySqlTemplate'; import applySqlTemplate from '../utility/applySqlTemplate';
import LoadingInfo from '../widgets/LoadingInfo'; import LoadingInfo from '../widgets/LoadingInfo';
import useExtensions from '../utility/useExtensions'; import useExtensions from '../utility/useExtensions';
import useTimerLabel from '../utility/useTimerLabel';
import { StatusBarItem } from '../widgets/StatusBar';
export default function QueryTab({ tabid, conid, database, initialArgs, tabVisible, toolbarPortalRef, ...other }) { export default function QueryTab({
tabid,
conid,
database,
initialArgs,
tabVisible,
toolbarPortalRef,
statusbarPortalRef,
...other
}) {
const [sessionId, setSessionId] = React.useState(null); const [sessionId, setSessionId] = React.useState(null);
const [visibleResultTabs, setVisibleResultTabs] = React.useState(false); const [visibleResultTabs, setVisibleResultTabs] = React.useState(false);
const [executeNumber, setExecuteNumber] = React.useState(0); const [executeNumber, setExecuteNumber] = React.useState(0);
@@ -31,6 +42,7 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
const [busy, setBusy] = React.useState(false); const [busy, setBusy] = React.useState(false);
const saveFileModalState = useModalState(); const saveFileModalState = useModalState();
const extensions = useExtensions(); const extensions = useExtensions();
const timerLabel = useTimerLabel();
const { editorData, setEditorData, isLoading } = useEditorData({ const { editorData, setEditorData, isLoading } = useEditorData({
tabid, tabid,
loadFromArgs: loadFromArgs:
@@ -43,6 +55,7 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
const handleSessionDone = React.useCallback(() => { const handleSessionDone = React.useCallback(() => {
setBusy(false); setBusy(false);
timerLabel.stop();
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
@@ -77,6 +90,7 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
setSessionId(sesid); setSessionId(sesid);
} }
setBusy(true); setBusy(true);
timerLabel.start();
await axios.post('sessions/execute-query', { await axios.post('sessions/execute-query', {
sesid, sesid,
sql: selectedText || editorData, sql: selectedText || editorData,
@@ -95,6 +109,7 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
}); });
setSessionId(null); setSessionId(null);
setBusy(false); setBusy(false);
timerLabel.stop();
}; };
const handleKeyDown = (data, hash, keyString, keyCode, event) => { const handleKeyDown = (data, hash, keyString, keyCode, event) => {
@@ -167,6 +182,10 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
/>, />,
toolbarPortalRef.current toolbarPortalRef.current
)} )}
{statusbarPortalRef &&
statusbarPortalRef.current &&
tabVisible &&
ReactDOM.createPortal(<StatusBarItem>{timerLabel.text}</StatusBarItem>, statusbarPortalRef.current)}
<SaveTabModal <SaveTabModal
modalState={saveFileModalState} modalState={saveFileModalState}
tabVisible={tabVisible} tabVisible={tabVisible}

View File

@@ -0,0 +1,37 @@
import React from 'react';
import _ from 'lodash';
function formatSeconds(duration) {
if (duration == null) return '';
const hours = _.padStart(Math.floor(duration / 3600).toString(), 2, '0');
const minutes = _.padStart((Math.floor(duration / 60) % 60).toString(), 2, '0');
const seconds = _.padStart((duration % 60).toString(), 2, '0');
return `${hours}:${minutes}:${seconds}`;
}
export default function useTimerLabel() {
const [duration, setDuration] = React.useState(null);
const [busy, setBusy] = React.useState(false);
React.useEffect(() => {
if (busy) {
setDuration(0);
const handle = setInterval(() => setDuration(x => x + 1), 1000);
return () => window.clearInterval(handle);
}
}, [busy]);
const start = React.useCallback(() => {
setBusy(true);
}, []);
const stop = React.useCallback(() => {
setBusy(false);
}, []);
return {
start,
stop,
text: formatSeconds(duration),
duration,
};
}

View File

@@ -10,9 +10,10 @@ const Container = styled.div`
display: flex; display: flex;
color: ${props => props.theme.statusbar_font1}; color: ${props => props.theme.statusbar_font1};
align-items: stretch; align-items: stretch;
justify-content: space-between;
`; `;
const Item = styled.div` export const StatusBarItem = styled.div`
padding: 2px 10px; padding: 2px 10px;
// margin: auto; // margin: auto;
// flex-grow: 0; // flex-grow: 0;
@@ -30,62 +31,72 @@ const InfoWrapper = styled.span`
props.theme.statusbar_font_green[5]}; props.theme.statusbar_font_green[5]};
`; `;
export default function StatusBar() { const StatusbarContainer = styled.div`
display: flex;
// align-items: flex-end;
// display: flex;
// user-select: none;
`;
export default function StatusBar({ statusbarPortalRef }) {
const { name, connection } = useCurrentDatabase() || {}; const { name, connection } = useCurrentDatabase() || {};
const status = useDatabaseStatus(connection ? { conid: connection._id, database: name } : {}); const status = useDatabaseStatus(connection ? { conid: connection._id, database: name } : {});
const { displayName, server, user, engine } = connection || {}; const { displayName, server, user, engine } = connection || {};
const theme = useTheme(); const theme = useTheme();
return ( return (
<Container theme={theme}> <Container theme={theme}>
{name && ( <StatusbarContainer>
<Item> {name && (
<FontIcon icon="icon database" /> {name} <StatusBarItem>
</Item> <FontIcon icon="icon database" /> {name}
)} </StatusBarItem>
{(displayName || server) && ( )}
<Item> {(displayName || server) && (
<FontIcon icon="icon server" /> {displayName || server} <StatusBarItem>
</Item> <FontIcon icon="icon server" /> {displayName || server}
)} </StatusBarItem>
)}
{user && ( {user && (
<Item> <StatusBarItem>
<FontIcon icon="icon account" /> {user} <FontIcon icon="icon account" /> {user}
</Item> </StatusBarItem>
)} )}
{connection && status && ( {connection && status && (
<Item> <StatusBarItem>
{status.name == 'pending' && ( {status.name == 'pending' && (
<>
<FontIcon icon="icon loading" /> Loading
</>
)}
{status.name == 'ok' && (
<>
<InfoWrapper theme={theme}>
<FontIcon icon="icon ok" />
</InfoWrapper>{' '}
Connected
</>
)}
{status.name == 'error' && (
<>
<ErrorWrapper theme={theme}>
<FontIcon icon="icon error" />
</ErrorWrapper>{' '}
Error
</>
)}
</StatusBarItem>
)}
{!connection && (
<StatusBarItem>
<> <>
<FontIcon icon="icon loading" /> Loading <FontIcon icon="icon disconnected" /> Not connected
</> </>
)} </StatusBarItem>
{status.name == 'ok' && ( )}
<> </StatusbarContainer>
<InfoWrapper theme={theme}> <StatusbarContainer ref={statusbarPortalRef}></StatusbarContainer>
<FontIcon icon="icon ok" />
</InfoWrapper>{' '}
Connected
</>
)}
{status.name == 'error' && (
<>
<ErrorWrapper theme={theme}>
<FontIcon icon="icon error" />
</ErrorWrapper>{' '}
Error
</>
)}
</Item>
)}
{!connection && (
<Item>
<>
<FontIcon icon="icon disconnected" /> Not connected
</>
</Item>
)}
</Container> </Container>
); );
} }