feat: make repo URL optional when creating an app

Useful for git-push-only deploys where no external repo URL is needed.
- CreateApp.repo_url: String → Option<String>
- DB schema default: repo_url TEXT NOT NULL DEFAULT ''
- UI validation no longer requires the field
- Label marked (optional) in the form

https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
Claude 2026-03-24 10:37:17 +00:00
parent bb26a81fe6
commit 5bc1948f1a
No known key found for this signature in database
4 changed files with 5 additions and 5 deletions

View file

@ -17,7 +17,7 @@ pub async fn migrate(pool: &DbPool) -> anyhow::Result<()> {
r#"CREATE TABLE IF NOT EXISTS apps ( r#"CREATE TABLE IF NOT EXISTS apps (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
repo_url TEXT NOT NULL, repo_url TEXT NOT NULL DEFAULT '',
branch TEXT NOT NULL DEFAULT 'main', branch TEXT NOT NULL DEFAULT 'main',
port INTEGER NOT NULL, port INTEGER NOT NULL,
webhook_secret TEXT NOT NULL, webhook_secret TEXT NOT NULL,

View file

@ -15,7 +15,7 @@ pub struct App {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct CreateApp { pub struct CreateApp {
pub name: String, pub name: String,
pub repo_url: String, pub repo_url: Option<String>,
pub branch: Option<String>, pub branch: Option<String>,
pub port: i64, pub port: i64,
} }

View file

@ -36,7 +36,7 @@ pub async fn create(
) )
.bind(&id) .bind(&id)
.bind(&payload.name) .bind(&payload.name)
.bind(&payload.repo_url) .bind(payload.repo_url.unwrap_or_default())
.bind(&branch) .bind(&branch)
.bind(payload.port) .bind(payload.port)
.bind(&secret) .bind(&secret)

View file

@ -241,7 +241,7 @@ pub async fn index(State(s): State<AppState>) -> Result<Html<String>, StatusCode
<h2>Add App</h2> <h2>Add App</h2>
<div class="grid2" style="margin-bottom:12px"> <div class="grid2" style="margin-bottom:12px">
<div><label>Name (slug)</label><input id="f-name" type="text" placeholder="my-api"></div> <div><label>Name (slug)</label><input id="f-name" type="text" placeholder="my-api"></div>
<div><label>GitHub Repo URL</label><input id="f-repo" type="text" placeholder="https://github.com/you/repo.git"></div> <div><label>GitHub Repo URL <span style="font-weight:normal;opacity:.6">(optional)</span></label><input id="f-repo" type="text" placeholder="https://github.com/you/repo.git"></div>
</div> </div>
<div class="grid2" style="margin-bottom:16px"> <div class="grid2" style="margin-bottom:16px">
<div><label>Branch</label><input id="f-branch" type="text" value="main"></div> <div><label>Branch</label><input id="f-branch" type="text" value="main"></div>
@ -266,7 +266,7 @@ pub async fn index(State(s): State<AppState>) -> Result<Html<String>, StatusCode
branch: document.getElementById('f-branch').value.trim() || 'main', branch: document.getElementById('f-branch').value.trim() || 'main',
port: parseInt(document.getElementById('f-port').value), port: parseInt(document.getElementById('f-port').value),
}}; }};
if (!data.name || !data.repo_url || !data.port) {{ alert('Fill in all fields'); return; }} if (!data.name || !data.port) {{ alert('Fill in all fields'); return; }}
const r = await fetch('/api/apps', {{ const r = await fetch('/api/apps', {{
method: 'POST', method: 'POST',
headers: {{'Content-Type': 'application/json'}}, headers: {{'Content-Type': 'application/json'}},