- Go server with Gin framework - PostgreSQL for metadata storage - MinIO/S3 for artifact storage with SHA256 content addressing - REST API for grove/tree/fruit operations - Web UI for managing artifacts - Docker Compose setup for local development 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
184 lines
7.6 KiB
HTML
184 lines
7.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Orchard - Content Addressable Storage</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body>
|
|
<nav class="navbar">
|
|
<div class="nav-brand">
|
|
<span class="logo">🍎</span> Orchard
|
|
</div>
|
|
<div class="nav-links">
|
|
<a href="#" class="nav-link active" data-view="groves">Groves</a>
|
|
<a href="#" class="nav-link" data-view="upload">Upload</a>
|
|
<a href="#" class="nav-link" data-view="search">Search</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="container">
|
|
<!-- Groves View -->
|
|
<div id="groves-view" class="view active">
|
|
<div class="view-header">
|
|
<h1>Groves</h1>
|
|
<button class="btn btn-primary" onclick="showCreateGroveModal()">+ New Grove</button>
|
|
</div>
|
|
<div id="groves-list" class="card-grid">
|
|
<div class="loading">Loading groves...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Grove Detail View -->
|
|
<div id="grove-detail-view" class="view">
|
|
<div class="view-header">
|
|
<button class="btn btn-secondary" onclick="showView('groves')">← Back</button>
|
|
<h1 id="grove-detail-title">Grove</h1>
|
|
</div>
|
|
<div class="grove-info" id="grove-info"></div>
|
|
<div class="section">
|
|
<div class="section-header">
|
|
<h2>Trees</h2>
|
|
<button class="btn btn-primary" onclick="showCreateTreeModal()">+ New Tree</button>
|
|
</div>
|
|
<div id="trees-list" class="card-grid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tree Detail View -->
|
|
<div id="tree-detail-view" class="view">
|
|
<div class="view-header">
|
|
<button class="btn btn-secondary" onclick="backToGrove()">← Back</button>
|
|
<h1 id="tree-detail-title">Tree</h1>
|
|
</div>
|
|
<div class="tree-info" id="tree-info"></div>
|
|
<div class="section">
|
|
<div class="section-header">
|
|
<h2>Versions (Grafts)</h2>
|
|
</div>
|
|
<div id="grafts-list" class="table-container"></div>
|
|
</div>
|
|
<div class="section">
|
|
<h2>Upload Artifact</h2>
|
|
<form id="tree-upload-form" class="upload-form" onsubmit="uploadToTree(event)">
|
|
<div class="form-group">
|
|
<label>File</label>
|
|
<input type="file" id="tree-upload-file" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Tag (optional)</label>
|
|
<input type="text" id="tree-upload-tag" placeholder="e.g., v1.0.0, latest">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Upload</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload View -->
|
|
<div id="upload-view" class="view">
|
|
<h1>Upload Artifact</h1>
|
|
<form id="upload-form" class="upload-form card" onsubmit="uploadArtifact(event)">
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label>Grove</label>
|
|
<select id="upload-grove" required onchange="loadTreesForUpload()">
|
|
<option value="">Select grove...</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Tree</label>
|
|
<select id="upload-tree" required>
|
|
<option value="">Select tree...</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>File</label>
|
|
<div class="file-drop" id="file-drop">
|
|
<input type="file" id="upload-file" required onchange="updateFileName()">
|
|
<p>Drop file here or click to browse</p>
|
|
<span id="file-name"></span>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Tag (optional)</label>
|
|
<input type="text" id="upload-tag" placeholder="e.g., v1.0.0, latest, stable">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary btn-lg">Upload Artifact</button>
|
|
</form>
|
|
<div id="upload-result" class="result-card hidden"></div>
|
|
</div>
|
|
|
|
<!-- Search View -->
|
|
<div id="search-view" class="view">
|
|
<h1>Search Artifacts</h1>
|
|
<div class="search-box">
|
|
<input type="text" id="search-input" placeholder="Enter fruit ID (SHA256 hash)..." onkeyup="handleSearchKeyup(event)">
|
|
<button class="btn btn-primary" onclick="searchFruit()">Search</button>
|
|
</div>
|
|
<div id="search-result" class="result-card hidden"></div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Create Grove Modal -->
|
|
<div id="create-grove-modal" class="modal hidden">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2>Create New Grove</h2>
|
|
<button class="modal-close" onclick="closeModals()">×</button>
|
|
</div>
|
|
<form onsubmit="createGrove(event)">
|
|
<div class="form-group">
|
|
<label>Name</label>
|
|
<input type="text" id="grove-name" required placeholder="e.g., blinx-core">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Description</label>
|
|
<textarea id="grove-description" placeholder="Optional description..."></textarea>
|
|
</div>
|
|
<div class="form-group checkbox">
|
|
<label>
|
|
<input type="checkbox" id="grove-public" checked>
|
|
Public grove
|
|
</label>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-secondary" onclick="closeModals()">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Create Grove</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create Tree Modal -->
|
|
<div id="create-tree-modal" class="modal hidden">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2>Create New Tree</h2>
|
|
<button class="modal-close" onclick="closeModals()">×</button>
|
|
</div>
|
|
<form onsubmit="createTree(event)">
|
|
<div class="form-group">
|
|
<label>Name</label>
|
|
<input type="text" id="tree-name" required placeholder="e.g., kernel">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Description</label>
|
|
<textarea id="tree-description" placeholder="Optional description..."></textarea>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-secondary" onclick="closeModals()">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Create Tree</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Toast Notifications -->
|
|
<div id="toast-container"></div>
|
|
|
|
<script src="/static/app.js"></script>
|
|
</body>
|
|
</html>
|