diff --git a/packages/web-console/assets/create-table.svg b/packages/web-console/assets/create-table.svg new file mode 100644 index 000000000..853085cfb --- /dev/null +++ b/packages/web-console/assets/create-table.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/web-console/assets/upload.svg b/packages/web-console/assets/upload.svg index baa8cf17f..8ca18f456 100644 --- a/packages/web-console/assets/upload.svg +++ b/packages/web-console/assets/upload.svg @@ -1,12 +1,17 @@ - - - - - + + + + + + + + + + - + diff --git a/packages/web-console/src/components/CreateTableDialog/index.tsx b/packages/web-console/src/components/CreateTableDialog/index.tsx index 9c0a648f3..72f947220 100644 --- a/packages/web-console/src/components/CreateTableDialog/index.tsx +++ b/packages/web-console/src/components/CreateTableDialog/index.tsx @@ -36,9 +36,7 @@ export const CreateTableDialog = () => { } useEffect(() => { - if (activeSidebar === "news") { - setAddTableDialogOpen(undefined) - } + setAddTableDialogOpen(activeSidebar === "create" ? "add" : undefined) }, [activeSidebar]) useEffect(() => { @@ -67,8 +65,10 @@ export const CreateTableDialog = () => { - setAddTableDialogOpen( - addTableDialogOpen === undefined ? "add" : undefined, + dispatch( + actions.console.setActiveSidebar( + addTableDialogOpen ? undefined : "create", + ), ) } > diff --git a/packages/web-console/src/scenes/Console/index.tsx b/packages/web-console/src/scenes/Console/index.tsx index b39c2ac30..d15f0a604 100644 --- a/packages/web-console/src/scenes/Console/index.tsx +++ b/packages/web-console/src/scenes/Console/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from "react" +import { useDispatch } from "react-redux" import styled from "styled-components" import { Splitter, useScreenSize, PopperHover } from "../../components" import Editor from "../Editor" @@ -10,7 +11,7 @@ import { BusEvent } from "../../consts" import { useLocalStorage } from "../../providers/LocalStorageProvider" import { StoreKey } from "../../utils/localStorage/types" import { useSelector } from "react-redux" -import { selectors } from "../../store" +import { actions, selectors } from "../../store" import { Tooltip } from "../../components/Tooltip" import { Sidebar } from "../../components/Sidebar" import { Navigation } from "../../components/Sidebar/navigation" @@ -19,6 +20,7 @@ import { ResultViewMode } from "./types" import { BUTTON_ICON_SIZE } from "../../consts/index" import { PrimaryToggleButton } from "../../components" import { Import } from "./import" +import { BottomPanel } from "../../store/Console/types" const Root = styled.div` display: flex; @@ -62,15 +64,14 @@ const viewModes: { }, ] -type BottomPanel = "result" | "zeroState" | "import" - const Console = () => { + const dispatch = useDispatch() const { sm } = useScreenSize() const { editorSplitterBasis, resultsSplitterBasis, updateSettings } = useLocalStorage() const result = useSelector(selectors.query.getResult) + const activeBottomPanel = useSelector(selectors.console.getActiveBottomPanel) const [resultViewMode, setResultViewMode] = useState("grid") - const [bottomPanel, setBottomPanel] = useState("zeroState") const resultRef = React.useRef(null) const zeroStateRef = React.useRef(null) const importRef = React.useRef(null) @@ -104,17 +105,15 @@ const Console = () => { useEffect(() => { if (resultRef.current && result) { - setBottomPanel("result") + dispatch(actions.console.setActiveBottomPanel("result")) } else if (zeroStateRef.current) { - setBottomPanel("zeroState") + dispatch(actions.console.setActiveBottomPanel("zeroState")) } }, [result]) useEffect(() => { - if (bottomPanel) { - showPanel(bottomPanel) - } - }, [bottomPanel]) + showPanel(activeBottomPanel) + }, [activeBottomPanel]) return ( @@ -169,11 +168,12 @@ const Console = () => { { - setBottomPanel("result") + dispatch(actions.console.setActiveBottomPanel("result")) setResultViewMode(mode) }} selected={ - bottomPanel === "result" && resultViewMode === mode + activeBottomPanel === "result" && + resultViewMode === mode } > {icon} @@ -187,8 +187,10 @@ const Console = () => { placement="right" trigger={ setBottomPanel("import")} - selected={bottomPanel === "import"} + onClick={() => { + dispatch(actions.console.setActiveBottomPanel("import")) + }} + selected={activeBottomPanel === "import"} > diff --git a/packages/web-console/src/scenes/Console/zero-state.tsx b/packages/web-console/src/scenes/Console/zero-state.tsx index 9352573b8..12345d987 100644 --- a/packages/web-console/src/scenes/Console/zero-state.tsx +++ b/packages/web-console/src/scenes/Console/zero-state.tsx @@ -1,7 +1,14 @@ import React from "react" import styled from "styled-components" -import { PaneContent, PaneWrapper, Text } from "../../components" -import { Heading } from "@questdb/react-components" +import { + bezierTransition, + PaneContent, + PaneWrapper, + Text, +} from "../../components" +import { Box, Heading } from "@questdb/react-components" +import { actions } from "../../store" +import { useDispatch } from "react-redux" const StyledPaneContent = styled(PaneContent)` align-items: center; @@ -12,8 +19,9 @@ const Items = styled.div` display: grid; grid-auto-flow: row; grid-auto-columns: max-content; - gap: 2rem; + gap: 4rem; text-align: center; + justify-items: center; ` const StyledHeading = styled(Heading)` @@ -28,27 +36,89 @@ const StyledText = styled(Text)` } ` -export const ZeroState = () => ( - - - - - Enter a query and press Run to view - results. - - - Get $200 in free credits when you sign up for{" "} - - QuestDB Cloud - - .
- No credit card required. - - - - -) +const Actions = styled.div` + display: grid; + gap: 2rem; + grid-template-columns: repeat(2, 1fr); +` + +const Action = styled(Box).attrs({ flexDirection: "column", gap: "2rem" })` + padding: 2rem; + border-radius: ${({ theme }) => theme.borderRadius}; + background: #2c2e3d; + cursor: pointer; + + &, + &:hover { + ${bezierTransition}; + } + + > * { + opacity: 0.8; + } + + &:hover { + background: #3f4252; + + > * { + opacity: 1; + } + } +` + +export const ZeroState = () => { + const dispatch = useDispatch() + + return ( + + + + + Enter a query and press Run to view + results. + + + + dispatch(actions.console.setActiveBottomPanel("import")) + } + > + File upload icon + Import CSV + + + dispatch(actions.console.setActiveSidebar("create")) + } + > + Create table icon + Create table + + + + Get $200 in free credits when you sign up for{" "} + + QuestDB Cloud + + .
+ No credit card required. +
+
+
+
+ ) +} diff --git a/packages/web-console/src/store/Console/actions.ts b/packages/web-console/src/store/Console/actions.ts index 8c6dda3ef..b71c4a4f0 100644 --- a/packages/web-console/src/store/Console/actions.ts +++ b/packages/web-console/src/store/Console/actions.ts @@ -25,8 +25,9 @@ import { ConsoleConfigShape, ConsoleAction, ConsoleAT, - Panel, -} from "../../types" + Sidebar, + BottomPanel, +} from "./types" const bootstrap = (): ConsoleAction => ({ type: ConsoleAT.BOOTSTRAP, @@ -42,11 +43,16 @@ const setConfig = (payload: ConsoleConfigShape): ConsoleAction => ({ type: ConsoleAT.SET_CONFIG, }) -const setActiveSidebar = (panel: Panel): ConsoleAction => ({ +const setActiveSidebar = (panel: Sidebar): ConsoleAction => ({ payload: panel, type: ConsoleAT.SET_ACTIVE_SIDEBAR, }) +const setActiveBottomPanel = (panel: BottomPanel): ConsoleAction => ({ + payload: panel, + type: ConsoleAT.SET_ACTIVE_BOTTOM_PANEL, +}) + const toggleSideMenu = (): ConsoleAction => ({ type: ConsoleAT.TOGGLE_SIDE_MENU, }) @@ -57,4 +63,5 @@ export default { setConfig, toggleSideMenu, setActiveSidebar, + setActiveBottomPanel, } diff --git a/packages/web-console/src/store/Console/reducers.ts b/packages/web-console/src/store/Console/reducers.ts index 81ed3ea71..7cf4777ad 100644 --- a/packages/web-console/src/store/Console/reducers.ts +++ b/packages/web-console/src/store/Console/reducers.ts @@ -32,6 +32,7 @@ import { export const initialState: ConsoleStateShape = { sideMenuOpened: false, activeSidebar: undefined, + activeBottomPanel: "zeroState", } export const defaultConfig: ConsoleConfigShape = { @@ -69,6 +70,13 @@ const _console = ( } } + case ConsoleAT.SET_ACTIVE_BOTTOM_PANEL: { + return { + ...state, + activeBottomPanel: action.payload, + } + } + default: return state } diff --git a/packages/web-console/src/store/Console/selectors.ts b/packages/web-console/src/store/Console/selectors.ts index 619ae8f7e..bf2937c34 100644 --- a/packages/web-console/src/store/Console/selectors.ts +++ b/packages/web-console/src/store/Console/selectors.ts @@ -21,7 +21,7 @@ * limitations under the License. * ******************************************************************************/ -import { ConsoleConfigShape, StoreShape, Panel } from "types" +import { ConsoleConfigShape, StoreShape, Sidebar, BottomPanel } from "types" import { defaultConfig } from "./reducers" @@ -31,11 +31,15 @@ const getConfig: (store: StoreShape) => ConsoleConfigShape = (store) => const getSideMenuOpened: (store: StoreShape) => boolean = (store) => store.console.sideMenuOpened -const getActiveSidebar: (store: StoreShape) => Panel = (store) => +const getActiveSidebar: (store: StoreShape) => Sidebar = (store) => store.console.activeSidebar +const getActiveBottomPanel: (store: StoreShape) => BottomPanel = (store) => + store.console.activeBottomPanel + export default { getConfig, getSideMenuOpened, getActiveSidebar, + getActiveBottomPanel, } diff --git a/packages/web-console/src/store/Console/types.ts b/packages/web-console/src/store/Console/types.ts index 0cf798784..7371e5803 100644 --- a/packages/web-console/src/store/Console/types.ts +++ b/packages/web-console/src/store/Console/types.ts @@ -33,7 +33,9 @@ export type QueryGroup = { queries: Query[] } -export type Panel = "news" | "create" | undefined +export type Sidebar = "news" | "create" | undefined + +export type BottomPanel = "result" | "zeroState" | "import" export type ConsoleConfigShape = Readonly<{ githubBanner: boolean @@ -44,7 +46,8 @@ export type ConsoleConfigShape = Readonly<{ export type ConsoleStateShape = Readonly<{ config?: ConsoleConfigShape sideMenuOpened: boolean - activeSidebar: Panel + activeSidebar: Sidebar + activeBottomPanel: BottomPanel }> export enum ConsoleAT { @@ -53,6 +56,7 @@ export enum ConsoleAT { SET_CONFIG = "CONSOLE/SET_CONFIG", TOGGLE_SIDE_MENU = "CONSOLE/TOGGLE_SIDE_MENU", SET_ACTIVE_SIDEBAR = "CONSOLE/SET_ACTIVE_SIDEBAR", + SET_ACTIVE_BOTTOM_PANEL = "CONSOLE/SET_ACTIVE_BOTTOM_PANEL", } export type BootstrapAction = Readonly<{ @@ -74,13 +78,19 @@ type ToggleSideMenuAction = Readonly<{ }> type setActiveSidebarAction = Readonly<{ - payload: Panel + payload: Sidebar type: ConsoleAT.SET_ACTIVE_SIDEBAR }> +type setActiveBottomPanelAction = Readonly<{ + payload: BottomPanel + type: ConsoleAT.SET_ACTIVE_BOTTOM_PANEL +}> + export type ConsoleAction = | BootstrapAction | RefreshAuthTokenAction | SetConfigAction | ToggleSideMenuAction | setActiveSidebarAction + | setActiveBottomPanelAction