886c863260
- Use profile-scoped canonical Git clone sources with locked refreshes - Mount shared Git configuration read-only and isolate profile content - Add API and desktop/mobile actions for live Git mount refresh Quality gates: frontend build and backend py_compile passed. Skipped: backend pytest/Ruff unavailable; Docker/manual checks not approved.
206 lines
5.0 KiB
TypeScript
206 lines
5.0 KiB
TypeScript
import { apiClient } from "./client";
|
|
|
|
export interface ConfigProfileRefreshOutcome {
|
|
instance_id: string;
|
|
status: "compatible" | "refreshed" | "restart_required" | "incompatible_permissions";
|
|
reason?: string;
|
|
}
|
|
|
|
export interface ConfigProfile {
|
|
id: string;
|
|
user_id: string;
|
|
name: string;
|
|
description: string | null;
|
|
project_id: string | null;
|
|
tool_type_id: string | null;
|
|
env_vars: Record<string, string>;
|
|
runtime_hints: Record<string, unknown>;
|
|
mounts: ConfigProfileMount[];
|
|
git_mounts: GitMount[];
|
|
files: Record<string, string>;
|
|
is_default: boolean;
|
|
includes: ConfigProfileInclude[];
|
|
created_at: string;
|
|
updated_at: string;
|
|
refresh_outcomes?: ConfigProfileRefreshOutcome[];
|
|
}
|
|
|
|
export interface ConfigProfileMount {
|
|
target: string;
|
|
mode: "ro" | "rw";
|
|
files: Record<string, string>;
|
|
}
|
|
|
|
export interface GitMountMapping {
|
|
source_path: string;
|
|
target_path: string;
|
|
}
|
|
|
|
export interface GitMount {
|
|
remote_url: string;
|
|
branch?: string;
|
|
mappings: GitMountMapping[];
|
|
// Legacy fields (for backward compatibility when reading old data)
|
|
source_path?: string;
|
|
target_path?: string;
|
|
}
|
|
|
|
export interface ConfigProfileInclude {
|
|
id: string;
|
|
included_profile_id: string;
|
|
order_index: number;
|
|
}
|
|
|
|
export interface ResolvedProfile {
|
|
profile_id: string;
|
|
profile_name: string;
|
|
env_vars: Record<string, string>;
|
|
runtime_hints: Record<string, unknown>;
|
|
mounts: ResolvedMount[];
|
|
git_mounts: GitMount[];
|
|
files: Record<string, string>;
|
|
overrides: {
|
|
env_vars: Record<string, string>;
|
|
runtime_hints: Record<string, string>;
|
|
files: Record<string, string>;
|
|
mounts: Record<string, string>;
|
|
};
|
|
included_profiles: Array<{ id: string; name: string }>;
|
|
}
|
|
|
|
export interface ResolvedMount {
|
|
target: string;
|
|
mode: "ro" | "rw";
|
|
files: Record<string, string>;
|
|
overridden_files: Record<string, string>;
|
|
}
|
|
|
|
export interface CreateConfigProfileRequest {
|
|
name: string;
|
|
description?: string;
|
|
project_id?: string;
|
|
tool_type_id?: string;
|
|
env_vars?: Record<string, string>;
|
|
runtime_hints?: Record<string, unknown>;
|
|
mounts?: ConfigProfileMount[];
|
|
git_mounts?: GitMount[];
|
|
files?: Record<string, string>;
|
|
is_default?: boolean;
|
|
}
|
|
|
|
export interface UpdateConfigProfileRequest {
|
|
name?: string;
|
|
description?: string;
|
|
project_id?: string;
|
|
tool_type_id?: string;
|
|
env_vars?: Record<string, string>;
|
|
runtime_hints?: Record<string, unknown>;
|
|
mounts?: ConfigProfileMount[];
|
|
git_mounts?: GitMount[];
|
|
files?: Record<string, string>;
|
|
is_default?: boolean;
|
|
}
|
|
|
|
export interface UpdateIncludesRequest {
|
|
includes: string[];
|
|
}
|
|
|
|
export const listConfigProfiles = async (
|
|
projectId?: string,
|
|
toolTypeId?: string,
|
|
): Promise<ConfigProfile[]> => {
|
|
const response = await apiClient.get<ConfigProfile[]>("/config-profiles", {
|
|
params: { project_id: projectId, tool_type_id: toolTypeId },
|
|
});
|
|
return response.data;
|
|
};
|
|
|
|
export const getConfigProfile = async (id: string): Promise<ConfigProfile> => {
|
|
const response = await apiClient.get<ConfigProfile>(`/config-profiles/${id}`);
|
|
return response.data;
|
|
};
|
|
|
|
export const createConfigProfile = async (
|
|
data: CreateConfigProfileRequest,
|
|
): Promise<ConfigProfile> => {
|
|
const response = await apiClient.post<ConfigProfile>(
|
|
"/config-profiles",
|
|
data,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
export const updateConfigProfile = async (
|
|
id: string,
|
|
data: UpdateConfigProfileRequest,
|
|
): Promise<ConfigProfile> => {
|
|
const response = await apiClient.put<ConfigProfile>(
|
|
`/config-profiles/${id}`,
|
|
data,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
export const deleteConfigProfile = async (id: string): Promise<void> => {
|
|
await apiClient.delete(`/config-profiles/${id}`);
|
|
};
|
|
|
|
export const refreshConfigProfileGitMounts = async (
|
|
id: string,
|
|
): Promise<{ refresh_outcomes: ConfigProfileRefreshOutcome[] }> => {
|
|
const response = await apiClient.post<{
|
|
refresh_outcomes: ConfigProfileRefreshOutcome[];
|
|
}>(`/config-profiles/${id}/refresh-git-mounts`);
|
|
return response.data;
|
|
};
|
|
|
|
export const updateProfileIncludes = async (
|
|
id: string,
|
|
data: UpdateIncludesRequest,
|
|
): Promise<ConfigProfile> => {
|
|
const response = await apiClient.put<ConfigProfile>(
|
|
`/config-profiles/${id}/includes`,
|
|
data,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
export const previewConfigProfile = async (
|
|
id: string,
|
|
): Promise<ResolvedProfile> => {
|
|
const response = await apiClient.get<ResolvedProfile>(
|
|
`/config-profiles/${id}/preview`,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
export const resolveDefaultProfile = async (
|
|
projectId: string,
|
|
toolTypeId: string,
|
|
): Promise<{ profile_id: string | null; profile_name: string | null }> => {
|
|
const response = await apiClient.get("/config-profiles/defaults/resolve", {
|
|
params: { project_id: projectId, tool_type_id: toolTypeId },
|
|
});
|
|
return response.data;
|
|
};
|
|
|
|
export interface ValidateGitUrlResponse {
|
|
valid: boolean;
|
|
suggested_url?: string;
|
|
branches?: string[];
|
|
default_branch?: string;
|
|
error?: string;
|
|
error_code?: string;
|
|
}
|
|
|
|
export const validateGitUrl = async (
|
|
url: string,
|
|
sshKeyId?: string,
|
|
): Promise<ValidateGitUrlResponse> => {
|
|
const response = await apiClient.post<ValidateGitUrlResponse>(
|
|
"/config-profiles/validate-git-url",
|
|
{ url, ssh_key_id: sshKeyId },
|
|
);
|
|
return response.data;
|
|
};
|