mirror of
https://github.com/chrislusf/seaweedfs
synced 2025-07-26 21:42:48 +02:00
* 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
160 lines
No EOL
6.1 KiB
Text
160 lines
No EOL
6.1 KiB
Text
package app
|
|
|
|
import (
|
|
"github.com/seaweedfs/seaweedfs/weed/admin/maintenance"
|
|
"github.com/seaweedfs/seaweedfs/weed/admin/view/components"
|
|
)
|
|
|
|
// TaskConfigTemplData represents data for templ-based task configuration
|
|
type TaskConfigTemplData struct {
|
|
TaskType maintenance.MaintenanceTaskType
|
|
TaskName string
|
|
TaskIcon string
|
|
Description string
|
|
ConfigSections []components.ConfigSectionData
|
|
}
|
|
|
|
templ TaskConfigTempl(data *TaskConfigTemplData) {
|
|
<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/queue" class="btn btn-outline-info">
|
|
<i class="fas fa-list me-1"></i>
|
|
View Queue
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="alert alert-info" role="alert">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
{data.Description}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="POST" class="needs-validation" novalidate>
|
|
<!-- Render all configuration sections -->
|
|
for _, section := range data.ConfigSections {
|
|
@components.ConfigSection(section)
|
|
}
|
|
|
|
<!-- Form actions -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-1"></i>
|
|
Save Configuration
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary ms-2" onclick="resetForm()">
|
|
<i class="fas fa-undo me-1"></i>
|
|
Reset
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-outline-info" onclick="testConfiguration()">
|
|
<i class="fas fa-play me-1"></i>
|
|
Test Configuration
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
// Form validation
|
|
(function() {
|
|
'use strict';
|
|
window.addEventListener('load', function() {
|
|
var forms = document.getElementsByClassName('needs-validation');
|
|
var validation = Array.prototype.filter.call(forms, function(form) {
|
|
form.addEventListener('submit', function(event) {
|
|
if (form.checkValidity() === false) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
form.classList.add('was-validated');
|
|
}, false);
|
|
});
|
|
}, false);
|
|
})();
|
|
|
|
// Auto-save functionality
|
|
let autoSaveTimeout;
|
|
function autoSave() {
|
|
clearTimeout(autoSaveTimeout);
|
|
autoSaveTimeout = setTimeout(function() {
|
|
const formData = new FormData(document.querySelector('form'));
|
|
localStorage.setItem('task_config_' + '{data.TaskType}', JSON.stringify(Object.fromEntries(formData)));
|
|
}, 1000);
|
|
}
|
|
|
|
// Add auto-save listeners to all form inputs
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.querySelector('form');
|
|
if (form) {
|
|
form.addEventListener('input', autoSave);
|
|
form.addEventListener('change', autoSave);
|
|
}
|
|
});
|
|
|
|
// Reset form function
|
|
function resetForm() {
|
|
if (confirm('Are you sure you want to reset all changes?')) {
|
|
location.reload();
|
|
}
|
|
}
|
|
|
|
// Test configuration function
|
|
function testConfiguration() {
|
|
const formData = new FormData(document.querySelector('form'));
|
|
|
|
// Show loading state
|
|
const testBtn = document.querySelector('button[onclick="testConfiguration()"]');
|
|
const originalContent = testBtn.innerHTML;
|
|
testBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Testing...';
|
|
testBtn.disabled = true;
|
|
|
|
fetch('/maintenance/config/{data.TaskType}/test', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert('Configuration test successful!');
|
|
} else {
|
|
alert('Configuration test failed: ' + data.error);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Test failed: ' + error);
|
|
})
|
|
.finally(() => {
|
|
testBtn.innerHTML = originalContent;
|
|
testBtn.disabled = false;
|
|
});
|
|
}
|
|
</script>
|
|
} |