Skip to content

Commit

Permalink
feat(platform): Edit secret in project (#684)
Browse files Browse the repository at this point in the history
Co-authored-by: codiumai-pr-agent-free[bot] <138128286+codiumai-pr-agent-free[bot]@users.noreply.github.com>
Co-authored-by: Rajdip Bhattacharya <agentR47@gmail.com>
  • Loading branch information
3 people authored Feb 5, 2025
1 parent 92cecfc commit 1e34030
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ import { Button } from '@/components/ui/button'
import {
createSecretOpenAtom,
deleteSecretOpenAtom,
editSecretOpenAtom,
secretsOfProjectAtom,
selectedProjectAtom,
selectedSecretAtom
} from '@/store'
import ConfirmDeleteSecret from '@/components/dashboard/secret/confirmDeleteSecret'
import SecretCard from '@/components/dashboard/secret/secretCard'
import EditSecretSheet from '@/components/dashboard/secret/editSecretSheet'

extend(relativeTime)

function SecretPage(): React.JSX.Element {
const setIsCreateSecretOpen = useSetAtom(createSecretOpenAtom)
const isEditSecretOpen = useAtomValue(editSecretOpenAtom)
const isDeleteSecretOpen = useAtomValue(deleteSecretOpenAtom)
const selectedSecret = useAtomValue(selectedSecretAtom)
const [secrets, setSecrets] = useAtom(secretsOfProjectAtom)
Expand Down Expand Up @@ -121,7 +124,7 @@ function SecretPage(): React.JSX.Element {
{secrets.map((secret) => (
<SecretCard
isDecrypted={isDecrypted}
key={secret.id}
key={secret.secret.id}
secretData={secret}
/>
))}
Expand All @@ -132,6 +135,9 @@ function SecretPage(): React.JSX.Element {
{isDeleteSecretOpen && selectedSecret ? (
<ConfirmDeleteSecret />
) : null}

{/* Edit secret sheet */}
{isEditSecretOpen && selectedSecret ? <EditSecretSheet /> : null}
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { useCallback, useState } from 'react'
import { toast } from 'sonner'
import type { UpdateSecretRequest } from '@keyshade/schema'
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle
} from '@/components/ui/sheet'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import {
editSecretOpenAtom,
secretsOfProjectAtom,
selectedSecretAtom
} from '@/store'
import ControllerInstance from '@/lib/controller-instance'

export default function EditSecretSheet(): JSX.Element {
const [isEditSecretSheetOpen, setIsEditSecretSheetOpen] =
useAtom(editSecretOpenAtom)
const selectedSecretData = useAtomValue(selectedSecretAtom)
const setSecrets = useSetAtom(secretsOfProjectAtom)

const [requestData, setRequestData] = useState<{
name: string | undefined
note: string | undefined
}>({
name: selectedSecretData?.secret.name,
note: selectedSecretData?.secret.note || ''
})

const handleClose = useCallback(() => {
setIsEditSecretSheetOpen(false)
}, [setIsEditSecretSheetOpen])

const updateSecret = useCallback(async () => {
if (!selectedSecretData) {
toast.error('No secret selected', {
description: (
<p className="text-xs text-red-300">
No secret selected. Please select a secret.
</p>
)
})
return
}

const { secret } = selectedSecretData

const request: UpdateSecretRequest = {
secretSlug: secret.slug,
name:
!requestData.name?.trim() || requestData.name === secret.name
? undefined
: requestData.name.trim(),
note: requestData.note?.trim() || undefined,
entries: undefined
}

const { success, error, data } =
await ControllerInstance.getInstance().secretController.updateSecret(
request,
{}
)

if (success && data) {
toast.success('Secret edited successfully', {
description: (
<p className="text-xs text-emerald-300">
You successfully edited the secret
</p>
)
})

// Update the secret in the store
setSecrets((prev) => {
const newSecrets = prev.map((s) => {
if (s.secret.slug === secret.slug) {
return {
...s,
secret: {
...s.secret,
name: requestData.name || s.secret.name,
note: requestData.note || s.secret.note,
slug: data.secret.slug
}
}
}
return s
})
return newSecrets
})
}
if (error) {
toast.error('Something went wrong!', {
description: (
<p className="text-xs text-red-300">
Something went wrong while updating the secret. Check console for
more info.
</p>
)
})
// eslint-disable-next-line no-console -- we need to log the error
console.error('Error while updating secret: ', error)
}

handleClose()
}, [selectedSecretData, requestData, handleClose, setSecrets])

return (
<Sheet
onOpenChange={(open) => {
setIsEditSecretSheetOpen(open)
}}
open={isEditSecretSheetOpen}
>
<SheetContent className="border-white/15 bg-[#222425]">
<SheetHeader>
<SheetTitle className="text-white">Edit this secret</SheetTitle>
<SheetDescription className="text-white/60">
Edit the secret name or the note
</SheetDescription>
</SheetHeader>
<div className="grid gap-x-4 gap-y-6 py-8">
<div className="flex flex-col items-start gap-x-4 gap-y-3">
<Label className="text-right" htmlFor="name">
Secret Name
</Label>
<Input
className="col-span-3 h-[2.75rem]"
id="name"
onChange={(e) => {
setRequestData((prev) => ({
...prev,
name: e.target.value
}))
}}
placeholder="Enter the key of the secret"
value={requestData.name}
/>
</div>

<div className="flex flex-col items-start gap-x-4 gap-y-3">
<Label className="text-right" htmlFor="name">
Extra Note
</Label>
<Input
className="col-span-3 h-[2.75rem]"
id="name"
onChange={(e) => {
setRequestData((prev) => ({
...prev,
note: e.target.value
}))
}}
placeholder="Enter the note of the secret"
value={requestData.note}
/>
</div>
</div>
<SheetFooter className="py-3">
<SheetClose asChild>
<Button
className="font-semibold"
onClick={updateSecret}
variant="secondary"
>
Edit Secret
</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
)
}
17 changes: 15 additions & 2 deletions apps/platform/src/components/dashboard/secret/secretCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import {
TooltipProvider,
TooltipTrigger
} from '@/components/ui/tooltip'
import { deleteSecretOpenAtom, selectedSecretAtom } from '@/store'
import {
deleteSecretOpenAtom,
editSecretOpenAtom,
selectedSecretAtom
} from '@/store'

interface SecretCardProps {
secretData: Secret
Expand All @@ -41,8 +45,14 @@ export default function SecretCard({
const { secret, values } = secretData

const setSelectedSecret = useSetAtom(selectedSecretAtom)
const setIsEditSecretOpen = useSetAtom(editSecretOpenAtom)
const setIsDeleteSecretOpen = useSetAtom(deleteSecretOpenAtom)

const handleEditClick = () => {
setSelectedSecret(secretData)
setIsEditSecretOpen(true)
}

const handleDeleteClick = () => {
setSelectedSecret(secretData)
setIsDeleteSecretOpen(true)
Expand Down Expand Up @@ -123,7 +133,10 @@ export default function SecretCard({
<ContextMenuItem className="h-[33%] w-[15.938rem] border-b-[0.025rem] border-white/65 text-xs font-semibold tracking-wide">
Show Version History
</ContextMenuItem>
<ContextMenuItem className="h-[33%] w-[15.938rem] text-xs font-semibold tracking-wide">
<ContextMenuItem
className="h-[33%] w-[15.938rem] text-xs font-semibold tracking-wide"
onSelect={handleEditClick}
>
Edit
</ContextMenuItem>
<ContextMenuItem
Expand Down

0 comments on commit 1e34030

Please sign in to comment.