Add setup script
This commit is contained in:
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "worktree_path",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE git_repo_path = $1 AND id != $2",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE git_repo_path = $1 AND id != $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
@@ -19,14 +19,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -36,9 +41,10 @@
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "18bfb3eb9408e5268bccf7a17fe02424df8ae3130b70aaad64c5342c198011c9"
|
||||
"hash": "205da45211b3aa413684ecd76d065fc59f793da42da075246464ac776016f5ff"
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_attempt_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "status!: TaskAttemptStatus",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE id = $1",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
@@ -19,14 +19,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -36,9 +41,10 @@
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "0133ba2ace195776eaa714981cdf492d2eaa3dc97dc3379b549a3c4fb8309975"
|
||||
"hash": "346d58b8e0628d6a5936675beadc0a43ffa2dca384ed4f4b3a3abfcd09592c07"
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "worktree_path",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects ORDER BY created_at DESC",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects ORDER BY created_at DESC",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
@@ -19,14 +19,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -36,9 +41,10 @@
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "022ee13a4082ece0cec1100f5c8c4dc5ecbf84018e1c6b735891ec4057e99f72"
|
||||
"hash": "420c9eec0dd98062947b090bc695b67c2bcaba9862c06b701a9ba3d8a5b02abf"
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_attempt_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "status!: TaskAttemptStatus",
|
||||
|
||||
50
backend/.sqlx/query-64fd750d2f767096f94b28650018dc657ad41c6a0af908215f694100319b4864.json
generated
Normal file
50
backend/.sqlx/query-64fd750d2f767096f94b28650018dc657ad41c6a0af908215f694100319b4864.json
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO projects (id, name, git_repo_path, setup_script) VALUES ($1, $2, $3, $4) RETURNING id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\"",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "git_repo_path",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "64fd750d2f767096f94b28650018dc657ad41c6a0af908215f694100319b4864"
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "worktree_path",
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO projects (id, name, git_repo_path) VALUES ($1, $2, $3) RETURNING id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\"",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "git_repo_path",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ab7c095d6ccb8bb41d159aa7dd4f7feb97505e31427c124b4219a6903e971f5a"
|
||||
}
|
||||
50
backend/.sqlx/query-b3bead952fd42b79bed0908db603726935c0e830ea74ff30064bac71185442fc.json
generated
Normal file
50
backend/.sqlx/query-b3bead952fd42b79bed0908db603726935c0e830ea74ff30064bac71185442fc.json
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE projects SET name = $2, git_repo_path = $3, setup_script = $4 WHERE id = $1 RETURNING id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\"",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "git_repo_path",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b3bead952fd42b79bed0908db603726935c0e830ea74ff30064bac71185442fc"
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE git_repo_path = $1",
|
||||
"query": "SELECT id as \"id!: Uuid\", name, git_repo_path, setup_script, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\" FROM projects WHERE git_repo_path = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
@@ -19,14 +19,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"name": "setup_script",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -36,9 +41,10 @@
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "96aade8205a632c862e4dd11118b7b303cbe521c6a42f5a43eda3cf5f8e6ab2c"
|
||||
"hash": "b62fa26fe7cdbee672504dbf63d3dbe19fca02a4a4f97d7df7143f340540efa0"
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "task_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "worktree_path",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "project_id!: Uuid",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE projects SET name = $2, git_repo_path = $3 WHERE id = $1 RETURNING id as \"id!: Uuid\", name, git_repo_path, created_at as \"created_at!: DateTime<Utc>\", updated_at as \"updated_at!: DateTime<Utc>\"",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!: Uuid",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "git_repo_path",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created_at!: DateTime<Utc>",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "updated_at!: DateTime<Utc>",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "eeede8a732db5214bb9054d6c2b7655989102264949864e719610f12cbb4c0c0"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE projects ADD COLUMN setup_script TEXT;
|
||||
@@ -10,6 +10,7 @@ pub struct Project {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub git_repo_path: String,
|
||||
pub setup_script: Option<String>,
|
||||
|
||||
#[ts(type = "Date")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
@@ -23,6 +24,7 @@ pub struct CreateProject {
|
||||
pub name: String,
|
||||
pub git_repo_path: String,
|
||||
pub use_existing_repo: bool,
|
||||
pub setup_script: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, TS)]
|
||||
@@ -30,6 +32,7 @@ pub struct CreateProject {
|
||||
pub struct UpdateProject {
|
||||
pub name: Option<String>,
|
||||
pub git_repo_path: Option<String>,
|
||||
pub setup_script: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, TS)]
|
||||
@@ -52,7 +55,7 @@ impl Project {
|
||||
pub async fn find_all(pool: &SqlitePool) -> Result<Vec<Self>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects ORDER BY created_at DESC"#
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects ORDER BY created_at DESC"#
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
@@ -61,7 +64,7 @@ impl Project {
|
||||
pub async fn find_by_id(pool: &SqlitePool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE id = $1"#,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE id = $1"#,
|
||||
id
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
@@ -74,7 +77,7 @@ impl Project {
|
||||
) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1"#,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1"#,
|
||||
git_repo_path
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
@@ -88,7 +91,7 @@ impl Project {
|
||||
) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1 AND id != $2"#,
|
||||
r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1 AND id != $2"#,
|
||||
git_repo_path,
|
||||
exclude_id
|
||||
)
|
||||
@@ -103,10 +106,11 @@ impl Project {
|
||||
) -> Result<Self, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"INSERT INTO projects (id, name, git_repo_path) VALUES ($1, $2, $3) RETURNING id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
|
||||
r#"INSERT INTO projects (id, name, git_repo_path, setup_script) VALUES ($1, $2, $3, $4) RETURNING id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
|
||||
project_id,
|
||||
data.name,
|
||||
data.git_repo_path
|
||||
data.git_repo_path,
|
||||
data.setup_script
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
@@ -117,13 +121,15 @@ impl Project {
|
||||
id: Uuid,
|
||||
name: String,
|
||||
git_repo_path: String,
|
||||
setup_script: Option<String>,
|
||||
) -> Result<Self, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
r#"UPDATE projects SET name = $2, git_repo_path = $3 WHERE id = $1 RETURNING id as "id!: Uuid", name, git_repo_path, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
|
||||
r#"UPDATE projects SET name = $2, git_repo_path = $3, setup_script = $4 WHERE id = $1 RETURNING id as "id!: Uuid", name, git_repo_path, setup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
|
||||
id,
|
||||
name,
|
||||
git_repo_path
|
||||
git_repo_path,
|
||||
setup_script
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
|
||||
@@ -181,6 +181,41 @@ impl TaskAttempt {
|
||||
let branch_name = format!("attempt-{}", attempt_id);
|
||||
repo.worktree(&branch_name, worktree_path, None)?;
|
||||
|
||||
// Run setup script if it exists
|
||||
if let Some(setup_script) = &project.setup_script {
|
||||
if !setup_script.trim().is_empty() {
|
||||
tracing::info!("Running setup script for task attempt {}", attempt_id);
|
||||
|
||||
let output = std::process::Command::new("bash")
|
||||
.arg("-c")
|
||||
.arg(setup_script)
|
||||
.current_dir(worktree_path)
|
||||
.output()
|
||||
.map_err(|e| {
|
||||
TaskAttemptError::Git(git2::Error::from_str(&format!(
|
||||
"Failed to execute setup script: {}",
|
||||
e
|
||||
)))
|
||||
})?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
tracing::error!("Setup script failed for attempt {}: {}", attempt_id, stderr);
|
||||
return Err(TaskAttemptError::Git(git2::Error::from_str(&format!(
|
||||
"Setup script failed: {}",
|
||||
stderr
|
||||
))));
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
tracing::info!(
|
||||
"Setup script completed for attempt {}: {}",
|
||||
attempt_id,
|
||||
stdout
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the record into the database
|
||||
Ok(sqlx::query_as!(
|
||||
TaskAttempt,
|
||||
|
||||
@@ -204,8 +204,9 @@ pub async fn update_project(
|
||||
let git_repo_path = payload
|
||||
.git_repo_path
|
||||
.unwrap_or(existing_project.git_repo_path.clone());
|
||||
let setup_script = payload.setup_script.or(existing_project.setup_script);
|
||||
|
||||
match Project::update(&pool, id, name, git_repo_path).await {
|
||||
match Project::update(&pool, id, name, git_repo_path, setup_script).await {
|
||||
Ok(project) => Ok(ResponseJson(ApiResponse {
|
||||
success: true,
|
||||
data: Some(project),
|
||||
@@ -387,350 +388,3 @@ pub fn projects_router() -> Router {
|
||||
)
|
||||
.route("/projects/:id/search", get(search_project_files))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::auth::{hash_password, AuthUser};
|
||||
use crate::models::project::{CreateProject, UpdateProject};
|
||||
use axum::extract::Extension;
|
||||
use chrono::Utc;
|
||||
use sqlx::SqlitePool;
|
||||
use uuid::Uuid;
|
||||
|
||||
async fn create_test_user(
|
||||
pool: &SqlitePool,
|
||||
email: &str,
|
||||
password: &str,
|
||||
is_admin: bool,
|
||||
) -> User {
|
||||
let id = Uuid::new_v4();
|
||||
let now = Utc::now();
|
||||
let password_hash = hash_password(password).unwrap();
|
||||
|
||||
sqlx::query_as!(
|
||||
User,
|
||||
"INSERT INTO users (id, email, password_hash, is_admin, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, email, password_hash, is_admin, created_at, updated_at",
|
||||
id,
|
||||
email,
|
||||
password_hash,
|
||||
is_admin,
|
||||
now,
|
||||
now
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn create_test_project(
|
||||
pool: &SqlitePool,
|
||||
name: &str,
|
||||
git_repo_path: &str,
|
||||
owner_id: Uuid,
|
||||
) -> Project {
|
||||
let id = Uuid::new_v4();
|
||||
let now = Utc::now();
|
||||
|
||||
sqlx::query_as!(
|
||||
Project,
|
||||
"INSERT INTO projects (id, name, git_repo_path, owner_id, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, name, git_repo_path, owner_id, created_at, updated_at",
|
||||
id,
|
||||
name,
|
||||
git_repo_path,
|
||||
owner_id,
|
||||
now,
|
||||
now
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_get_projects_success(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
|
||||
// Create multiple projects
|
||||
create_test_project(&pool, "Project 1", "/tmp/test1", user.id).await;
|
||||
create_test_project(&pool, "Project 2", "/tmp/test2", user.id).await;
|
||||
create_test_project(&pool, "Project 3", "/tmp/test3", user.id).await;
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: user.id,
|
||||
email: user.email,
|
||||
is_admin: false,
|
||||
};
|
||||
|
||||
let result = get_projects(auth, Extension(pool)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
assert_eq!(response.data.unwrap().len(), 3);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_get_projects_empty(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: user.id,
|
||||
email: user.email,
|
||||
is_admin: false,
|
||||
};
|
||||
|
||||
let result = get_projects(auth, Extension(pool)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
assert_eq!(response.data.unwrap().len(), 0);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_get_project_success(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let project = create_test_project(&pool, "Test Project", "/tmp/test", user.id).await;
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: user.id,
|
||||
email: user.email,
|
||||
is_admin: false,
|
||||
};
|
||||
|
||||
let result = get_project(auth, Path(project.id), Extension(pool)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
let returned_project = response.data.unwrap();
|
||||
assert_eq!(returned_project.id, project.id);
|
||||
assert_eq!(returned_project.name, project.name);
|
||||
assert_eq!(returned_project.owner_id, project.owner_id);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_get_project_not_found(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let nonexistent_project_id = Uuid::new_v4();
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: user.id,
|
||||
email: user.email,
|
||||
is_admin: false,
|
||||
};
|
||||
|
||||
let result = get_project(auth, Path(nonexistent_project_id), Extension(pool)).await;
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_create_project_success(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: user.id,
|
||||
email: user.email.clone(),
|
||||
is_admin: false,
|
||||
};
|
||||
|
||||
let create_request = CreateProject {
|
||||
name: "New Project".to_string(),
|
||||
git_repo_path: "/tmp/new-project".to_string(),
|
||||
use_existing_repo: false,
|
||||
};
|
||||
|
||||
let result = create_project(auth.clone(), Extension(pool), Json(create_request)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
let created_project = response.data.unwrap();
|
||||
assert_eq!(created_project.name, "New Project");
|
||||
assert_eq!(created_project.owner_id, auth.user_id);
|
||||
assert_eq!(response.message.unwrap(), "Project created successfully");
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_create_project_as_admin(pool: SqlitePool) {
|
||||
let admin_user = create_test_user(&pool, "admin@example.com", "password123", true).await;
|
||||
|
||||
let auth = AuthUser {
|
||||
user_id: admin_user.id,
|
||||
email: admin_user.email.clone(),
|
||||
is_admin: true,
|
||||
};
|
||||
|
||||
let create_request = CreateProject {
|
||||
name: "Admin Project".to_string(),
|
||||
git_repo_path: "/tmp/admin-project".to_string(),
|
||||
use_existing_repo: false,
|
||||
};
|
||||
|
||||
let result = create_project(auth.clone(), Extension(pool), Json(create_request)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
let created_project = response.data.unwrap();
|
||||
assert_eq!(created_project.name, "Admin Project");
|
||||
assert_eq!(created_project.owner_id, auth.user_id);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_update_project_success(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let project = create_test_project(&pool, "Original Name", "/tmp/original", user.id).await;
|
||||
|
||||
let update_request = UpdateProject {
|
||||
name: Some("Updated Name".to_string()),
|
||||
git_repo_path: None,
|
||||
};
|
||||
|
||||
let result = update_project(Path(project.id), Extension(pool), Json(update_request)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
let updated_project = response.data.unwrap();
|
||||
assert_eq!(updated_project.name, "Updated Name");
|
||||
assert_eq!(updated_project.owner_id, project.owner_id);
|
||||
assert_eq!(response.message.unwrap(), "Project updated successfully");
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_update_project_partial(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let project = create_test_project(&pool, "Original Name", "/tmp/original", user.id).await;
|
||||
|
||||
// Update with no changes (None for name should keep existing name)
|
||||
let update_request = UpdateProject {
|
||||
name: None,
|
||||
git_repo_path: None,
|
||||
};
|
||||
|
||||
let result = update_project(Path(project.id), Extension(pool), Json(update_request)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert!(response.data.is_some());
|
||||
let updated_project = response.data.unwrap();
|
||||
assert_eq!(updated_project.name, "Original Name"); // Should remain unchanged
|
||||
assert_eq!(updated_project.owner_id, project.owner_id);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_update_project_not_found(pool: SqlitePool) {
|
||||
let nonexistent_project_id = Uuid::new_v4();
|
||||
|
||||
let update_request = UpdateProject {
|
||||
name: Some("Updated Name".to_string()),
|
||||
git_repo_path: None,
|
||||
};
|
||||
|
||||
let result = update_project(
|
||||
Path(nonexistent_project_id),
|
||||
Extension(pool),
|
||||
Json(update_request),
|
||||
)
|
||||
.await;
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_delete_project_success(pool: SqlitePool) {
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let project =
|
||||
create_test_project(&pool, "Project to Delete", "/tmp/to-delete", user.id).await;
|
||||
|
||||
let result = delete_project(Path(project.id), Extension(pool)).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let response = result.unwrap().0;
|
||||
assert!(response.success);
|
||||
assert_eq!(response.message.unwrap(), "Project deleted successfully");
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_delete_project_not_found(pool: SqlitePool) {
|
||||
let nonexistent_project_id = Uuid::new_v4();
|
||||
|
||||
let result = delete_project(Path(nonexistent_project_id), Extension(pool)).await;
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_delete_project_cascades_to_tasks(pool: SqlitePool) {
|
||||
use crate::models::task::{Task, TaskStatus};
|
||||
|
||||
let user = create_test_user(&pool, "test@example.com", "password123", false).await;
|
||||
let project =
|
||||
create_test_project(&pool, "Project with Tasks", "/tmp/with-tasks", user.id).await;
|
||||
|
||||
// Create a task in the project
|
||||
let task_id = Uuid::new_v4();
|
||||
let now = Utc::now();
|
||||
sqlx::query!(
|
||||
"INSERT INTO tasks (id, project_id, title, description, status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
task_id,
|
||||
project.id,
|
||||
"Test Task",
|
||||
Some("Test Description"),
|
||||
TaskStatus::Todo as TaskStatus,
|
||||
now,
|
||||
now
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Verify task exists
|
||||
let task_count_before = sqlx::query!(
|
||||
"SELECT COUNT(*) as count FROM tasks WHERE project_id = $1",
|
||||
project.id
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(task_count_before.count.unwrap(), 1);
|
||||
|
||||
// Delete the project
|
||||
let result = delete_project(Path(project.id), Extension(pool.clone())).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Verify tasks were cascaded (deleted)
|
||||
let task_count_after = sqlx::query!(
|
||||
"SELECT COUNT(*) as count FROM tasks WHERE project_id = $1",
|
||||
project.id
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(task_count_after.count.unwrap(), 0);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_projects_belong_to_users(pool: SqlitePool) {
|
||||
let user1 = create_test_user(&pool, "user1@example.com", "password123", false).await;
|
||||
let user2 = create_test_user(&pool, "user2@example.com", "password123", false).await;
|
||||
|
||||
let project1 = create_test_project(&pool, "User 1 Project", "/tmp/user1", user1.id).await;
|
||||
let project2 = create_test_project(&pool, "User 2 Project", "/tmp/user2", user2.id).await;
|
||||
|
||||
// Verify project ownership
|
||||
assert_eq!(project1.owner_id, user1.id);
|
||||
assert_eq!(project2.owner_id, user2.id);
|
||||
assert_ne!(project1.owner_id, project2.owner_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -31,6 +31,7 @@ export function ProjectForm({
|
||||
}: ProjectFormProps) {
|
||||
const [name, setName] = useState(project?.name || "");
|
||||
const [gitRepoPath, setGitRepoPath] = useState(project?.git_repo_path || "");
|
||||
const [setupScript, setSetupScript] = useState(project?.setup_script ?? "");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [showFolderPicker, setShowFolderPicker] = useState(false);
|
||||
@@ -40,6 +41,19 @@ export function ProjectForm({
|
||||
|
||||
const isEditing = !!project;
|
||||
|
||||
// Update form fields when project prop changes
|
||||
useEffect(() => {
|
||||
if (project) {
|
||||
setName(project.name || "");
|
||||
setGitRepoPath(project.git_repo_path || "");
|
||||
setSetupScript(project.setup_script ?? "");
|
||||
} else {
|
||||
setName("");
|
||||
setGitRepoPath("");
|
||||
setSetupScript("");
|
||||
}
|
||||
}, [project]);
|
||||
|
||||
// Auto-populate project name from directory name
|
||||
const handleGitRepoPathChange = (path: string) => {
|
||||
setGitRepoPath(path);
|
||||
@@ -75,6 +89,7 @@ export function ProjectForm({
|
||||
const updateData: UpdateProject = {
|
||||
name,
|
||||
git_repo_path: finalGitRepoPath,
|
||||
setup_script: setupScript.trim() || null,
|
||||
};
|
||||
const response = await makeRequest(
|
||||
`/api/projects/${project.id}`,
|
||||
@@ -97,6 +112,7 @@ export function ProjectForm({
|
||||
name,
|
||||
git_repo_path: finalGitRepoPath,
|
||||
use_existing_repo: repoMode === "existing",
|
||||
setup_script: setupScript.trim() || null,
|
||||
};
|
||||
const response = await makeRequest("/api/projects", {
|
||||
method: "POST",
|
||||
@@ -116,6 +132,7 @@ export function ProjectForm({
|
||||
onSuccess();
|
||||
setName("");
|
||||
setGitRepoPath("");
|
||||
setSetupScript("");
|
||||
setParentPath("");
|
||||
setFolderName("");
|
||||
} catch (error) {
|
||||
@@ -126,8 +143,17 @@ export function ProjectForm({
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setName(project?.name || "");
|
||||
setGitRepoPath(project?.git_repo_path || "");
|
||||
if (project) {
|
||||
setName(project.name || "");
|
||||
setGitRepoPath(project.git_repo_path || "");
|
||||
setSetupScript(project.setup_script ?? "");
|
||||
} else {
|
||||
setName("");
|
||||
setGitRepoPath("");
|
||||
setSetupScript("");
|
||||
}
|
||||
setParentPath("");
|
||||
setFolderName("");
|
||||
setError("");
|
||||
onClose();
|
||||
};
|
||||
@@ -274,6 +300,22 @@ export function ProjectForm({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="setup-script">Setup Script (Optional)</Label>
|
||||
<textarea
|
||||
id="setup-script"
|
||||
value={setupScript}
|
||||
onChange={(e) => setSetupScript(e.target.value)}
|
||||
placeholder="#!/bin/bash npm install # Add any setup commands here..."
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-input bg-background text-foreground rounded-md resize-vertical focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
This script will run after creating the worktree and before the executor starts.
|
||||
Use it for setup tasks like installing dependencies or preparing the environment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
|
||||
@@ -5,11 +5,11 @@ export type ApiResponse<T> = { success: boolean, data: T | null, message: string
|
||||
|
||||
export type ExecutorConfig = { "type": "echo" } | { "type": "claude" } | { "type": "amp" };
|
||||
|
||||
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, };
|
||||
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, setup_script: string | null, };
|
||||
|
||||
export type Project = { id: string, name: string, git_repo_path: string, created_at: Date, updated_at: Date, };
|
||||
export type Project = { id: string, name: string, git_repo_path: string, setup_script: string | null, created_at: Date, updated_at: Date, };
|
||||
|
||||
export type UpdateProject = { name: string | null, git_repo_path: string | null, };
|
||||
export type UpdateProject = { name: string | null, git_repo_path: string | null, setup_script: string | null, };
|
||||
|
||||
export type SearchResult = { path: string, is_file: boolean, match_type: SearchMatchType, };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user