From 15c9a0e1b79962f5f65c0d4a6a04839c87d74f3a Mon Sep 17 00:00:00 2001 From: Amogh Bharadwaj Date: Mon, 4 Mar 2024 22:59:57 +0530 Subject: [PATCH] UI: Collapsible sidebar and fixes (#1418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Collapsible sidebar - Remove extra borders from tables - Change dropdown colors https://github.com/PeerDB-io/peerdb/assets/65964360/e5c1c47f-c4b4-431f-ab60-a9881330dd5a ![Screenshot 2024-02-29 at 10 42 05 PM](https://github.com/PeerDB-io/peerdb/assets/65964360/e07d2e6c-0060-4814-9dd7-3cf0827b5597) --- ui/app/alert-config/new.tsx | 2 + ui/app/alert-config/page.tsx | 5 +- ui/app/mirrors/[mirrorId]/cdc.tsx | 2 + ui/app/mirrors/[mirrorId]/cdcGraph.tsx | 2 + ui/app/mirrors/[mirrorId]/syncStatusTable.tsx | 2 + ui/app/mirrors/[mirrorId]/tablePairs.tsx | 80 ++--- ui/app/mirrors/create/mirrorcards.tsx | 12 +- ui/app/mirrors/create/page.tsx | 329 +++++++++--------- ui/app/mirrors/create/qrep/qrep.tsx | 3 + ui/app/mirrors/create/qrep/upsertcols.tsx | 2 + .../status/qrep/[mirrorId]/qrepGraph.tsx | 2 + .../qrep/[mirrorId]/qrepStatusTable.tsx | 3 - ui/app/mirrors/tables.tsx | 42 +-- ui/app/page.tsx | 2 +- ui/app/peers/[peerName]/lagGraph.tsx | 3 + ui/app/peers/[peerName]/page.tsx | 9 +- ui/app/peers/[peerName]/style.ts | 7 +- ui/app/peers/create/[peerType]/page.tsx | 20 +- ui/app/peers/create/page.tsx | 35 +- ui/app/peers/page.tsx | 4 +- ui/app/peers/peersTable.tsx | 2 + ui/app/styles/select.tsx | 12 + ui/components/PeerInfo.tsx | 6 +- ui/components/SelectSource.tsx | 2 + ui/components/SidebarComponent.tsx | 81 +++-- ui/lib/Layout/Layout.styles.ts | 16 +- ui/lib/Layout/Layout.tsx | 3 +- 27 files changed, 353 insertions(+), 335 deletions(-) create mode 100644 ui/app/styles/select.tsx diff --git a/ui/app/alert-config/new.tsx b/ui/app/alert-config/new.tsx index ffaa41f91b..6a399e4c81 100644 --- a/ui/app/alert-config/new.tsx +++ b/ui/app/alert-config/new.tsx @@ -6,6 +6,7 @@ import ReactSelect from 'react-select'; import { PulseLoader } from 'react-spinners'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import SelectTheme from '../styles/select'; import { alertConfigReqSchema, alertConfigType } from './validation'; export interface AlertConfigProps { @@ -107,6 +108,7 @@ const NewAlertConfig = (alertProps: AlertConfigProps) => { }} formatOptionLabel={ConfigLabel} onChange={(val, _) => val && setServiceType(val.value)} + theme={SelectTheme} />
diff --git a/ui/app/alert-config/page.tsx b/ui/app/alert-config/page.tsx index 7d76872827..514f586155 100644 --- a/ui/app/alert-config/page.tsx +++ b/ui/app/alert-config/page.tsx @@ -10,6 +10,7 @@ import React, { useState } from 'react'; import { PulseLoader } from 'react-spinners'; import useSWR from 'swr'; import { UAlertConfigResponse } from '../dto/AlertDTO'; +import { tableStyle } from '../peers/[peerName]/style'; import { fetcher } from '../utils/swr'; import NewAlertConfig, { AlertConfigProps } from './new'; const ServiceIcon = (serviceType: string) => { @@ -73,9 +74,7 @@ const AlertConfigPage: React.FC = () => { alerts.
-
+
{alerts?.length ? ( alerts.map((alertConfig: UAlertConfigResponse, index) => ( diff --git a/ui/app/mirrors/[mirrorId]/cdc.tsx b/ui/app/mirrors/[mirrorId]/cdc.tsx index 3ca1737251..61ebc03434 100644 --- a/ui/app/mirrors/[mirrorId]/cdc.tsx +++ b/ui/app/mirrors/[mirrorId]/cdc.tsx @@ -1,5 +1,6 @@ 'use client'; import { SyncStatusRow } from '@/app/dto/MirrorsDTO'; +import SelectTheme from '@/app/styles/select'; import TimeLabel from '@/components/TimeComponent'; import { CloneTableSummary, @@ -153,6 +154,7 @@ export const SnapshotStatusTable = ({ status }: SnapshotStatusProps) => { value: 'cloneStartTime', label: 'Start Time', }} + theme={SelectTheme} />
+
+ Source Table + Destination Table + + } > - - ( + - - - - - - {shownTables?.map((table) => ( - - - - - ))} - -
- Source Table - - Destination Table -
- {table.sourceTableIdentifier} - - {table.destinationTableIdentifier} -
+ {table.sourceTableIdentifier} + + {table.destinationTableIdentifier} + + + ))} +
); diff --git a/ui/app/mirrors/create/mirrorcards.tsx b/ui/app/mirrors/create/mirrorcards.tsx index 207f4be3b4..6cf2dcd348 100644 --- a/ui/app/mirrors/create/mirrorcards.tsx +++ b/ui/app/mirrors/create/mirrorcards.tsx @@ -46,7 +46,6 @@ const MirrorCards = ({ style={{ padding: '0.5rem', width: '35%', - minHeight: '22vh', marginRight: card.title === 'Query Replication' ? '0.5rem' : 'auto', marginLeft: @@ -71,14 +70,17 @@ const MirrorCards = ({
{card.description}
- + ); })} diff --git a/ui/app/mirrors/create/page.tsx b/ui/app/mirrors/create/page.tsx index 76052329d7..4d79fea628 100644 --- a/ui/app/mirrors/create/page.tsx +++ b/ui/app/mirrors/create/page.tsx @@ -1,4 +1,5 @@ 'use client'; +import SelectTheme from '@/app/styles/select'; import { DBTypeToImageMapping } from '@/components/PeerComponent'; import { RequiredIndicator } from '@/components/RequiredIndicator'; import { QRepConfig } from '@/grpc_generated/flow'; @@ -105,183 +106,195 @@ export default function CreateMirrors() { }; return ( -
- - - - - - - - Mirror Name} - action={ - ) => - setMirrorName(e.target.value) - } - /> - } - /> - {['src', 'dst'].map((peerEnd, index) => { - return ( - - {peerEnd === 'src' ? 'Source Peer' : 'Destination Peer'} - {RequiredIndicator(true)} - - } - action={ -
-
- - handlePeer(val, peerEnd as 'src' | 'dst', setConfig) +
+
+ + + + + + + + Mirror Name} + action={ + ) => + setMirrorName(e.target.value) + } + /> + } + /> + {['src', 'dst'].map((peerEnd, index) => { + return ( + + {peerEnd === 'src' ? 'Source Peer' : 'Destination Peer'} + {RequiredIndicator(true)} + + } + action={ +
+
+ + handlePeer(val, peerEnd as 'src' | 'dst', setConfig) + } + options={ + (peerEnd === 'src' + ? peers.filter( + (peer) => peer.type == DBType.POSTGRES + ) + : peers) ?? [] + } + getOptionValue={getPeerValue} + formatOptionLabel={getPeerLabel} + theme={SelectTheme} + /> +
+ peer.type == DBType.POSTGRES) - : peers) ?? [] + link={ + 'https://docs.peerdb.io/usecases/Real-time%20CDC/postgres-to-snowflake#prerequisites' } - getOptionValue={getPeerValue} - formatOptionLabel={getPeerLabel} />
- -
- } - /> - ); - })} + } + /> + ); + })} - + - {mirrorType === 'Query Replication' && ( - - )} + {mirrorType === 'Query Replication' && ( + + )} - {mirrorType && ( - - )} - {!creating && } - {mirrorType === '' ? ( - <> - ) : mirrorType === 'CDC' ? ( - - ) : ( - - )} - - - {mirrorType && ( -
- {mirrorType === 'CDC' && ( + {mirrorType && ( + + )} + {!creating && } + {mirrorType === '' ? ( + <> + ) : mirrorType === 'CDC' ? ( + + ) : ( + + )} + + + {mirrorType && ( +
+ {mirrorType === 'CDC' && ( + + )} - )} - -
- )} -
+
+ )} +
+
); } diff --git a/ui/app/mirrors/create/qrep/qrep.tsx b/ui/app/mirrors/create/qrep/qrep.tsx index 28a7adc282..ecd4a63630 100644 --- a/ui/app/mirrors/create/qrep/qrep.tsx +++ b/ui/app/mirrors/create/qrep/qrep.tsx @@ -1,4 +1,5 @@ 'use client'; +import SelectTheme from '@/app/styles/select'; import { RequiredIndicator } from '@/components/RequiredIndicator'; import { QRepConfig, QRepWriteType } from '@/grpc_generated/flow'; import { DBType } from '@/grpc_generated/peers'; @@ -202,6 +203,7 @@ export default function QRepConfigForm({ val && handleChange(val.value, setting) } options={WriteModes} + theme={SelectTheme} /> ) : setting.label === 'Upsert Key Columns' ? ( )}
diff --git a/ui/app/mirrors/create/qrep/upsertcols.tsx b/ui/app/mirrors/create/qrep/upsertcols.tsx index cd1009f48f..e49e004886 100644 --- a/ui/app/mirrors/create/qrep/upsertcols.tsx +++ b/ui/app/mirrors/create/qrep/upsertcols.tsx @@ -1,4 +1,5 @@ 'use client'; +import SelectTheme from '@/app/styles/select'; import { QRepConfig, QRepWriteMode, @@ -69,6 +70,7 @@ const UpsertColsDisplay = ({ }} isLoading={loading} options={columns} + theme={SelectTheme} />
val && setAggregateType(val.value)} + theme={SelectTheme} />
diff --git a/ui/app/mirrors/status/qrep/[mirrorId]/qrepStatusTable.tsx b/ui/app/mirrors/status/qrep/[mirrorId]/qrepStatusTable.tsx index 667ddcbff4..d0a01a1468 100644 --- a/ui/app/mirrors/status/qrep/[mirrorId]/qrepStatusTable.tsx +++ b/ui/app/mirrors/status/qrep/[mirrorId]/qrepStatusTable.tsx @@ -162,9 +162,6 @@ export default function QRepStatusTable({ > -
(''); @@ -23,26 +23,8 @@ export function CDCFlows({ cdcFlows }: { cdcFlows: any }) { return ( <> -
+
, - right: ( - ) => - setSearchQuery(e.target.value) - } - /> - ), - }} header={ {['Name', 'Source', 'Destination', 'Start Time', 'Logs', ''].map( @@ -131,26 +113,8 @@ export function QRepFlows({ return ( <> -
+
, - right: ( - ) => - setSearchQuery(e.target.value) - } - /> - ), - }} header={ {['Name', 'Source', 'Destination', 'Start Time', ''].map( diff --git a/ui/app/page.tsx b/ui/app/page.tsx index 4e84221bb7..83a0f1ccd6 100644 --- a/ui/app/page.tsx +++ b/ui/app/page.tsx @@ -5,7 +5,7 @@ import { Layout, LayoutMain } from '@/lib/Layout'; export default function Home() { return ( }> - +
PeerDB Home Page
diff --git a/ui/app/peers/[peerName]/lagGraph.tsx b/ui/app/peers/[peerName]/lagGraph.tsx index 31dbef3062..82f0ed9aae 100644 --- a/ui/app/peers/[peerName]/lagGraph.tsx +++ b/ui/app/peers/[peerName]/lagGraph.tsx @@ -1,5 +1,6 @@ 'use client'; import { SlotLagPoint } from '@/app/dto/PeersDTO'; +import SelectTheme from '@/app/styles/select'; import { formatGraphLabel, timeOptions } from '@/app/utils/graph'; import { Label } from '@/lib/Label'; import { ProgressCircle } from '@/lib/ProgressCircle/ProgressCircle'; @@ -92,6 +93,7 @@ function LagGraph({ slotNames }: { slotNames: string[] }) { ? { value: selectedSlot, label: selectedSlot } : undefined } + theme={SelectTheme} /> val && setTimeSince(val.value)} + theme={SelectTheme} /> { const stats = await getStatData(); return ( -
+
- - {configComponentMap(dbType)} - - + @@ -50,7 +63,7 @@ export default function CreatePeer() { - - +
+
); } diff --git a/ui/app/peers/page.tsx b/ui/app/peers/page.tsx index 34eea42f91..d7812e54c0 100644 --- a/ui/app/peers/page.tsx +++ b/ui/app/peers/page.tsx @@ -18,8 +18,8 @@ export default function Peers() { const { data: peers, error, isLoading } = useSWR('/api/peers', fetcher); return ( - - + +
({ + ...theme, + colors: { + ...theme.colors, + primary25: 'rgba(48, 164, 108, 0.3)', + primary: 'rgba(48, 164, 108, 0.3)', + }, +}); + +export default SelectTheme; diff --git a/ui/components/PeerInfo.tsx b/ui/components/PeerInfo.tsx index bdff740032..9c6cf79eb0 100644 --- a/ui/components/PeerInfo.tsx +++ b/ui/components/PeerInfo.tsx @@ -26,10 +26,8 @@ export const PeerInfo = ({ peerName }: { peerName: string }) => { size='auto' style={{ width: '40rem' }} triggerButton={ - } > diff --git a/ui/components/SelectSource.tsx b/ui/components/SelectSource.tsx index 04cc5bf3a3..4aefe67082 100644 --- a/ui/components/SelectSource.tsx +++ b/ui/components/SelectSource.tsx @@ -1,4 +1,5 @@ 'use client'; +import SelectTheme from '@/app/styles/select'; import { DBType } from '@/grpc_generated/peers'; import Image from 'next/image'; import { Dispatch, SetStateAction } from 'react'; @@ -44,6 +45,7 @@ export default function SelectSource({ defaultValue={dbTypes.find((opt) => opt.value === peerType)} onChange={(val, _) => val && setPeerType(val.value)} formatOptionLabel={SourceLabel} + theme={SelectTheme} /> ); } diff --git a/ui/components/SidebarComponent.tsx b/ui/components/SidebarComponent.tsx index 0ecf06598b..750648ef51 100644 --- a/ui/components/SidebarComponent.tsx +++ b/ui/components/SidebarComponent.tsx @@ -4,6 +4,7 @@ import { UVersionResponse } from '@/app/dto/VersionDTO'; import { fetcher } from '@/app/utils/swr'; import Logout from '@/components/Logout'; import { BrandLogo } from '@/lib/BrandLogo'; +import { Button } from '@/lib/Button'; import { Icon } from '@/lib/Icon'; import { Label } from '@/lib/Label'; import { RowWithSelect } from '@/lib/Layout'; @@ -21,33 +22,61 @@ const centerFlexStyle = { marginBottom: '0.5rem', }; -export default function SidebarComponent(props: {}) { +export default function SidebarComponent() { const timezones = ['UTC', 'Local', 'Relative']; const [zone, setZone] = useLocalStorage('timezone-ui', ''); const { data: version, - error, isLoading, }: { data: UVersionResponse; error: any; isLoading: boolean } = useSWR( '/api/version', fetcher ); + const [sidebarState, setSidebarState] = useLocalStorage( + 'peerdb-sidebar', + 'open' + ); return ( -
- -
- +
+ {sidebarState === 'open' && ( + + )} + +
} bottomRow={ - <> -
-
+ sidebarState === 'open' ? ( + <> +
Timezone:} action={ @@ -73,18 +102,24 @@ export default function SidebarComponent(props: {}) { } />
-
- - + + + ) : ( + <> + ) } bottomLabel={ -
- -
+ sidebarState === 'open' ? ( +
+ +
+ ) : ( + <> + ) } > } > - Peers + {sidebarState === 'open' && 'Peers'} } > - Mirrors + {sidebarState === 'open' && 'Mirrors'} } > - Alert Configuration + {sidebarState === 'open' && 'Alert Configuration'} diff --git a/ui/lib/Layout/Layout.styles.ts b/ui/lib/Layout/Layout.styles.ts index d9ac6fadd0..61fc360aa6 100644 --- a/ui/lib/Layout/Layout.styles.ts +++ b/ui/lib/Layout/Layout.styles.ts @@ -1,25 +1,17 @@ import styled from 'styled-components'; export const LayoutWrapper = styled.div` - display: grid; - grid-template-columns: 250px auto; + display: flex; background-color: ${({ theme }) => theme.colors.base.background.normal}; min-height: 100vh; + width: 100vw; `; -export type ContentWrapperProps = { - $fullWidth?: boolean; -}; - -export const ContentWrapper = styled.div` - grid-column: ${({ $fullWidth = false }) => - $fullWidth ? '1 / -1' : '2 / -1'}; +export const ContentWrapper = styled.div` background-color: ${({ theme }) => theme.colors.base.background.normal}; padding: ${({ theme }) => theme.spacing.medium}; - overflow-y: auto; - - display: grid; height: 100vh; + width: 100%; overflow-y: auto; `; diff --git a/ui/lib/Layout/Layout.tsx b/ui/lib/Layout/Layout.tsx index 97222c0f65..28b41fed65 100644 --- a/ui/lib/Layout/Layout.tsx +++ b/ui/lib/Layout/Layout.tsx @@ -81,12 +81,11 @@ type LayoutProps = PropsWithChildren<{ }>; export function Layout({ sidebar, children }: LayoutProps) { const Sidebar = isDefined(sidebar) && sidebar; - const fullWidth = !isDefined(sidebar); return ( {Sidebar} - {children} + {children} ); }