refactor(cursor): seperate components and add permissions skeleton

This commit is contained in:
Kacper
2025-12-30 17:54:02 +01:00
parent 3c6736bc44
commit 853292af45
7 changed files with 682 additions and 507 deletions

View File

@@ -1,2 +1,4 @@
export { useCliStatus } from './use-cli-status';
export { useSettingsView, type SettingsViewId } from './use-settings-view';
export { useCursorStatus, type CursorStatus } from './use-cursor-status';
export { useCursorPermissions, type PermissionsData } from './use-cursor-permissions';

View File

@@ -0,0 +1,103 @@
import { useState, useCallback } from 'react';
import { toast } from 'sonner';
import { getHttpApiClient } from '@/lib/http-api-client';
import type { CursorPermissionProfile } from '@automaker/types';
export interface PermissionsData {
activeProfile: CursorPermissionProfile | null;
effectivePermissions: { allow: string[]; deny: string[] } | null;
hasProjectConfig: boolean;
availableProfiles: Array<{
id: string;
name: string;
description: string;
permissions: { allow: string[]; deny: string[] };
}>;
}
/**
* Custom hook for managing Cursor CLI permissions
* Handles loading permissions data, applying profiles, and copying configs
*/
export function useCursorPermissions(projectPath?: string) {
const [permissions, setPermissions] = useState<PermissionsData | null>(null);
const [isLoadingPermissions, setIsLoadingPermissions] = useState(false);
const [isSavingPermissions, setIsSavingPermissions] = useState(false);
const [copiedConfig, setCopiedConfig] = useState(false);
// Load permissions data
const loadPermissions = useCallback(async () => {
setIsLoadingPermissions(true);
try {
const api = getHttpApiClient();
const result = await api.setup.getCursorPermissions(projectPath);
if (result.success) {
setPermissions({
activeProfile: result.activeProfile || null,
effectivePermissions: result.effectivePermissions || null,
hasProjectConfig: result.hasProjectConfig || false,
availableProfiles: result.availableProfiles || [],
});
}
} catch (error) {
console.error('Failed to load Cursor permissions:', error);
} finally {
setIsLoadingPermissions(false);
}
}, [projectPath]);
// Apply a permission profile
const applyProfile = useCallback(
async (profileId: 'strict' | 'development', scope: 'global' | 'project') => {
setIsSavingPermissions(true);
try {
const api = getHttpApiClient();
const result = await api.setup.applyCursorPermissionProfile(
profileId,
scope,
scope === 'project' ? projectPath : undefined
);
if (result.success) {
toast.success(result.message || `Applied ${profileId} profile`);
await loadPermissions();
} else {
toast.error(result.error || 'Failed to apply profile');
}
} catch (error) {
toast.error('Failed to apply profile');
} finally {
setIsSavingPermissions(false);
}
},
[projectPath, loadPermissions]
);
// Copy example config to clipboard
const copyConfig = useCallback(async (profileId: 'strict' | 'development') => {
try {
const api = getHttpApiClient();
const result = await api.setup.getCursorExampleConfig(profileId);
if (result.success && result.config) {
await navigator.clipboard.writeText(result.config);
setCopiedConfig(true);
toast.success('Config copied to clipboard');
setTimeout(() => setCopiedConfig(false), 2000);
}
} catch (error) {
toast.error('Failed to copy config');
}
}, []);
return {
permissions,
isLoadingPermissions,
isSavingPermissions,
copiedConfig,
loadPermissions,
applyProfile,
copyConfig,
};
}

View File

@@ -0,0 +1,67 @@
import { useState, useEffect, useCallback } from 'react';
import { toast } from 'sonner';
import { getHttpApiClient } from '@/lib/http-api-client';
import { useSetupStore } from '@/store/setup-store';
export interface CursorStatus {
installed: boolean;
version?: string;
authenticated: boolean;
method?: string;
}
/**
* Custom hook for managing Cursor CLI status
* Handles checking CLI installation, authentication, and refresh functionality
*/
export function useCursorStatus() {
const { setCursorCliStatus } = useSetupStore();
const [status, setStatus] = useState<CursorStatus | null>(null);
const [isLoading, setIsLoading] = useState(true);
const loadData = useCallback(async () => {
setIsLoading(true);
try {
const api = getHttpApiClient();
const statusResult = await api.setup.getCursorStatus();
if (statusResult.success) {
const newStatus = {
installed: statusResult.installed ?? false,
version: statusResult.version ?? undefined,
authenticated: statusResult.auth?.authenticated ?? false,
method: statusResult.auth?.method,
};
setStatus(newStatus);
// Also update the global setup store so other components can access the status
setCursorCliStatus({
installed: newStatus.installed,
version: newStatus.version,
auth: newStatus.authenticated
? {
authenticated: true,
method: newStatus.method || 'unknown',
}
: undefined,
});
}
} catch (error) {
console.error('Failed to load Cursor settings:', error);
toast.error('Failed to load Cursor settings');
} finally {
setIsLoading(false);
}
}, [setCursorCliStatus]);
useEffect(() => {
loadData();
}, [loadData]);
return {
status,
isLoading,
loadData,
};
}