Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/server #99

Merged
merged 4 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions desktop-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
"dependencies": {
"@hookform/resolvers": "^3.3.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.6",
Expand All @@ -25,6 +27,7 @@
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.4",
"@radix-ui/react-tooltip": "^1.0.6",
Expand Down
4 changes: 2 additions & 2 deletions desktop-app/renderer/api/exchangeAccounts/exchangeAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ export interface ExchangeAccount {
testing: boolean
}

export async function list(
export async function listExchangeAccount(
searchParams: ReturnType<typeof useSearchParams>
): Promise<AxiosResponse<ExchangeAccount[]>> {
const response = await request(searchParams, 'GET', '/api/exchange_account/')
return response as AxiosResponse<ExchangeAccount[]>
}

export async function get(
export async function getExchangeAccount(
searchParams: ReturnType<typeof useSearchParams>,
id: string
): Promise<AxiosResponse<ExchangeAccount>> {
Expand Down
43 changes: 43 additions & 0 deletions desktop-app/renderer/api/key/key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { request } from 'api/request'
import { AxiosResponse } from 'axios'
import { useSearchParams } from 'next/navigation'

export interface Key {
name: string
prefix: string
permissions: string[]
is_master_key: boolean
revoked: boolean
description: string
}

export async function getKey(
searchParams: ReturnType<typeof useSearchParams>,
id: string
): Promise<AxiosResponse<Key>> {
const response = await request(searchParams, 'GET', `/api/key/${id}/`)
return response as AxiosResponse<Key>
}
export async function listKey(
searchParams: ReturnType<typeof useSearchParams>,
space: string | null = null
): Promise<AxiosResponse<Key[]>> {
const response = await request(
searchParams,
'GET',
space ? `/api/key/?space=${space}` : '/api/key/'
)
return response as AxiosResponse<Key[]>
}

export async function createKey(
searchParams: ReturnType<typeof useSearchParams>,
name: string,
description: string
): Promise<AxiosResponse<{ key: string }>> {
const response = await request(searchParams, 'POST', '/api/key/', {
name,
description
})
return response as AxiosResponse<{ key: string }>
}
15 changes: 11 additions & 4 deletions desktop-app/renderer/api/request.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { getServer } from '@/lib/localStorage'
import axios from 'axios'
import axios, { AxiosHeaders } from 'axios'
import { useSearchParams } from 'next/navigation'

export function request(
searchParams: ReturnType<typeof useSearchParams>,
method: string,
url: string,
...args: any[]
data: Object | null = null,
headers: AxiosHeaders | null = null
) {
const serverID = searchParams.get('server')
if (!serverID) {
throw new Error('No server selected')
}
const serverUrl = getServer(serverID).url
const server = getServer(serverID)
const serverUrl = server.url
const token = server.token
return axios({
method: method,
url: url,
baseURL: serverUrl,
...args
headers: {
Authorization: 'Api-Key ' + token,
...headers
},
data: data || {}
})
}
27 changes: 27 additions & 0 deletions desktop-app/renderer/api/spaces/spaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { request } from 'api/request'
import { AxiosResponse } from 'axios'
import { useSearchParams } from 'next/navigation'

export interface NapseSpace {
name: string
uuid: string
value: number
fleet_count: number
exchange_account: string
delta?: number
}

export async function listSpace(
searchParams: ReturnType<typeof useSearchParams>
): Promise<AxiosResponse<NapseSpace[]>> {
const response = await request(searchParams, 'GET', '/api/space/')
return response as AxiosResponse<NapseSpace[]>
}

export async function getSpace(
searchParams: ReturnType<typeof useSearchParams>,
id: string
): Promise<AxiosResponse<NapseSpace>> {
const response = await request(searchParams, 'GET', `/api/space/${id}/`)
return response as AxiosResponse<NapseSpace>
}
52 changes: 52 additions & 0 deletions desktop-app/renderer/components/custom/copyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { CheckIcon, CopyIcon } from '@radix-ui/react-icons'
import * as React from 'react'

import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'

interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
value: string
src?: string
}

export async function copyToClipboardWithMeta(value: string, event?: Event) {
navigator.clipboard.writeText(value)
}

export default function CopyButton({
value,
className,
src,
...props
}: CopyButtonProps) {
const [hasCopied, setHasCopied] = React.useState(false)

React.useEffect(() => {
setTimeout(() => {
setHasCopied(false)
}, 2000)
}, [hasCopied])

return (
<Button
size="icon"
variant="ghost"
className={cn(
'bg-foreground relative z-10 h-6 w-6 text-zinc-50',
className
)}
onClick={() => {
copyToClipboardWithMeta(value)
setHasCopied(true)
}}
{...props}
>
<span className="sr-only">Copy</span>
{hasCopied ? (
<CheckIcon className="h-3 w-3" />
) : (
<CopyIcon className="h-3 w-3" />
)}
</Button>
)
}
117 changes: 89 additions & 28 deletions desktop-app/renderer/components/custom/headerPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { ToastAction } from '@/components/ui/toast'
import { useToast } from '@/components/ui/use-toast'
import { addServer, getServers, removeServer } from '@/lib/localStorage'
import { standardUrlPartial } from '@/lib/queryParams'
import { PlusCircledIcon } from '@radix-ui/react-icons'
import { PlusIcon } from '@radix-ui/react-icons'
import { Settings } from 'lucide-react'
import { useSearchParams } from 'next/navigation'
import { useRouter } from 'next/router'
import { useState } from 'react'
Expand All @@ -28,11 +29,16 @@ 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 [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]
return (
<>
<Popover>
Expand All @@ -43,48 +49,86 @@ export default function ServerPopover(): JSX.Element {
<div className="flex flex-col items-stretch space-y-3">
{Object.entries(servers).map(([key, server], index) => {
return (
<div key={index + 1} className="flex flex-row space-x-5">
<div key={index + 1} className="flex flex-row space-x-1">
<Button
onClick={() => {
router.push(
standardUrlPartial(
'/servers/',
server.id,
{
server: server.id,
exchangeAccount: '',
space: '',
fleet: '',
bot: ''
},
searchParams
)
)
if (currentURL === '/') {
router
.push(
standardUrlPartial(
'/exchangeAccounts/',
null,
{
server: server.id,
exchangeAccount: '',
space: '',
fleet: '',
bot: ''
},
searchParams
)
)
.catch((err) => {
console.error(err)
})
} else {
router
.push(
standardUrlPartial(
`/${urlBase}/`,
urlId,
{
server: server.id,
exchangeAccount: '',
space: '',
fleet: '',
bot: ''
},
searchParams
)
)
.catch((err) => {
console.error(err)
})
}
}}
variant="ghost"
className="w-full"
className="w-full space-x-5"
>
{server.name}
</Button>
<Button
onClick={() => {
removeServer(key)
setServers(getServers())
router
.push(
standardUrlPartial(
'/servers/',
server.id,
{
server: server.id,
exchangeAccount: '',
space: '',
fleet: '',
bot: ''
},
searchParams
)
)
.catch((err) => {
console.error(err)
})
}}
variant="default"
variant="outline"
>
<div className="flex flex-row ">
{/* <MinusCircledIcon className="mr-2 h-5 w-5" /> */}
<div>Remove</div>
</div>
<Settings className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all " />
</Button>
</div>
)
})}
<Dialog key={0}>
<DialogTrigger asChild>
<Button variant="outline" className="">
<PlusCircledIcon className="mr-2 h-5 w-5" />
<PlusIcon className="mr-2 h-5 w-5" />
Add new
</Button>
</DialogTrigger>
Expand All @@ -111,24 +155,41 @@ export default function ServerPopover(): JSX.Element {
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
<Label htmlFor="url" className="text-right">
URL
</Label>
<Input
id="username"
id="url"
defaultValue={defaultServerURL}
className="col-span-3"
onChange={(e) => {
setNewServerURL(e.currentTarget.value)
}}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="token" className="text-right">
API Token
</Label>
<Input
id="token"
defaultValue={defaulAPIToken}
className="col-span-3"
onChange={(e) => {
setNewServerToken(e.currentTarget.value)
}}
/>
</div>
</div>
<DialogFooter>
<Button
type="submit"
onClick={() => {
const id = addServer(newServerName, newServerURL)
const id = addServer(
newServerName,
newServerURL,
newServerToken
)
setServers(getServers())
setNewServerName(defaultServerName)
setNewServerURL(defaultServerURL)
Expand Down
21 changes: 21 additions & 0 deletions desktop-app/renderer/components/custom/settingsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Button } from '@/components/ui/button'
import { Settings } from 'lucide-react'
import { useRouter } from 'next/router'

export function SettingsButton(): JSX.Element {
const router = useRouter()

return (
<Button
variant="outline"
size="icon"
onClick={() => {
router.push('/settings').catch((err) => {
console.error(err)
})
}}
>
<Settings className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all " />
</Button>
)
}
Loading