mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-14 08:18:04 +00:00
fix: harden profile lifecycle validation and dashboard UX flows
This commit is contained in:
1 parent
02c81743a0
commit
d6fc5dd64c
8 files changed
+184
-36
No files matched your search
@@ -70,9 +70,6 @@ export function useDeleteProfile() {
|
||||
export function useDiscoverProfileOrphans() {
|
||||
return useMutation({
|
||||
mutationFn: () => api.profiles.discoverOrphans(),
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,9 +82,6 @@ export function useRegisterProfileOrphans() {
|
||||
queryClient.invalidateQueries({ queryKey: ['profiles'] });
|
||||
toast.success('Orphan profiles registration complete');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,9 +95,6 @@ export function useCopyProfile() {
|
||||
queryClient.invalidateQueries({ queryKey: ['profiles'] });
|
||||
toast.success('Profile copied successfully');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -111,9 +102,6 @@ export function useExportProfile() {
|
||||
return useMutation({
|
||||
mutationFn: ({ name, includeSecrets }: { name: string; includeSecrets?: boolean }) =>
|
||||
api.profiles.export(name, includeSecrets ?? false),
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,8 +114,5 @@ export function useImportProfile() {
|
||||
queryClient.invalidateQueries({ queryKey: ['profiles'] });
|
||||
toast.success('Profile imported successfully');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -164,6 +164,13 @@ export interface CopyProfileRequest {
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export interface CopyProfileResponse {
|
||||
success: boolean;
|
||||
name?: string;
|
||||
settingsPath?: string;
|
||||
warnings?: string[];
|
||||
}
|
||||
|
||||
export interface ApiProfileExportBundle {
|
||||
schemaVersion: 1;
|
||||
exportedAt: string;
|
||||
@@ -711,7 +718,7 @@ export const api = {
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
copy: (name: string, data: CopyProfileRequest) =>
|
||||
request(`/profiles/${name}/copy`, {
|
||||
request<CopyProfileResponse>(`/profiles/${name}/copy`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
+19
-5
@@ -82,6 +82,8 @@ export function ApiPage() {
|
||||
onSuccess: () => {
|
||||
if (selectedProfile === name) {
|
||||
setSelectedProfile(null);
|
||||
setEditorHasChanges(false);
|
||||
setPendingSwitch(null);
|
||||
}
|
||||
setDeleteConfirm(null);
|
||||
},
|
||||
@@ -135,18 +137,26 @@ export function ApiPage() {
|
||||
|
||||
const handleCopySelectedProfile = async () => {
|
||||
if (!selectedProfileData) return;
|
||||
const destination = window.prompt(
|
||||
const destinationInput = window.prompt(
|
||||
`Copy profile "${selectedProfileData.name}" to new profile name:`,
|
||||
`${selectedProfileData.name}-copy`
|
||||
);
|
||||
if (!destination) return;
|
||||
if (!destinationInput) return;
|
||||
const destination = destinationInput.trim();
|
||||
if (!destination) {
|
||||
toast.error('Destination profile name cannot be empty');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await copyProfileMutation.mutateAsync({
|
||||
const result = await copyProfileMutation.mutateAsync({
|
||||
name: selectedProfileData.name,
|
||||
data: { destination: destination.trim() },
|
||||
data: { destination },
|
||||
});
|
||||
switchToProfile(destination.trim());
|
||||
switchToProfile(destination);
|
||||
if (result.warnings && result.warnings.length > 0) {
|
||||
toast.info(result.warnings.join('\n'));
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error((error as Error).message);
|
||||
}
|
||||
@@ -210,6 +220,8 @@ export function ApiPage() {
|
||||
variant="outline"
|
||||
onClick={() => void handleDiscoverOrphans()}
|
||||
disabled={discoverOrphansMutation.isPending || registerOrphansMutation.isPending}
|
||||
aria-label="Discover orphan profiles"
|
||||
title="Discover orphan profiles"
|
||||
>
|
||||
<RefreshCw
|
||||
className={`w-4 h-4 ${discoverOrphansMutation.isPending ? 'animate-spin' : ''}`}
|
||||
@@ -220,6 +232,8 @@ export function ApiPage() {
|
||||
variant="outline"
|
||||
onClick={handleImportClick}
|
||||
disabled={importProfileMutation.isPending}
|
||||
aria-label="Import profile bundle"
|
||||
title="Import profile bundle"
|
||||
>
|
||||
<Upload className="w-4 h-4" />
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user