Task attempt 55cc3eff-6099-484a-b9c1-899d2a3528ce - Final changes
This commit is contained in:
@@ -20,60 +20,66 @@ fn main() {
|
|||||||
r#"// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
r#"// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
// Auto-generated from Rust backend types using ts-rs
|
// Auto-generated from Rust backend types using ts-rs
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}
|
{}
|
||||||
|
|
||||||
export {}"#,
|
{}
|
||||||
|
|
||||||
|
{}
|
||||||
|
|
||||||
|
{}"#,
|
||||||
vibe_kanban::models::ApiResponse::<()>::decl(),
|
vibe_kanban::models::ApiResponse::<()>::decl(),
|
||||||
vibe_kanban::models::config::Config::decl(),
|
vibe_kanban::models::config::Config::decl(),
|
||||||
vibe_kanban::models::config::ThemeMode::decl(),
|
vibe_kanban::models::config::ThemeMode::decl(),
|
||||||
|
vibe_kanban::models::config::EditorConfig::decl(),
|
||||||
|
vibe_kanban::models::config::EditorType::decl(),
|
||||||
vibe_kanban::executor::ExecutorConfig::decl(),
|
vibe_kanban::executor::ExecutorConfig::decl(),
|
||||||
vibe_kanban::models::project::CreateProject::decl(),
|
vibe_kanban::models::project::CreateProject::decl(),
|
||||||
vibe_kanban::models::project::Project::decl(),
|
vibe_kanban::models::project::Project::decl(),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ pub struct Config {
|
|||||||
pub executor: ExecutorConfig,
|
pub executor: ExecutorConfig,
|
||||||
pub disclaimer_acknowledged: bool,
|
pub disclaimer_acknowledged: bool,
|
||||||
pub sound_alerts: bool,
|
pub sound_alerts: bool,
|
||||||
|
pub editor: EditorConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
@@ -21,6 +22,25 @@ pub enum ThemeMode {
|
|||||||
System,
|
System,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct EditorConfig {
|
||||||
|
pub editor_type: EditorType,
|
||||||
|
pub custom_command: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum EditorType {
|
||||||
|
VSCode,
|
||||||
|
Cursor,
|
||||||
|
Windsurf,
|
||||||
|
IntelliJ,
|
||||||
|
Zed,
|
||||||
|
Custom,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -28,6 +48,35 @@ impl Default for Config {
|
|||||||
executor: ExecutorConfig::Claude,
|
executor: ExecutorConfig::Claude,
|
||||||
disclaimer_acknowledged: false,
|
disclaimer_acknowledged: false,
|
||||||
sound_alerts: true,
|
sound_alerts: true,
|
||||||
|
editor: EditorConfig::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EditorConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
editor_type: EditorType::VSCode,
|
||||||
|
custom_command: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditorConfig {
|
||||||
|
pub fn get_command(&self) -> Vec<String> {
|
||||||
|
match &self.editor_type {
|
||||||
|
EditorType::VSCode => vec!["code".to_string()],
|
||||||
|
EditorType::Cursor => vec!["cursor".to_string()],
|
||||||
|
EditorType::Windsurf => vec!["windsurf".to_string()],
|
||||||
|
EditorType::IntelliJ => vec!["idea".to_string()],
|
||||||
|
EditorType::Zed => vec!["zed".to_string()],
|
||||||
|
EditorType::Custom => {
|
||||||
|
if let Some(custom) = &self.custom_command {
|
||||||
|
custom.split_whitespace().map(|s| s.to_string()).collect()
|
||||||
|
} else {
|
||||||
|
vec!["code".to_string()] // fallback to VSCode
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use axum::{
|
|||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
@@ -452,6 +453,7 @@ pub async fn merge_task_attempt(
|
|||||||
pub async fn open_task_attempt_in_editor(
|
pub async fn open_task_attempt_in_editor(
|
||||||
Path((project_id, task_id, attempt_id)): Path<(Uuid, Uuid, Uuid)>,
|
Path((project_id, task_id, attempt_id)): Path<(Uuid, Uuid, Uuid)>,
|
||||||
Extension(pool): Extension<SqlitePool>,
|
Extension(pool): Extension<SqlitePool>,
|
||||||
|
Extension(config): Extension<Arc<Mutex<crate::models::config::Config>>>,
|
||||||
) -> Result<ResponseJson<ApiResponse<()>>, StatusCode> {
|
) -> Result<ResponseJson<ApiResponse<()>>, StatusCode> {
|
||||||
// Verify task attempt exists and belongs to the correct task
|
// Verify task attempt exists and belongs to the correct task
|
||||||
match TaskAttempt::exists_for_task(&pool, attempt_id, task_id, project_id).await {
|
match TaskAttempt::exists_for_task(&pool, attempt_id, task_id, project_id).await {
|
||||||
@@ -473,29 +475,44 @@ pub async fn open_task_attempt_in_editor(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open VSCode in the worktree directory
|
// Get editor command from config
|
||||||
match std::process::Command::new("code")
|
let editor_command = {
|
||||||
.arg(&attempt.worktree_path)
|
let config_guard = config.lock().unwrap();
|
||||||
.spawn()
|
config_guard.editor.get_command()
|
||||||
{
|
};
|
||||||
|
|
||||||
|
// Open editor in the worktree directory
|
||||||
|
let mut cmd = std::process::Command::new(&editor_command[0]);
|
||||||
|
for arg in &editor_command[1..] {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
cmd.arg(&attempt.worktree_path);
|
||||||
|
|
||||||
|
match cmd.spawn() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Opened VSCode for task attempt {} at path: {}",
|
"Opened editor ({}) for task attempt {} at path: {}",
|
||||||
|
editor_command.join(" "),
|
||||||
attempt_id,
|
attempt_id,
|
||||||
attempt.worktree_path
|
attempt.worktree_path
|
||||||
);
|
);
|
||||||
Ok(ResponseJson(ApiResponse {
|
Ok(ResponseJson(ApiResponse {
|
||||||
success: true,
|
success: true,
|
||||||
data: None,
|
data: None,
|
||||||
message: Some("VSCode opened successfully".to_string()),
|
message: Some("Editor opened successfully".to_string()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Failed to open VSCode for attempt {}: {}", attempt_id, e);
|
tracing::error!(
|
||||||
|
"Failed to open editor ({}) for attempt {}: {}",
|
||||||
|
editor_command.join(" "),
|
||||||
|
attempt_id,
|
||||||
|
e
|
||||||
|
);
|
||||||
Ok(ResponseJson(ApiResponse {
|
Ok(ResponseJson(ApiResponse {
|
||||||
success: false,
|
success: false,
|
||||||
data: None,
|
data: None,
|
||||||
message: Some(format!("Failed to open VSCode: {}", e)),
|
message: Some(format!("Failed to open editor: {}", e)),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import type { Config, ThemeMode, ApiResponse } from "shared/types";
|
import type { Config, ThemeMode, EditorType, ApiResponse } from "shared/types";
|
||||||
import { useTheme } from "@/components/theme-provider";
|
import { useTheme } from "@/components/theme-provider";
|
||||||
|
|
||||||
export function Settings() {
|
export function Settings() {
|
||||||
@@ -191,6 +192,65 @@ export function Settings() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Editor</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Configure which editor to open when viewing task attempts.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="editor">Preferred Editor</Label>
|
||||||
|
<Select
|
||||||
|
value={config.editor.editor_type}
|
||||||
|
onValueChange={(value: EditorType) => updateConfig({
|
||||||
|
editor: {
|
||||||
|
...config.editor,
|
||||||
|
editor_type: value,
|
||||||
|
custom_command: value === "custom" ? config.editor.custom_command : null
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<SelectTrigger id="editor">
|
||||||
|
<SelectValue placeholder="Select editor" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="vscode">VS Code</SelectItem>
|
||||||
|
<SelectItem value="cursor">Cursor</SelectItem>
|
||||||
|
<SelectItem value="windsurf">Windsurf</SelectItem>
|
||||||
|
<SelectItem value="intellij">IntelliJ IDEA</SelectItem>
|
||||||
|
<SelectItem value="zed">Zed</SelectItem>
|
||||||
|
<SelectItem value="custom">Custom Command</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Choose your preferred code editor for opening task attempts.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{config.editor.editor_type === "custom" && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="custom-command">Custom Command</Label>
|
||||||
|
<Input
|
||||||
|
id="custom-command"
|
||||||
|
placeholder="e.g., code, subl, vim"
|
||||||
|
value={config.editor.custom_command || ""}
|
||||||
|
onChange={(e) => updateConfig({
|
||||||
|
editor: {
|
||||||
|
...config.editor,
|
||||||
|
custom_command: e.target.value || null
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Enter the command to run your custom editor. Use spaces for arguments (e.g., "code --wait").
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Notifications</CardTitle>
|
<CardTitle>Notifications</CardTitle>
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
export type ApiResponse<T> = { success: boolean, data: T | null, message: string | null, };
|
export type ApiResponse<T> = { success: boolean, data: T | null, message: string | null, };
|
||||||
|
|
||||||
export type Config = { theme: ThemeMode, executor: ExecutorConfig, disclaimer_acknowledged: boolean, sound_alerts: boolean, };
|
export type Config = { theme: ThemeMode, executor: ExecutorConfig, disclaimer_acknowledged: boolean, sound_alerts: boolean, editor: EditorConfig, };
|
||||||
|
|
||||||
export type ThemeMode = "light" | "dark" | "system";
|
export type ThemeMode = "light" | "dark" | "system";
|
||||||
|
|
||||||
|
export type EditorConfig = { editor_type: EditorType, custom_command: string | null, };
|
||||||
|
|
||||||
|
export type EditorType = "vscode" | "cursor" | "windsurf" | "intellij" | "zed" | "custom";
|
||||||
|
|
||||||
export type ExecutorConfig = { "type": "echo" } | { "type": "claude" } | { "type": "amp" };
|
export type ExecutorConfig = { "type": "echo" } | { "type": "claude" } | { "type": "amp" };
|
||||||
|
|
||||||
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, setup_script: string | null, };
|
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, setup_script: string | null, };
|
||||||
|
|||||||
Reference in New Issue
Block a user