security sections are fully functional

This commit is contained in:
2026-05-07 15:06:45 +02:00
parent 5e60b814ed
commit 53aa5cbbf5
20 changed files with 946 additions and 41 deletions
+79
View File
@@ -0,0 +1,79 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
import { api } from '../client'
import type { DeployKey, AccessToken } from '../../types/api'
// ─── Deploy keys ──────────────────────────────────────────────────────────────
const deployKeySchema = z.object({
id: z.number(),
title: z.string(),
readOnly: z.boolean(),
createdAt: z.string(),
token: z.string().optional(),
})
const deployKeysSchema = z.array(deployKeySchema)
export function useDeployKeys(owner: string, repo: string) {
return useQuery({
queryKey: ['repos', owner, repo, 'keys'],
queryFn: () => api.get<DeployKey[]>(`/api/v1/repos/${owner}/${repo}/keys`, deployKeysSchema),
enabled: Boolean(owner && repo),
})
}
export function useCreateDeployKey(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (data: { title: string; readOnly: boolean }) =>
api.post<DeployKey>(`/api/v1/repos/${owner}/${repo}/keys`, deployKeySchema, data),
onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'keys'] }),
})
}
export function useDeleteDeployKey(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (keyId: number) =>
api.delete(`/api/v1/repos/${owner}/${repo}/keys/${keyId}`, z.any()),
onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'keys'] }),
})
}
// ─── Access tokens ────────────────────────────────────────────────────────────
const accessTokenSchema = z.object({
id: z.number(),
title: z.string(),
scopes: z.string(),
expiresAt: z.string().nullable().optional(),
createdAt: z.string(),
token: z.string().optional(),
})
const accessTokensSchema = z.array(accessTokenSchema)
export function useAccessTokens(owner: string, repo: string) {
return useQuery({
queryKey: ['repos', owner, repo, 'tokens'],
queryFn: () => api.get<AccessToken[]>(`/api/v1/repos/${owner}/${repo}/tokens`, accessTokensSchema),
enabled: Boolean(owner && repo),
})
}
export function useCreateAccessToken(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (data: { title: string; scopes: string; expiresAt?: string }) =>
api.post<AccessToken>(`/api/v1/repos/${owner}/${repo}/tokens`, accessTokenSchema, data),
onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'tokens'] }),
})
}
export function useDeleteAccessToken(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (tokenId: number) =>
api.delete(`/api/v1/repos/${owner}/${repo}/tokens/${tokenId}`, z.any()),
onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'tokens'] }),
})
}