Files
nexus/frontend/src/api/projects.ts
T
AzuTear f5552218bc
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s
feat: ship agent-first mission control v0.2.57
2026-07-31 22:39:47 +02:00

142 lines
4.8 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, toValue, type MaybeRefOrGetter } from 'vue'
import type { components } from './generated/schema'
import { apiClient } from './client'
import { throwApiProblem } from './contracts'
import { queryKeys } from './queryClient'
import { reportOperationResult } from '../services/operationResults'
export type ProjectDto = components['schemas']['ProjectDto']
export type ProjectTaskDto = components['schemas']['ProjectTaskDto']
export interface CreateProjectInput {
name: string
description?: string | null
}
export interface UpdateProjectInput {
name?: string | null
description?: string | null
status?: string | null
}
export async function fetchProjects(signal?: AbortSignal): Promise<ProjectDto[]> {
const { data, error, response } = await apiClient.GET('/api/v1/projects', { signal })
if (!response.ok || error || !data) {
await throwApiProblem(response, 'Projekte konnten nicht geladen werden')
}
return data as ProjectDto[]
}
export async function fetchProject(id: string, signal?: AbortSignal): Promise<ProjectDto> {
const { data, error, response } = await apiClient.GET('/api/v1/projects/{id}', {
params: { path: { id } },
signal,
})
if (!response.ok || error || !data) {
await throwApiProblem(response, 'Projekt konnte nicht geladen werden')
}
return data as ProjectDto
}
async function createProject(input: CreateProjectInput): Promise<ProjectDto> {
const { data, error, response } = await apiClient.POST('/api/v1/projects', {
body: {
name: input.name,
description: input.description ?? null,
},
})
if (!response.ok || error || !data) {
await throwApiProblem(response, 'Projekt konnte nicht erstellt werden')
}
const project = data as ProjectDto
reportOperationResult(project.operation, 'Projekt erstellt')
return withoutProjectOperation(project)
}
export async function updateProject(id: string, input: UpdateProjectInput): Promise<ProjectDto> {
const { data, error, response } = await apiClient.PATCH('/api/v1/projects/{id}', {
params: { path: { id } },
body: input as components['schemas']['UpdateProjectRequest'],
})
if (!response.ok || error || !data) {
await throwApiProblem(response, 'Projekt konnte nicht gespeichert werden')
}
const project = data as ProjectDto
reportOperationResult(project.operation, 'Projekt aktualisiert')
return withoutProjectOperation(project)
}
function withoutProjectOperation(project: ProjectDto): ProjectDto {
const { operation: _operation, ...persistedProject } = project
return persistedProject
}
export async function fetchProjectTasks(
id: string,
signal?: AbortSignal,
): Promise<ProjectTaskDto[]> {
const { data, error, response } = await apiClient.GET('/api/v1/projects/{id}/tasks', {
params: { path: { id } },
signal,
})
if (!response.ok || error || !data) {
await throwApiProblem(response, 'Projektaufgaben konnten nicht geladen werden')
}
return data as ProjectTaskDto[]
}
export function useProjects() {
const client = useQueryClient()
const query = useQuery<ProjectDto[]>({
queryKey: queryKeys.projects(),
queryFn: ({ signal }) => fetchProjects(signal),
})
const createMutation = useMutation({
mutationFn: createProject,
onSuccess: project => {
client.setQueryData<ProjectDto[]>(queryKeys.projects(), current =>
current ? [project, ...current.filter(item => item.id !== project.id)] : [project])
client.setQueryData(queryKeys.project(project.id), project)
},
})
return {
query,
createProject: (input: CreateProjectInput) => createMutation.mutateAsync(input),
creating: createMutation.isPending,
createError: createMutation.error,
}
}
export function useProject(id: MaybeRefOrGetter<string>) {
const client = useQueryClient()
const query = useQuery<ProjectDto>({
queryKey: computed(() => queryKeys.project(toValue(id))),
queryFn: ({ signal }) => fetchProject(toValue(id), signal),
enabled: () => Boolean(toValue(id)),
})
const updateMutation = useMutation({
mutationFn: (input: UpdateProjectInput) => updateProject(toValue(id), input),
onSuccess: project => {
client.setQueryData(queryKeys.project(project.id), project)
client.setQueryData<ProjectDto[]>(queryKeys.projects(), current =>
current?.map(item => item.id === project.id ? project : item))
},
})
return {
query,
updateProject: (input: UpdateProjectInput) => updateMutation.mutateAsync(input),
updating: updateMutation.isPending,
updateError: updateMutation.error,
}
}
export function useProjectTasks(id: MaybeRefOrGetter<string>) {
return useQuery<ProjectTaskDto[]>({
queryKey: computed(() => queryKeys.projectTasks(toValue(id))),
queryFn: ({ signal }) => fetchProjectTasks(toValue(id), signal),
enabled: () => Boolean(toValue(id)),
})
}