letsbe-hub/src/hooks/use-enterprise-clients.ts

563 lines
18 KiB
TypeScript

'use client'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import {
getEnterpriseClients,
getEnterpriseClient,
createEnterpriseClient,
updateEnterpriseClient,
deleteEnterpriseClient,
getClientServers,
getClientServer,
addClientServer,
updateClientServer,
removeClientServer,
testServerPortainerConnection,
performServerAction,
requestVerificationCode,
getErrorRules,
createErrorRule,
updateErrorRule,
deleteErrorRule,
getDetectedErrors,
acknowledgeError,
getClientStats,
getServerStats,
collectServerStats,
getServerContainers,
getContainer,
getContainerLogs,
performContainerAction,
removeContainer,
getErrorDashboard,
getContainerEvents,
acknowledgeContainerEvents,
getErrorSummary,
getNotificationSettings,
updateNotificationSettings,
} from '@/lib/api/admin'
import type { StatsRange, ContainerEventFilters, UpdateNotificationSettingsPayload } from '@/lib/api/admin'
import type {
CreateEnterpriseClientPayload,
UpdateEnterpriseClientPayload,
AddServerPayload,
UpdateServerPayload,
ServerActionPayload,
CreateErrorRulePayload,
UpdateErrorRulePayload,
ErrorFilters,
} from '@/types/api'
// ============================================================================
// Query Keys
// ============================================================================
export const enterpriseClientKeys = {
all: ['enterprise-clients'] as const,
lists: () => [...enterpriseClientKeys.all, 'list'] as const,
list: () => [...enterpriseClientKeys.lists()] as const,
details: () => [...enterpriseClientKeys.all, 'detail'] as const,
detail: (id: string) => [...enterpriseClientKeys.details(), id] as const,
servers: (clientId: string) => [...enterpriseClientKeys.detail(clientId), 'servers'] as const,
server: (clientId: string, serverId: string) => [...enterpriseClientKeys.servers(clientId), serverId] as const,
serverStats: (clientId: string, serverId: string, range: StatsRange) =>
[...enterpriseClientKeys.server(clientId, serverId), 'stats', range] as const,
clientStats: (clientId: string, range: StatsRange) =>
[...enterpriseClientKeys.detail(clientId), 'stats', range] as const,
errorRules: (clientId: string) => [...enterpriseClientKeys.detail(clientId), 'error-rules'] as const,
errors: (clientId: string, filters?: ErrorFilters) => [...enterpriseClientKeys.detail(clientId), 'errors', filters] as const,
containers: (clientId: string, serverId: string) =>
[...enterpriseClientKeys.server(clientId, serverId), 'containers'] as const,
container: (clientId: string, serverId: string, containerId: string) =>
[...enterpriseClientKeys.containers(clientId, serverId), containerId] as const,
containerLogs: (clientId: string, serverId: string, containerId: string, tail: number) =>
[...enterpriseClientKeys.container(clientId, serverId, containerId), 'logs', tail] as const,
// Error tracking keys
errorDashboard: (clientId: string) => [...enterpriseClientKeys.detail(clientId), 'error-dashboard'] as const,
containerEvents: (clientId: string, filters?: ContainerEventFilters) =>
[...enterpriseClientKeys.detail(clientId), 'container-events', filters] as const,
errorSummary: () => [...enterpriseClientKeys.all, 'error-summary'] as const,
// Notification settings key
notifications: (clientId: string) => [...enterpriseClientKeys.detail(clientId), 'notifications'] as const,
}
// ============================================================================
// Client Hooks
// ============================================================================
export function useEnterpriseClients() {
return useQuery({
queryKey: enterpriseClientKeys.list(),
queryFn: getEnterpriseClients,
})
}
export function useEnterpriseClient(id: string) {
return useQuery({
queryKey: enterpriseClientKeys.detail(id),
queryFn: () => getEnterpriseClient(id),
enabled: !!id,
})
}
export function useCreateEnterpriseClient() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: CreateEnterpriseClientPayload) => createEnterpriseClient(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.lists() })
},
})
}
export function useUpdateEnterpriseClient() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateEnterpriseClientPayload }) =>
updateEnterpriseClient(id, data),
onSuccess: (_, { id }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.detail(id) })
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.lists() })
},
})
}
export function useDeleteEnterpriseClient() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (id: string) => deleteEnterpriseClient(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.lists() })
},
})
}
// ============================================================================
// Server Hooks
// ============================================================================
export function useClientServers(clientId: string) {
return useQuery({
queryKey: enterpriseClientKeys.servers(clientId),
queryFn: () => getClientServers(clientId),
enabled: !!clientId,
})
}
export function useClientServer(clientId: string, serverId: string) {
return useQuery({
queryKey: enterpriseClientKeys.server(clientId, serverId),
queryFn: () => getClientServer(clientId, serverId),
enabled: !!clientId && !!serverId,
})
}
export function useAddServerToClient() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, data }: { clientId: string; data: AddServerPayload }) =>
addClientServer(clientId, data),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.servers(clientId) })
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.detail(clientId) })
},
})
}
export function useUpdateClientServer() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
serverId,
data,
}: {
clientId: string
serverId: string
data: UpdateServerPayload
}) => updateClientServer(clientId, serverId, data),
onSuccess: (_, { clientId, serverId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.server(clientId, serverId) })
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.servers(clientId) })
},
})
}
export function useRemoveServerFromClient() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, serverId }: { clientId: string; serverId: string }) =>
removeClientServer(clientId, serverId),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.servers(clientId) })
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.detail(clientId) })
},
})
}
export function useTestPortainerConnection() {
return useMutation({
mutationFn: ({
clientId,
serverId,
credentials,
}: {
clientId: string
serverId: string
credentials: { portainerUrl: string; portainerUsername: string; portainerPassword: string }
}) => testServerPortainerConnection(clientId, serverId, credentials),
})
}
// ============================================================================
// Server Action Hooks
// ============================================================================
export function useServerAction() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
serverId,
action,
}: {
clientId: string
serverId: string
action: ServerActionPayload
}) => performServerAction(clientId, serverId, action),
onSuccess: (_, { clientId, serverId }) => {
// Refresh server status after action
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.server(clientId, serverId) })
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.servers(clientId) })
},
})
}
export function useRequestVerificationCode() {
return useMutation({
mutationFn: ({
clientId,
serverId,
action,
}: {
clientId: string
serverId: string
action: 'WIPE' | 'REINSTALL'
}) => requestVerificationCode(clientId, serverId, action),
})
}
// ============================================================================
// Error Rule Hooks
// ============================================================================
export function useErrorRules(clientId: string) {
return useQuery({
queryKey: enterpriseClientKeys.errorRules(clientId),
queryFn: () => getErrorRules(clientId),
enabled: !!clientId,
})
}
export function useCreateErrorRule() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, data }: { clientId: string; data: CreateErrorRulePayload }) =>
createErrorRule(clientId, data),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.errorRules(clientId) })
},
})
}
export function useUpdateErrorRule() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
ruleId,
data,
}: {
clientId: string
ruleId: string
data: UpdateErrorRulePayload
}) => updateErrorRule(clientId, ruleId, data),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.errorRules(clientId) })
},
})
}
export function useDeleteErrorRule() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, ruleId }: { clientId: string; ruleId: string }) =>
deleteErrorRule(clientId, ruleId),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.errorRules(clientId) })
},
})
}
// ============================================================================
// Detected Error Hooks
// ============================================================================
export function useDetectedErrors(clientId: string, filters?: ErrorFilters) {
return useQuery({
queryKey: enterpriseClientKeys.errors(clientId, filters),
queryFn: () => getDetectedErrors(clientId, filters),
enabled: !!clientId,
})
}
export function useAcknowledgeError() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, errorId }: { clientId: string; errorId: string }) =>
acknowledgeError(clientId, errorId),
onSuccess: (_, { clientId }) => {
// Invalidate all error queries for this client
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.detail(clientId),
predicate: (query) => {
const key = query.queryKey
return Array.isArray(key) && key.includes('errors')
},
})
// Also refresh the client detail to update error count
queryClient.invalidateQueries({ queryKey: enterpriseClientKeys.detail(clientId) })
},
})
}
// ============================================================================
// Stats Hooks
// ============================================================================
export function useClientStatsOverview(clientId: string, range: StatsRange = '24h') {
return useQuery({
queryKey: enterpriseClientKeys.clientStats(clientId, range),
queryFn: () => getClientStats(clientId, range),
enabled: !!clientId,
refetchInterval: 60000, // Refresh every minute
})
}
export function useServerStatsHistory(
clientId: string,
serverId: string,
range: StatsRange = '24h'
) {
return useQuery({
queryKey: enterpriseClientKeys.serverStats(clientId, serverId, range),
queryFn: () => getServerStats(clientId, serverId, range),
enabled: !!clientId && !!serverId,
refetchInterval: 30000, // Refresh every 30 seconds
})
}
export function useCollectServerStats() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, serverId }: { clientId: string; serverId: string }) =>
collectServerStats(clientId, serverId),
onSuccess: (_, { clientId, serverId }) => {
// Invalidate all stats queries for this server
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.server(clientId, serverId),
})
},
})
}
// ============================================================================
// Container Hooks
// ============================================================================
export function useServerContainers(clientId: string, serverId: string, all: boolean = true) {
return useQuery({
queryKey: enterpriseClientKeys.containers(clientId, serverId),
queryFn: () => getServerContainers(clientId, serverId, all),
enabled: !!clientId && !!serverId,
refetchInterval: 10000, // Refresh every 10 seconds
})
}
export function useContainer(clientId: string, serverId: string, containerId: string) {
return useQuery({
queryKey: enterpriseClientKeys.container(clientId, serverId, containerId),
queryFn: () => getContainer(clientId, serverId, containerId),
enabled: !!clientId && !!serverId && !!containerId,
})
}
export function useContainerLogs(
clientId: string,
serverId: string,
containerId: string,
tail: number = 500
) {
return useQuery({
queryKey: enterpriseClientKeys.containerLogs(clientId, serverId, containerId, tail),
queryFn: () => getContainerLogs(clientId, serverId, containerId, tail),
enabled: !!clientId && !!serverId && !!containerId,
})
}
export function useContainerAction() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
serverId,
containerId,
action,
}: {
clientId: string
serverId: string
containerId: string
action: 'start' | 'stop' | 'restart'
}) => performContainerAction(clientId, serverId, containerId, action),
onSuccess: (_, { clientId, serverId }) => {
// Invalidate container list to refresh status
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.containers(clientId, serverId),
})
},
})
}
export function useRemoveContainer() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
serverId,
containerId,
force,
}: {
clientId: string
serverId: string
containerId: string
force?: boolean
}) => removeContainer(clientId, serverId, containerId, force),
onSuccess: (_, { clientId, serverId }) => {
// Invalidate container list
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.containers(clientId, serverId),
})
},
})
}
// ============================================================================
// Error Dashboard Hooks
// ============================================================================
export function useErrorDashboard(clientId: string) {
return useQuery({
queryKey: enterpriseClientKeys.errorDashboard(clientId),
queryFn: () => getErrorDashboard(clientId),
enabled: !!clientId,
refetchInterval: 60000, // Refresh every minute
})
}
// ============================================================================
// Container Events Hooks
// ============================================================================
export function useContainerEvents(clientId: string, filters?: ContainerEventFilters) {
return useQuery({
queryKey: enterpriseClientKeys.containerEvents(clientId, filters),
queryFn: () => getContainerEvents(clientId, filters),
enabled: !!clientId,
refetchInterval: 30000, // Refresh every 30 seconds
})
}
export function useAcknowledgeContainerEvents() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({ clientId, eventIds }: { clientId: string; eventIds: string[] }) =>
acknowledgeContainerEvents(clientId, eventIds),
onSuccess: (_, { clientId }) => {
// Invalidate container events queries for this client
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.detail(clientId),
predicate: (query) => {
const key = query.queryKey
return Array.isArray(key) && key.includes('container-events')
},
})
// Also refresh the error dashboard
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.errorDashboard(clientId),
})
// Also refresh the global error summary
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.errorSummary(),
})
},
})
}
// ============================================================================
// All Clients Error Summary Hooks
// ============================================================================
export function useAllClientsErrorSummary() {
return useQuery({
queryKey: enterpriseClientKeys.errorSummary(),
queryFn: getErrorSummary,
refetchInterval: 60000, // Refresh every minute
})
}
// ============================================================================
// Notification Settings Hooks
// ============================================================================
export function useNotificationSettings(clientId: string) {
return useQuery({
queryKey: enterpriseClientKeys.notifications(clientId),
queryFn: () => getNotificationSettings(clientId),
enabled: !!clientId,
})
}
export function useUpdateNotificationSettings() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: ({
clientId,
data,
}: {
clientId: string
data: UpdateNotificationSettingsPayload
}) => updateNotificationSettings(clientId, data),
onSuccess: (_, { clientId }) => {
queryClient.invalidateQueries({
queryKey: enterpriseClientKeys.notifications(clientId),
})
},
})
}