Update according to requirements

This commit is contained in:
Joshen Lim committed 2023-06-22 22:07:18 +08:00
1 parent 55654fc7c3
commit e704ab5aaa
4 files changed
+159 -32

No files matched your search

@@ -0,0 +1,71 @@
import Table from 'components/to-be-cleaned/Table'
import { OAuthApp } from 'data/oauth/oauth-apps-query'
import dayjs from 'dayjs'
import { copyToClipboard } from 'lib/helpers'
import { useState } from 'react'
import {
Button,
Dropdown,
IconCheck,
IconClipboard,
IconEdit,
IconMoreVertical,
IconTrash,
} from 'ui'
export interface OAuthAppRowProps {
app: OAuthApp
onSelectEdit: () => void
onSelectDelete: () => void
}
const OAuthAppRow = ({ app, onSelectEdit, onSelectDelete }: OAuthAppRowProps) => {
const [isCopied, setIsCopied] = useState(false)
return (
<Table.tr>
<Table.td>{app.name}</Table.td>
<Table.td>
<span className="font-mono truncate">{app.client_id}</span>
<Button
type="default"
icon={
isCopied ? <IconCheck className="text-brand-900" strokeWidth={3} /> : <IconClipboard />
}
className="ml-2 px-1"
onClick={() => {
copyToClipboard(app.client_id)
setIsCopied(true)
setTimeout(() => {
setIsCopied(false)
}, 3000)
}}
/>
</Table.td>
<Table.td>
<span className="font-mono">{app.client_secret_alias}...</span>
</Table.td>
<Table.td>{dayjs(app.created_at).format('DD/MM/YYYY, HH:mm:ss')}</Table.td>
<Table.td align="right">
<Dropdown
size="tiny"
align="end"
side="bottom"
overlay={[
<Dropdown.Item key="edit" icon={<IconEdit />} onClick={() => onSelectEdit()}>
Edit app
</Dropdown.Item>,
<Dropdown.Separator key="separator" />,
<Dropdown.Item key="delete" icon={<IconTrash />} onClick={() => onSelectDelete()}>
Delete app
</Dropdown.Item>,
]}
>
<Button type="default" icon={<IconMoreVertical />} className="px-1" />
</Dropdown>
</Table.td>
</Table.tr>
)
}
export default OAuthAppRow
@@ -2,16 +2,20 @@ import { useParams } from 'common'
import Table from 'components/to-be-cleaned/Table'
import { OAuthApp, useOAuthAppsQuery } from 'data/oauth/oauth-apps-query'
import { useState } from 'react'
import { Button, IconEdit, IconTrash } from 'ui'
import { Alert, Button, IconClipboard, IconEdit, IconTrash, IconX, Input } from 'ui'
import PublishAppModal from './PublishAppModal'
import DeleteAppModal from './DeleteAppModal'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import AlertError from 'components/ui/AlertError'
import { copyToClipboard } from 'lib/helpers'
import OAuthAppRow from './OAuthAppRow'
import { OAuthAppCreateResponse } from 'data/oauth/oauth-app-create-mutation'
// [Joshen] Just FYI need to relook at the copy writing at the end
const OAuthApps = () => {
const { slug } = useParams()
const [createdApp, setCreatedApp] = useState<OAuthAppCreateResponse>()
const [showPublishModal, setShowPublishModal] = useState(false)
const [selectedAppToUpdate, setSelectedAppToUpdate] = useState<OAuthApp>()
const [selectedAppToDelete, setSelectedAppToDelete] = useState<OAuthApp>()
@@ -58,6 +62,47 @@ const OAuthApps = () => {
{isError && <AlertError subject="Unable to retrieve published OAuth apps" />}
{createdApp !== undefined && (
<Alert withIcon variant="success" title="Successfully published a new application!">
<div className="absolute top-4 right-4">
<Button
type="text"
icon={<IconX size={18} />}
className="px-1"
onClick={() => setCreatedApp(undefined)}
/>
</div>
<div className="w-full space-y-4">
<p className="text-sm">
Ensure that you store the client secret securely - you will not be able to see
it again.
</p>
<div className="space-y-4">
<Input
copy
readOnly
size="small"
// layout="horizontal"
label="Client ID"
className="max-w-xl input-mono"
value={createdApp.client_id}
onChange={() => {}}
/>
<Input
copy
readOnly
size="small"
// layout="horizontal"
label="Client secret"
className="max-w-xl input-mono"
value={createdApp.client_secret}
onChange={() => {}}
/>
</div>
</div>
</Alert>
)}
{isSuccess && (
<>
{(publishedApps?.length ?? 0) === 0 ? (
@@ -71,36 +116,20 @@ const OAuthApps = () => {
<Table.th key="name">Name</Table.th>,
<Table.th key="client-id">Client ID</Table.th>,
<Table.th key="client-secret">Client Secret</Table.th>,
<Table.th key="client-secret">Created at</Table.th>,
<Table.th key="delete-action"></Table.th>,
]}
body={
sortedPublishedApps?.map((app) => (
<Table.tr key={app.id}>
<Table.td>{app.name}</Table.td>
<Table.td>{app.client_id}</Table.td>
<Table.td>{app.client_secret_alias}</Table.td>
<Table.td align="right">
<div className="space-x-2">
<Button
type="default"
title="Delete app"
icon={<IconEdit />}
className="px-1"
onClick={() => {
setShowPublishModal(true)
setSelectedAppToUpdate(app)
}}
/>
<Button
type="default"
title="Delete app"
icon={<IconTrash />}
className="px-1"
onClick={() => setSelectedAppToDelete(app)}
/>
</div>
</Table.td>
</Table.tr>
<OAuthAppRow
key={app.id}
app={app}
onSelectEdit={() => {
setShowPublishModal(true)
setSelectedAppToUpdate(app)
}}
onSelectDelete={() => setSelectedAppToDelete(app)}
/>
)) ?? []
}
/>
@@ -151,6 +180,7 @@ const OAuthApps = () => {
setSelectedAppToUpdate(undefined)
setShowPublishModal(false)
}}
onCreateSuccess={setCreatedApp}
/>
<DeleteAppModal
selectedApp={selectedAppToDelete}
@@ -2,7 +2,10 @@ import clsx from 'clsx'
import { ChangeEvent, useEffect, useRef, useState } from 'react'
import { useParams } from 'common'
import { useOAuthAppCreateMutation } from 'data/oauth/oauth-app-create-mutation'
import {
OAuthAppCreateResponse,
useOAuthAppCreateMutation,
} from 'data/oauth/oauth-app-create-mutation'
import { useOAuthAppUpdateMutation } from 'data/oauth/oauth-app-update-mutation'
import { OAuthApp } from 'data/oauth/oauth-apps-query'
import { useStore } from 'hooks'
@@ -14,9 +17,15 @@ export interface PublishAppModalProps {
visible: boolean
selectedApp?: OAuthApp
onClose: () => void
onCreateSuccess: (app: OAuthAppCreateResponse) => void
}
const PublishAppModal = ({ visible, selectedApp, onClose }: PublishAppModalProps) => {
const PublishAppModal = ({
visible,
selectedApp,
onClose,
onCreateSuccess,
}: PublishAppModalProps) => {
const { ui } = useStore()
const { slug } = useParams()
const uploadButtonRef = useRef<any>()
@@ -96,12 +105,19 @@ const PublishAppModal = ({ visible, selectedApp, onClose }: PublishAppModalProps
if (selectedApp === undefined) {
// Create application
try {
await createOAuthApp({ slug, name, website, redirect_uris, icon: uploadedIconUrl })
const res = await createOAuthApp({
slug,
name,
website,
redirect_uris,
icon: uploadedIconUrl,
})
ui.setNotification({
category: 'success',
message: `Successfully created OAuth app "${name}"!`,
})
onClose()
onCreateSuccess(res)
} catch (error: any) {
setSubmitting(false)
ui.setNotification({
@@ -163,7 +179,11 @@ const PublishAppModal = ({ visible, selectedApp, onClose }: PublishAppModalProps
<Modal.Content>
<div className="py-4 flex items-start justify-between gap-10">
<div className="space-y-4 w-full">
<Input id="name" label="Application name"></Input>
<Input
id="name"
label="Application name"
descriptionText={selectedApp?.id && `ID: ${selectedApp.id}`}
></Input>
<Input
id="website"
label="Website URL"
@@ -11,6 +11,12 @@ export type OAuthAppCreateVariables = {
redirect_uris: string[]
}
export type OAuthAppCreateResponse = {
id: string
client_id: string
client_secret: string
}
export async function createOAuthApp({
slug,
name,
@@ -29,7 +35,7 @@ export async function createOAuthApp({
redirect_uris,
})
if (response.error) throw response.error
return response
return response as OAuthAppCreateResponse
}
type OAuthAppCreateData = Awaited<ReturnType<typeof createOAuthApp>>