From 34086547b79277761b33014d1bb7e2c3c0c727db Mon Sep 17 00:00:00 2001 From: Tom Jeannesson Date: Fri, 20 Oct 2023 14:31:09 +0200 Subject: [PATCH] feat(layouts): streamlined settings layout for all objects --- desktop-app/.eslintrc.json | 3 +- .../api/exchangeAccounts/exchangeAccount.ts | 40 +++- desktop-app/renderer/api/request.ts | 2 +- .../components/custom/headerPopover.tsx | 139 +++++++------- .../components/custom/panel/infoPanelCard.tsx | 2 +- .../components/custom/panel/panelCard.tsx | 19 +- .../custom/selectedObject/inputs.tsx | 88 +++++++++ .../custom/selectedObject/selectedObject.tsx | 171 +++++++++++++++++ .../components/custom/selectedObject/tabs.tsx | 34 ++++ .../components/layout/contextHeader.tsx | 2 +- .../renderer/components/ui/use-toast.ts | 2 +- desktop-app/renderer/pages/404.tsx | 7 +- .../pages/exchangeAccounts/[slug]/index.tsx | 57 +++++- .../createExchangeAccountDialog.tsx | 127 ++++--------- .../renderer/pages/exchangeAccounts/index.tsx | 2 +- .../renderer/pages/keys/[slug]/index.tsx | 116 +++++++++++- .../keys/[slug]/keyGeneralAttributes.tsx | 179 ------------------ .../pages/keys/[slug]/keyPermissions.tsx | 2 +- .../renderer/pages/servers/[slug]/index.tsx | 80 ++++++-- .../pages/servers/[slug]/selectedServer.tsx | 126 ------------ desktop-app/renderer/pages/servers/index.tsx | 87 +++++---- 21 files changed, 739 insertions(+), 546 deletions(-) create mode 100644 desktop-app/renderer/components/custom/selectedObject/inputs.tsx create mode 100644 desktop-app/renderer/components/custom/selectedObject/selectedObject.tsx create mode 100644 desktop-app/renderer/components/custom/selectedObject/tabs.tsx delete mode 100644 desktop-app/renderer/pages/keys/[slug]/keyGeneralAttributes.tsx delete mode 100644 desktop-app/renderer/pages/servers/[slug]/selectedServer.tsx diff --git a/desktop-app/.eslintrc.json b/desktop-app/.eslintrc.json index 3a4bcfcd..6b9d8306 100644 --- a/desktop-app/.eslintrc.json +++ b/desktop-app/.eslintrc.json @@ -8,8 +8,7 @@ "extends": [ "plugin:react/recommended", "plugin:tailwindcss/recommended", - "next/core-web-vitals", - "next/babel" + "next/core-web-vitals" ], "parserOptions": { "ecmaVersion": "latest", diff --git a/desktop-app/renderer/api/exchangeAccounts/exchangeAccount.ts b/desktop-app/renderer/api/exchangeAccounts/exchangeAccount.ts index f9b550b6..1d466ca7 100644 --- a/desktop-app/renderer/api/exchangeAccounts/exchangeAccount.ts +++ b/desktop-app/renderer/api/exchangeAccounts/exchangeAccount.ts @@ -12,13 +12,6 @@ export interface RetreivedExchangeAccount extends ExchangeAccount { uuid: string } -export async function listExchangeAccount( - searchParams: ReturnType -): Promise> { - const response = await request(searchParams, 'GET', '/api/exchange_account/') - return response as AxiosResponse -} - export async function getExchangeAccount( searchParams: ReturnType, id: string @@ -31,6 +24,13 @@ export async function getExchangeAccount( return response as AxiosResponse } +export async function listExchangeAccount( + searchParams: ReturnType +): Promise> { + const response = await request(searchParams, 'GET', '/api/exchange_account/') + return response as AxiosResponse +} + export async function createExchangeAccount( searchParams: ReturnType, data: ExchangeAccount @@ -44,6 +44,32 @@ export async function createExchangeAccount( return response as AxiosResponse } +export async function deleteExchangeAccount( + searchParams: ReturnType, + id: string +): Promise> { + const response = await request( + searchParams, + 'DELETE', + `/api/exchange_account/${id}/` + ) + return response as AxiosResponse +} + +export async function updateExchangeAccount( + searchParams: ReturnType, + id: string, + data: { name: string; description: string } +): Promise> { + const response = await request( + searchParams, + 'PATCH', + `/api/exchange_account/${id}/`, + data + ) + return response as AxiosResponse +} + export async function getPossibleExchanges( searchParams: ReturnType ): Promise> { diff --git a/desktop-app/renderer/api/request.ts b/desktop-app/renderer/api/request.ts index a52f07cb..930ef114 100644 --- a/desktop-app/renderer/api/request.ts +++ b/desktop-app/renderer/api/request.ts @@ -4,7 +4,7 @@ import { useSearchParams } from 'next/navigation' export function request( searchParams: ReturnType, - method: string, + method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH', url: string, data: Object | null = null, headers: AxiosHeaders | null = null diff --git a/desktop-app/renderer/components/custom/headerPopover.tsx b/desktop-app/renderer/components/custom/headerPopover.tsx index c962cee2..b7230034 100644 --- a/desktop-app/renderer/components/custom/headerPopover.tsx +++ b/desktop-app/renderer/components/custom/headerPopover.tsx @@ -9,8 +9,6 @@ import { DialogTitle, DialogTrigger } from '@/components/ui/dialog' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' import { Popover, PopoverContent, @@ -18,7 +16,7 @@ import { } from '@/components/ui/popover' import { ToastAction } from '@/components/ui/toast' import { useToast } from '@/components/ui/use-toast' -import { addServer, getServers, removeServer } from '@/lib/localStorage' +import { Server, addServer, getServers, removeServer } from '@/lib/localStorage' import { standardUrlPartial } from '@/lib/queryParams' import { DialogClose } from '@radix-ui/react-dialog' import { PlusIcon } from '@radix-ui/react-icons' @@ -26,22 +24,24 @@ import { Settings } from 'lucide-react' import { useSearchParams } from 'next/navigation' import { useRouter } from 'next/router' import { useState } from 'react' +import AllInputs from './selectedObject/inputs' export default function ServerPopover(): JSX.Element { const { toast } = useToast() - const defaultServerName = 'Localhost' - const defaultServerURL = 'http://localhost:8000' - const defaulAPIToken = 'xxxxxxxx.xxxxxx.xxxxxxxxx' - const [newServerName, setNewServerName] = useState(defaultServerName) - const [newServerURL, setNewServerURL] = useState(defaultServerURL) - const [newServerToken, setNewServerToken] = useState(defaulAPIToken) + const defaultServer: Omit = { + name: 'Localhost', + url: 'http://localhost:8000', + token: 'xxxxxxxx.xxxxxx.xxxxxxxxx' + } + const [servers, setServers] = useState(getServers()) const router = useRouter() const searchParams = useSearchParams() const currentURL = router.asPath const urlBase = currentURL.split('?')[0].split('/')[1] const urlId = currentURL.split('?')[0].split('/')[2] - const [openDialog, setOpenDialog] = useState(false) + + const [server, setServer] = useState(defaultServer) return ( @@ -49,7 +49,7 @@ export default function ServerPopover(): JSX.Element {
- {Object.entries(servers).map(([key, server], index) => { + {Object.values(servers).map((server, index) => { return (
) })} - + + + + + + + + Are you absolutely sure? + + This action cannot be undone. Deleteing an {objectName} will + also delete all its children. Check the documentation for more + information. + + + + Cancel + { + if (!deleteOnClick) return + await deleteOnClick() + toast({ + title: `Successfully deleted ${objectName} !`, + description: `${object[objectIdentifier]} deleted` + }) + if (noAutoRouteOnDelete) return + router + .push( + standardUrlPartial( + `/${router.pathname.split('/')[1]}`, + null, + { + exchangeAccount: '', + space: '', + fleet: '', + bot: '' + }, + searchParams + ) + ) + .catch((err) => { + console.error(err) + }) + }} + > + Detete + + + + + {childrenPosition === 'endFooter' && children} + + + ) +} diff --git a/desktop-app/renderer/components/custom/selectedObject/tabs.tsx b/desktop-app/renderer/components/custom/selectedObject/tabs.tsx new file mode 100644 index 00000000..d586415b --- /dev/null +++ b/desktop-app/renderer/components/custom/selectedObject/tabs.tsx @@ -0,0 +1,34 @@ +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' + +type Tab = { + name: string + content: JSX.Element +} + +export default function TabsLayout({ + tabs, + settingsTab +}: { + tabs?: Tab[] + settingsTab: JSX.Element +}): JSX.Element { + const defaultTab = tabs ? tabs[0].name : 'settings' + return ( + + + {tabs?.map((tab, index) => ( + + {tab.name} + + ))} + Settings + + {tabs?.map((tab, index) => ( + + {tab.content} + + ))} + {settingsTab} + + ) +} diff --git a/desktop-app/renderer/components/layout/contextHeader.tsx b/desktop-app/renderer/components/layout/contextHeader.tsx index 3bcfd7d0..4b85be03 100644 --- a/desktop-app/renderer/components/layout/contextHeader.tsx +++ b/desktop-app/renderer/components/layout/contextHeader.tsx @@ -49,7 +49,7 @@ export default function ContextHeader({ }, [theme.resolvedTheme]) return ( <> -
+
- + {/*
Full path: {router.asPath}
*/} +
) } diff --git a/desktop-app/renderer/pages/exchangeAccounts/[slug]/index.tsx b/desktop-app/renderer/pages/exchangeAccounts/[slug]/index.tsx index ed7f388e..5472fffe 100644 --- a/desktop-app/renderer/pages/exchangeAccounts/[slug]/index.tsx +++ b/desktop-app/renderer/pages/exchangeAccounts/[slug]/index.tsx @@ -1,13 +1,16 @@ import { RetreivedExchangeAccount, - getExchangeAccount + deleteExchangeAccount, + getExchangeAccount, + updateExchangeAccount } from '@/api/exchangeAccounts/exchangeAccount' +import SelectedObject from '@/components/custom/selectedObject/selectedObject' +import TabsLayout from '@/components/custom/selectedObject/tabs' import ContextHeader from '@/components/layout/contextHeader' import DefaultPageLayout from '@/components/layout/defaultPageLayout' import { useSearchParams } from 'next/navigation' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' - const defaultExchangeAccount: RetreivedExchangeAccount = { uuid: '', name: '', @@ -39,19 +42,57 @@ export default function ExchangeAccount(): JSX.Element { fetchExchangeAccount() } }, [searchParams, router.query.slug]) - return ( -
+ { + updateExchangeAccount( + searchParams, + router.query.slug as string, + { + name: exchangeAccount.name, + description: exchangeAccount.description + } + ) + }} + deleteOnClick={() => { + deleteExchangeAccount(searchParams, router.query.slug as string) + }} + inputs={[ + { label: 'Name', key: 'name', type: 'input' }, + { + label: 'Description', + key: 'description', + type: 'input' + }, + { + label: 'Exchange', + key: 'exchange', + type: 'input', + disabled: true + }, + { + label: 'Testing', + key: 'testing', + type: 'switch', + disabled: true + } + ]} + /> + } + />
) diff --git a/desktop-app/renderer/pages/exchangeAccounts/createExchangeAccountDialog.tsx b/desktop-app/renderer/pages/exchangeAccounts/createExchangeAccountDialog.tsx index 77e0cf7e..42a93cdc 100644 --- a/desktop-app/renderer/pages/exchangeAccounts/createExchangeAccountDialog.tsx +++ b/desktop-app/renderer/pages/exchangeAccounts/createExchangeAccountDialog.tsx @@ -1,3 +1,4 @@ +import AllInputs from '@/components/custom/selectedObject/inputs' import { Button } from '@/components/ui/button' import { Dialog, @@ -7,21 +8,10 @@ import { DialogTitle, DialogTrigger } from '@/components/ui/dialog' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectLabel, - SelectTrigger, - SelectValue -} from '@/components/ui/select' -import { Switch } from '@/components/ui/switch' import { DialogClose } from '@radix-ui/react-dialog' import { PlusIcon } from '@radix-ui/react-icons' import { + ExchangeAccount, RetreivedExchangeAccount, createExchangeAccount, getPossibleExchanges @@ -29,6 +19,13 @@ import { import { useSearchParams } from 'next/navigation' import { useEffect, useState } from 'react' +const defaultExchangeAccount: ExchangeAccount = { + name: 'My Exchange Account', + description: 'My Exchange Account Description', + testing: true, + exchange: 'BINANCE' +} + export default function CreateExchangeAccountDialog({ exchangeAccounts, setExchangeAccounts @@ -52,7 +49,9 @@ export default function CreateExchangeAccountDialog({ const [possibleExchanges, setPossibleExchanges] = useState([]) const [selectedExchange, setSelectedExchange] = useState('') - + const [exchangeAccount, setExchangeAccount] = useState( + defaultExchangeAccount + ) useEffect(() => { const fetchPossibleExchanges = async () => { try { @@ -72,7 +71,7 @@ export default function CreateExchangeAccountDialog({ return ( - @@ -85,73 +84,34 @@ export default function CreateExchangeAccountDialog({ provide the server name and the server URL. -
-
-
- - { - setNewExchangeAccountName(e.currentTarget.value) - }} - /> -
-
- - { - setNewExchangeAccountDescription(e.currentTarget.value) - }} - /> -
-
- - -
-
- - { - setNewExchangeAccountTesting(!newExchangeAccountTesting) - }} - /> -
-
-
+
- - -
- - ) -} diff --git a/desktop-app/renderer/pages/keys/[slug]/keyPermissions.tsx b/desktop-app/renderer/pages/keys/[slug]/keyPermissions.tsx index 153269ca..40b06bce 100644 --- a/desktop-app/renderer/pages/keys/[slug]/keyPermissions.tsx +++ b/desktop-app/renderer/pages/keys/[slug]/keyPermissions.tsx @@ -154,7 +154,7 @@ export default function KeyPermissions(): JSX.Element {
+ } + /> + ) } diff --git a/desktop-app/renderer/pages/servers/[slug]/selectedServer.tsx b/desktop-app/renderer/pages/servers/[slug]/selectedServer.tsx deleted file mode 100644 index 53fa5c3f..00000000 --- a/desktop-app/renderer/pages/servers/[slug]/selectedServer.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { Button } from '@/components/ui/button' -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle -} from '@/components/ui/card' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { useToast } from '@/components/ui/use-toast' -import { Server, removeServer, updateServer } from '@/lib/localStorage' -import { standardUrlPartial } from '@/lib/queryParams' -import { useSearchParams } from 'next/navigation' - -import { useRouter } from 'next/router' -import { Dispatch, SetStateAction } from 'react' - -export default function SelectedServer({ - server, - setServer -}: { - server: Server - setServer: Dispatch> -}): JSX.Element { - const searchParams = useSearchParams() - const router = useRouter() - const { toast } = useToast() - if (!server) { - return
Loading
- } - return ( - - - Selected Server: {server.name} - - You can view/edit your server properties here. - - - -
-
-
- - { - setServer({ ...server, name: e.currentTarget.value }) - }} - /> -
-
- - { - setServer({ ...server, url: e.currentTarget.value }) - }} - /> -
-
- - { - setServer({ ...server, token: e.currentTarget.value }) - }} - /> -
-
-
-
- - - - -
- ) -} diff --git a/desktop-app/renderer/pages/servers/index.tsx b/desktop-app/renderer/pages/servers/index.tsx index 1c25d3bd..6e10feeb 100644 --- a/desktop-app/renderer/pages/servers/index.tsx +++ b/desktop-app/renderer/pages/servers/index.tsx @@ -1,16 +1,67 @@ -import MinimalistPanelCard from '@/components/custom/panel/minimalistPanelCard' +import { connectKey } from '@/api/key/key' +import InfoPanelCard from '@/components/custom/panel/infoPanelCard' import ContextHeader from '@/components/layout/contextHeader' import DefaultPageLayout from '@/components/layout/defaultPageLayout' -import { getServers } from '@/lib/localStorage' +import { Server, getServers } from '@/lib/localStorage' import { standardUrlPartial } from '@/lib/queryParams' import { useSearchParams } from 'next/navigation' import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' export default function Servers(): JSX.Element { const router = useRouter() - const servers = getServers() const searchParams = useSearchParams() + + const [cards, setCards] = useState([]) + const [servers, setServers] = useState>({}) + + useEffect(() => { + const fetchServers = async () => { + setServers(getServers()) + } + fetchServers() + }, []) + + useEffect(() => { + Promise.all( + Object.values(servers).map(async (server, index) => { + let response + try { + response = await connectKey(server.url, server.token) + } catch (error) {} + return ( + { + router + .push( + standardUrlPartial( + '/servers/', + server.id, + { + server: server.id, + exchangeAccount: '', + space: '', + fleet: '', + bot: '' + }, + searchParams + ) + ) + .catch((err) => { + console.error(err) + }) + }} + /> + ) + }) + ).then(setCards) + }, [servers, router, searchParams]) + return ( -
- {Object.entries(servers).map(([id, server], index) => ( - { - router - .push( - standardUrlPartial( - '/servers/', - server.id, - { - server: server.id, - exchangeAccount: '', - space: '', - fleet: '', - bot: '' - }, - searchParams - ) - ) - .catch((err) => { - console.error(err) - }) - }} - /> - ))} -
+
{cards}
)