Admin UI add maintenance menu (#6944)
* add ui for maintenance * valid config loading. fix workers page. * refactor * grpc between admin and workers * add a long-running bidirectional grpc call between admin and worker * use the grpc call to heartbeat * use the grpc call to communicate * worker can remove the http client * admin uses http port + 10000 as its default grpc port * one task one package * handles connection failures gracefully with exponential backoff * grpc with insecure tls * grpc with optional tls * fix detecting tls * change time config from nano seconds to seconds * add tasks with 3 interfaces * compiles reducing hard coded * remove a couple of tasks * remove hard coded references * reduce hard coded values * remove hard coded values * remove hard coded from templ * refactor maintenance package * fix import cycle * simplify * simplify * auto register * auto register factory * auto register task types * self register types * refactor * simplify * remove one task * register ui * lazy init executor factories * use registered task types * DefaultWorkerConfig remove hard coded task types * remove more hard coded * implement get maintenance task * dynamic task configuration * "System Settings" should only have system level settings * adjust menu for tasks * ensure menu not collapsed * render job configuration well * use templ for ui of task configuration * fix ordering * fix bugs * saving duration in seconds * use value and unit for duration * Delete WORKER_REFACTORING_PLAN.md * Delete maintenance.json * Delete custom_worker_example.go * remove address from workers * remove old code from ec task * remove creating collection button * reconnect with exponential backoff * worker use security.toml * start admin server with tls info from security.toml * fix "weed admin" cli description
This commit is contained in:
160
weed/admin/view/app/task_config.templ
Normal file
160
weed/admin/view/app/task_config.templ
Normal file
@@ -0,0 +1,160 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/admin/maintenance"
|
||||
)
|
||||
|
||||
templ TaskConfig(data *maintenance.TaskConfigData) {
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h2 class="mb-0">
|
||||
<i class={data.TaskIcon + " me-2"}></i>
|
||||
{data.TaskName} Configuration
|
||||
</h2>
|
||||
<div class="btn-group">
|
||||
<a href="/maintenance/config" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-1"></i>
|
||||
Back to Configuration
|
||||
</a>
|
||||
<a href="/maintenance" class="btn btn-outline-primary">
|
||||
<i class="fas fa-list me-1"></i>
|
||||
View Queue
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class={data.TaskIcon + " me-2"}></i>
|
||||
{data.TaskName} Settings
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-4">{data.Description}</p>
|
||||
|
||||
<!-- Task-specific configuration form -->
|
||||
<form method="POST">
|
||||
<div class="task-config-form">
|
||||
@templ.Raw(string(data.ConfigFormHTML))
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save me-1"></i>
|
||||
Save Configuration
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="resetForm()">
|
||||
<i class="fas fa-undo me-1"></i>
|
||||
Reset to Defaults
|
||||
</button>
|
||||
<a href="/maintenance/config" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-times me-1"></i>
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Task Information -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
Task Information
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted">Task Type</h6>
|
||||
<p class="mb-3">
|
||||
<span class="badge bg-secondary">{string(data.TaskType)}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted">Display Name</h6>
|
||||
<p class="mb-3">{data.TaskName}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h6 class="text-muted">Description</h6>
|
||||
<p class="mb-0">{data.Description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function resetForm() {
|
||||
if (confirm('Are you sure you want to reset all settings to their default values?')) {
|
||||
// Find all form inputs and reset them
|
||||
const form = document.querySelector('form');
|
||||
if (form) {
|
||||
form.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-save form data to localStorage for recovery
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.querySelector('form');
|
||||
if (form) {
|
||||
const taskType = '{string(data.TaskType)}';
|
||||
const storageKey = 'taskConfig_' + taskType;
|
||||
|
||||
// Load saved data
|
||||
const savedData = localStorage.getItem(storageKey);
|
||||
if (savedData) {
|
||||
try {
|
||||
const data = JSON.parse(savedData);
|
||||
Object.keys(data).forEach(key => {
|
||||
const input = form.querySelector(`[name="${key}"]`);
|
||||
if (input) {
|
||||
if (input.type === 'checkbox') {
|
||||
input.checked = data[key];
|
||||
} else {
|
||||
input.value = data[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('Failed to load saved configuration:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Save data on input change
|
||||
form.addEventListener('input', function() {
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
for (let [key, value] of formData.entries()) {
|
||||
data[key] = value;
|
||||
}
|
||||
localStorage.setItem(storageKey, JSON.stringify(data));
|
||||
});
|
||||
|
||||
// Clear saved data on successful submit
|
||||
form.addEventListener('submit', function() {
|
||||
localStorage.removeItem(storageKey);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
Reference in New Issue
Block a user