ui improovements
This commit is contained in:
parent
1dce9fb0e8
commit
950139010e
7 changed files with 67 additions and 0 deletions
|
|
@ -80,6 +80,27 @@ func (a *App) ensureCaddyRoute(ctx context.Context, p Project) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *App) fetchCaddyConfig(ctx context.Context) (map[string]any, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, a.cfg.CaddyAdminURL+"/config/", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("caddy config request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode >= 300 {
|
||||
return nil, fmt.Errorf("caddy config error: status=%d body=%s", resp.StatusCode, string(body))
|
||||
}
|
||||
var out map[string]any
|
||||
if err := json.Unmarshal(body, &out); err != nil {
|
||||
return nil, fmt.Errorf("caddy config parse failed: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *App) ensureForgejoDeployWebhook(ctx context.Context, p Project) error {
|
||||
if a.cfg.ForgejoBaseURL == "" || a.cfg.ForgejoToken == "" || p.RepoURL == "" {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ func (a *App) listProjects(ctx context.Context, userID string) ([]Project, error
|
|||
return nil, err
|
||||
}
|
||||
p.WebhookURL = a.deployWebhookURL(p.ID, p.DeployToken)
|
||||
p.AppURL = a.appURL(p.RouteHost)
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
|
|
@ -70,6 +71,7 @@ func (a *App) createProject(ctx context.Context, user User, workspaceID int64, n
|
|||
p.Workspace = workspace.Name
|
||||
p.UnixUser = workspace.UnixUser
|
||||
p.WebhookURL = a.deployWebhookURL(p.ID, p.DeployToken)
|
||||
p.AppURL = a.appURL(p.RouteHost)
|
||||
return p, a.provisionProject(ctx, &p)
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +154,7 @@ func (a *App) getProject(ctx context.Context, userID string, projectID int64) (P
|
|||
return Project{}, err
|
||||
}
|
||||
p.WebhookURL = a.deployWebhookURL(p.ID, p.DeployToken)
|
||||
p.AppURL = a.appURL(p.RouteHost)
|
||||
return p, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ func (a *App) routes() http.Handler {
|
|||
mux.HandleFunc("/api/workspaces", a.withAuth(a.handleWorkspaces))
|
||||
mux.HandleFunc("/api/projects", a.withAuth(a.handleProjects))
|
||||
mux.HandleFunc("/api/projects/", a.withAuth(a.handleProjectSubroutes))
|
||||
mux.HandleFunc("/api/caddy/config", a.withAuth(a.handleCaddyConfig))
|
||||
mux.HandleFunc("/api/webhooks/deploy/", a.handleDeployWebhook)
|
||||
return loggingMiddleware(mux)
|
||||
}
|
||||
|
|
@ -268,3 +269,16 @@ func (a *App) handleProjectLogs(w http.ResponseWriter, r *http.Request, user Use
|
|||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"lines": lines, "logs": logs})
|
||||
}
|
||||
|
||||
func (a *App) handleCaddyConfig(w http.ResponseWriter, r *http.Request, _ User) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
cfg, err := a.fetchCaddyConfig(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, cfg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ type Project struct {
|
|||
RepoPrivate bool `json:"repo_private"`
|
||||
ServiceName string `json:"service_name"`
|
||||
RouteHost string `json:"route_host"`
|
||||
AppURL string `json:"app_url"`
|
||||
TargetPort int `json:"target_port"`
|
||||
WorkspaceID int64 `json:"workspace_id"`
|
||||
Workspace string `json:"workspace"`
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ func (a *App) deployWebhookURL(projectID int64, token string) string {
|
|||
return path
|
||||
}
|
||||
|
||||
func (a *App) appURL(routeHost string) string {
|
||||
routeHost = strings.TrimSpace(routeHost)
|
||||
if routeHost == "" {
|
||||
return ""
|
||||
}
|
||||
return "https://" + routeHost
|
||||
}
|
||||
|
||||
func newDeployToken() (string, error) {
|
||||
buf := make([]byte, 24)
|
||||
if _, err := rand.Read(buf); err != nil {
|
||||
|
|
|
|||
14
web/app.js
14
web/app.js
|
|
@ -15,8 +15,10 @@ async function init() {
|
|||
|
||||
document.getElementById('workspaceForm').addEventListener('submit', createWorkspace);
|
||||
document.getElementById('createForm').addEventListener('submit', createProject);
|
||||
document.getElementById('refreshCaddyBtn').addEventListener('click', loadCaddyConfig);
|
||||
await refreshWorkspaces();
|
||||
await refreshProjects();
|
||||
await loadCaddyConfig();
|
||||
}
|
||||
|
||||
async function refreshWorkspaces() {
|
||||
|
|
@ -52,6 +54,7 @@ function renderProjects() {
|
|||
<p class="meta">workspace: ${escapeHtml(p.workspace)} (${escapeHtml(p.unix_user)})</p>
|
||||
<p class="meta">slug: ${escapeHtml(p.slug)} | service: ${escapeHtml(p.service_name)}</p>
|
||||
<p class="meta">app target: 127.0.0.1:${escapeHtml(p.target_port)} | route host: ${escapeHtml(p.route_host || 'not set')}</p>
|
||||
<p class="meta">app url: ${p.app_url ? `<a class="link" href="${escapeHtml(p.app_url)}" target="_blank" rel="noreferrer">${escapeHtml(p.app_url)}</a>` : 'not set'}</p>
|
||||
<p class="meta">deploy webhook: <code>${escapeHtml(p.webhook_url || 'n/a')}</code></p>
|
||||
<p class="meta">provisioning: ${escapeHtml(p.provision_state || 'unknown')}${p.provision_error ? ` | error: ${escapeHtml(p.provision_error)}` : ''}</p>
|
||||
<p>${escapeHtml(p.description || '')}</p>
|
||||
|
|
@ -194,6 +197,17 @@ async function createWorkspace(e) {
|
|||
}
|
||||
}
|
||||
|
||||
async function loadCaddyConfig() {
|
||||
const out = document.getElementById('caddyConfigOut');
|
||||
out.textContent = 'Loading Caddy config...';
|
||||
try {
|
||||
const cfg = await api('/api/caddy/config');
|
||||
out.textContent = JSON.stringify(cfg, null, 2);
|
||||
} catch (err) {
|
||||
out.textContent = `Error: ${err.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s)
|
||||
.replaceAll('&', '&')
|
||||
|
|
|
|||
|
|
@ -45,6 +45,12 @@
|
|||
<h2>Your Projects</h2>
|
||||
<div id="projects" class="projects"></div>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Caddy Config</h2>
|
||||
<button id="refreshCaddyBtn" type="button">Refresh Caddy Config</button>
|
||||
<pre id="caddyConfigOut" class="meta" style="white-space: pre-wrap; max-height: 320px; overflow: auto;">Not loaded.</pre>
|
||||
</section>
|
||||
</main>
|
||||
<script src="/app.js" defer></script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue