feat(cli-endpoints): add create, update, and delete functionality for CLI endpoints

- Implemented `useCreateCliEndpoint`, `useUpdateCliEndpoint`, and `useDeleteCliEndpoint` hooks for managing CLI endpoints.
- Added `CliEndpointFormDialog` component for creating and editing CLI endpoints with validation.
- Updated translations for CLI hooks and manager to include new fields and messages.
- Refactored `CcwToolsMcpCard` to simplify enabling and disabling tools.
- Adjusted `SkillCreateDialog` to display paths based on CLI type.
This commit is contained in:
catlog22
2026-02-07 21:56:08 +08:00
parent 678be8d41f
commit 6073627ff2
12 changed files with 1252 additions and 422 deletions

View File

@@ -170,6 +170,9 @@ export type {
export {
useCliEndpoints,
useToggleCliEndpoint,
useCreateCliEndpoint,
useUpdateCliEndpoint,
useDeleteCliEndpoint,
cliEndpointsKeys,
useCliInstallations,
useInstallCliTool,
@@ -298,4 +301,4 @@ export type {
UseRebuildIndexReturn,
UseUpdateIndexReturn,
UseCancelIndexingReturn,
} from './useCodexLens';
} from './useCodexLens';

View File

@@ -10,6 +10,9 @@ import { sanitizeErrorMessage } from '../utils/errorSanitizer';
import {
fetchCliEndpoints,
toggleCliEndpoint,
createCliEndpoint,
updateCliEndpoint,
deleteCliEndpoint,
type CliEndpoint,
type CliEndpointsResponse,
} from '../lib/api';
@@ -121,6 +124,101 @@ export function useToggleCliEndpoint() {
};
}
export function useCreateCliEndpoint() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (endpoint: Omit<CliEndpoint, 'id'>) => createCliEndpoint(endpoint),
onSuccess: (created) => {
queryClient.setQueryData<CliEndpointsResponse>(cliEndpointsKeys.lists(), (old) => {
if (!old) return { endpoints: [created] };
return { endpoints: [created, ...old.endpoints] };
});
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: cliEndpointsKeys.all });
},
});
return {
createEndpoint: mutation.mutateAsync,
isCreating: mutation.isPending,
error: mutation.error,
};
}
export function useUpdateCliEndpoint() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: ({ endpointId, updates }: { endpointId: string; updates: Partial<CliEndpoint> }) =>
updateCliEndpoint(endpointId, updates),
onMutate: async ({ endpointId, updates }) => {
await queryClient.cancelQueries({ queryKey: cliEndpointsKeys.all });
const previous = queryClient.getQueryData<CliEndpointsResponse>(cliEndpointsKeys.lists());
queryClient.setQueryData<CliEndpointsResponse>(cliEndpointsKeys.lists(), (old) => {
if (!old) return old;
return {
endpoints: old.endpoints.map((e) => (e.id === endpointId ? { ...e, ...updates } : e)),
};
});
return { previous };
},
onError: (_err, _vars, context) => {
if (context?.previous) {
queryClient.setQueryData(cliEndpointsKeys.lists(), context.previous);
}
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: cliEndpointsKeys.all });
},
});
return {
updateEndpoint: (endpointId: string, updates: Partial<CliEndpoint>) =>
mutation.mutateAsync({ endpointId, updates }),
isUpdating: mutation.isPending,
error: mutation.error,
};
}
export function useDeleteCliEndpoint() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (endpointId: string) => deleteCliEndpoint(endpointId),
onMutate: async (endpointId) => {
await queryClient.cancelQueries({ queryKey: cliEndpointsKeys.all });
const previous = queryClient.getQueryData<CliEndpointsResponse>(cliEndpointsKeys.lists());
queryClient.setQueryData<CliEndpointsResponse>(cliEndpointsKeys.lists(), (old) => {
if (!old) return old;
return {
endpoints: old.endpoints.filter((e) => e.id !== endpointId),
};
});
return { previous };
},
onError: (_err, _endpointId, context) => {
if (context?.previous) {
queryClient.setQueryData(cliEndpointsKeys.lists(), context.previous);
}
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: cliEndpointsKeys.all });
},
});
return {
deleteEndpoint: mutation.mutateAsync,
isDeleting: mutation.isPending,
error: mutation.error,
};
}
// ========================================
// useCliInstallations Hook
// ========================================