This commit is contained in:
parent
d744d2a63f
commit
ce8bb92cdb
8 changed files with 139 additions and 11 deletions
|
|
@ -161,11 +161,25 @@
|
|||
.detail-item label { display: block; font-size: .75rem; color: var(--color-text-muted); margin-bottom: .25rem }
|
||||
|
||||
/* Partition Lists */
|
||||
.partition-list { list-style: none; font-family: monospace; font-size: .8125rem }
|
||||
.partition-list { list-style: none }
|
||||
.partition-list li { padding: .25rem 0 }
|
||||
.partition-list a { color: var(--color-brand); text-decoration: none }
|
||||
.partition-list a { text-decoration: none }
|
||||
.partition-list a:hover { text-decoration: underline }
|
||||
|
||||
/* Partition Ref Tags (inline code style) */
|
||||
.partition-ref {
|
||||
display: inline-block;
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace;
|
||||
font-size: .8125rem;
|
||||
background: #f1f5f9;
|
||||
color: #334155;
|
||||
padding: .125rem .375rem;
|
||||
border-radius: .25rem;
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
a.partition-ref { color: var(--color-brand) }
|
||||
a.partition-ref:hover { background: var(--color-brand-light); text-decoration: none }
|
||||
|
||||
/* Forms */
|
||||
.form-section {
|
||||
background: var(--color-surface);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<h2>Building Partitions ({{ job_run.building_partitions.len() }})</h2>
|
||||
<ul class="partition-list">
|
||||
{% for p in job_run.building_partitions %}
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}">{{ p.partition_ref }}</a></li>
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a></li>
|
||||
{% endfor %}
|
||||
{% if job_run.building_partitions.is_empty() %}
|
||||
<li style="color:var(--color-text-muted)">No partitions</li>
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
<div><a href="/wants/{{ sw.want_id }}">{{ sw.want_id }}</a></div>
|
||||
<ul class="partition-list" style="margin-left:1rem">
|
||||
{% for p in sw.partitions %}
|
||||
<li>{{ p.partition_ref }}</li>
|
||||
<li><span class="partition-ref">{{ p.partition_ref }}</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,12 @@
|
|||
{% when None %}<span class="status">Unknown</span>
|
||||
{% endmatch %}
|
||||
</td>
|
||||
<td>{{ jr.building_partitions.len() }}</td>
|
||||
<td>
|
||||
{% for p in jr.building_partitions %}
|
||||
<a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a>{% if !loop.last %} {% endif %}
|
||||
{% endfor %}
|
||||
{% if jr.building_partitions.is_empty() %}<span style="color:var(--color-text-muted)">-</span>{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% match jr.last_heartbeat_at %}
|
||||
{% when Some with (ts) %}{{ ts }}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
{% call base::nav("partitions", base.graph_label) %}
|
||||
|
||||
<div class="detail-header" style="view-transition-name:partition-header">
|
||||
<h1 style="font-family:monospace;font-size:1.25rem">
|
||||
{% if partition.has_partition_ref %}{{ partition.partition_ref }}{% else %}Unknown{% endif %}
|
||||
<h1>
|
||||
{% if partition.has_partition_ref %}<span class="partition-ref" style="font-size:1.125rem">{{ partition.partition_ref }}</span>{% else %}Unknown{% endif %}
|
||||
</h1>
|
||||
{% match partition.status %}
|
||||
{% when Some with (s) %}<span class="status status-{{ s.name_lowercase }}">{{ s.name }}</span>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<tr style="view-transition-name: partition-{{ loop.index }}">
|
||||
<td>
|
||||
{% if p.has_partition_ref %}
|
||||
<a href="/partitions/{{ p.partition_ref_encoded }}">{{ p.partition_ref }}</a>
|
||||
<a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a>
|
||||
{% else %}
|
||||
<span style="color:var(--color-text-muted)">-</span>
|
||||
{% endif %}
|
||||
|
|
|
|||
104
databuild/web/templates/wants/create.html
Normal file
104
databuild/web/templates/wants/create.html
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
{% import "base.html" as base %}
|
||||
|
||||
{% call base::head("Create Want - DataBuild") %}
|
||||
{% call base::nav("wants", base.graph_label) %}
|
||||
|
||||
<h1>Create Want</h1>
|
||||
|
||||
<form id="create-want-form">
|
||||
<div class="form-section">
|
||||
<h2>Partitions</h2>
|
||||
<div class="form-field">
|
||||
<label for="partitions">Partition References</label>
|
||||
<textarea id="partitions" name="partitions" rows="4"
|
||||
placeholder="Enter partition refs, one per line"></textarea>
|
||||
<small>e.g., daily_summaries/category=comedy/date=2024-01-01</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<h2>Settings</h2>
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="data_timestamp">Data Timestamp</label>
|
||||
<input type="datetime-local" id="data_timestamp">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="ttl_seconds">TTL (seconds)</label>
|
||||
<input type="number" id="ttl_seconds" value="3600" min="0">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="sla_seconds">SLA (seconds)</label>
|
||||
<input type="number" id="sla_seconds" value="300" min="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="comment">Comment (optional)</label>
|
||||
<textarea id="comment" name="comment" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="error-message" class="error-message" style="display:none"></div>
|
||||
|
||||
<button type="submit" class="btn-primary">Create Want</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
// Set default data timestamp to now
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
|
||||
document.getElementById('data_timestamp').value = now.toISOString().slice(0, 16);
|
||||
|
||||
document.getElementById('create-want-form').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const partitionsText = document.getElementById('partitions').value;
|
||||
const partitions = partitionsText
|
||||
.split(/[\n,]/)
|
||||
.map(p => p.trim())
|
||||
.filter(p => p.length > 0)
|
||||
.map(ref => ({ ref }));
|
||||
|
||||
if (partitions.length === 0) {
|
||||
document.getElementById('error-message').textContent = 'Please enter at least one partition reference';
|
||||
document.getElementById('error-message').style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
const dataTimestamp = new Date(document.getElementById('data_timestamp').value).getTime();
|
||||
const ttlSeconds = parseInt(document.getElementById('ttl_seconds').value) || 3600;
|
||||
const slaSeconds = parseInt(document.getElementById('sla_seconds').value) || 300;
|
||||
const comment = document.getElementById('comment').value || undefined;
|
||||
|
||||
const payload = {
|
||||
partitions,
|
||||
data_timestamp: dataTimestamp,
|
||||
ttl_seconds: ttlSeconds,
|
||||
sla_seconds: slaSeconds,
|
||||
source: { manually_triggered: { user: "web_ui" } },
|
||||
...(comment && { comment })
|
||||
};
|
||||
|
||||
try {
|
||||
const resp = await fetch('/api/wants', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
window.location.href = '/wants/' + data.data.want_id;
|
||||
} else {
|
||||
const err = await resp.json();
|
||||
document.getElementById('error-message').textContent = err.error || 'Failed to create want';
|
||||
document.getElementById('error-message').style.display = 'block';
|
||||
}
|
||||
} catch (err) {
|
||||
document.getElementById('error-message').textContent = 'Network error: ' + err.message;
|
||||
document.getElementById('error-message').style.display = 'block';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% call base::footer() %}
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
<h2>Requested Partitions ({{ want.partitions.len() }})</h2>
|
||||
<ul class="partition-list">
|
||||
{% for p in want.partitions %}
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}">{{ p.partition_ref }}</a></li>
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a></li>
|
||||
{% endfor %}
|
||||
{% if want.partitions.is_empty() %}
|
||||
<li style="color:var(--color-text-muted)">No partitions</li>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<h2>Upstream Dependencies ({{ want.upstreams.len() }})</h2>
|
||||
<ul class="partition-list">
|
||||
{% for p in want.upstreams %}
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}">{{ p.partition_ref }}</a></li>
|
||||
<li><a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,12 @@
|
|||
{% when None %}<span class="status">Unknown</span>
|
||||
{% endmatch %}
|
||||
</td>
|
||||
<td>{{ want.partitions.len() }}</td>
|
||||
<td>
|
||||
{% for p in want.partitions %}
|
||||
<a href="/partitions/{{ p.partition_ref_encoded }}" class="partition-ref">{{ p.partition_ref }}</a>{% if !loop.last %} {% endif %}
|
||||
{% endfor %}
|
||||
{% if want.partitions.is_empty() %}<span style="color:var(--color-text-muted)">-</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ want.comment_display }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue