mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-09 16:10:48 +02:00
- Introduced new source and destination forms for Backblaze B2 and Wasabi, allowing users to configure their cloud storage settings. - Updated the configuration generation logic to handle B2 and Wasabi, including necessary parameters such as access keys, bucket names, and endpoints. - Enhanced the user interface to provide clear instructions and security notes for both storage options, improving user experience and security awareness.
472 lines
22 KiB
Templ
472 lines
22 KiB
Templ
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/starfleetcptn/gomft/internal/db"
|
|
)
|
|
|
|
templ NameField() {
|
|
<div class="mb-6">
|
|
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Configuration Name</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-tag text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<input type="text" name="name" id="name" x-model="name" required
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder="Transfer configuration name" />
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">Choose a descriptive name to identify this configuration.</p>
|
|
</div>
|
|
}
|
|
|
|
templ FilePatternFields() {
|
|
<div class="space-y-6">
|
|
<div class="mb-6">
|
|
<label for="file_pattern" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">File Pattern</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-filter text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<input type="text" name="file_pattern" id="file_pattern" x-model="filePattern"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder="*.txt, *.csv" />
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Glob pattern for files to transfer. Leave empty to transfer all files.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mb-6">
|
|
<label for="output_pattern" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Output Pattern</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-file-export text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<input type="text" name="output_pattern" id="output_pattern" x-model="outputPattern"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder="${filename}" />
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Pattern for output filename. Use variables like ${`filename`}, ${`timestamp`}, ${`date`}
|
|
</p>
|
|
|
|
<div class="mt-4 p-4 bg-gray-50 rounded-lg border border-gray-200 dark:bg-gray-800 dark:border-gray-700">
|
|
<h4 class="text-sm font-medium text-gray-900 dark:text-white mb-2">Available variables:</h4>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
|
<span class="block">• ${`filename`} - Original filename without extension (e.g., "report")</span>
|
|
<span class="block">• ${`ext`} - Original file extension (e.g., "csv")</span>
|
|
<span class="block">• ${`date:format`} - Current date using Go's time format:</span>
|
|
<span class="block pl-4">- 2006-01-02 → YYYY-MM-DD</span>
|
|
<span class="block pl-4">- 20060102 → YYYYMMDD</span>
|
|
<span class="block pl-4">- 2006-01-02 15:04:05 → YYYY-MM-DD_HH:MM:SS</span>
|
|
<span class="block italic mt-2">Example: ${`filename`}_${`date:2006-01-02`}_${`ext`} → "report_2023-03-01.csv"</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ ArchiveOptions() {
|
|
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
|
|
<div class="space-y-6">
|
|
<div class="flex items-center">
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" id="archive_enabled" name="archive_enabled" x-model="archiveEnabled"
|
|
class="sr-only peer" :value="archiveEnabled ? 'true' : 'false'">
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
|
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-white">Enable archiving</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div x-show="archiveEnabled" class="mt-4">
|
|
<label for="archive_path" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Archive Path</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-folder text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<input id="archive_path" name="archive_path" type="text" x-model="archivePath"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder="Path to archive files" />
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Files will be moved here after successful transfer
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" id="delete_after_transfer" name="delete_after_transfer" x-model="deleteAfterTransfer"
|
|
class="sr-only peer" :value="deleteAfterTransfer ? 'true' : 'false'">
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-red-300 dark:peer-focus:ring-red-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-red-600"></div>
|
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-white">Delete source files after transfer</span>
|
|
</label>
|
|
</div>
|
|
<div x-show="deleteAfterTransfer" class="mt-2">
|
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-red-900/30 dark:text-red-300" role="alert">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-exclamation-triangle mr-2"></i>
|
|
<span>Warning: This will permanently delete the original files</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" id="skip_processed_files" name="skip_processed_files" x-model="skipProcessedFiles"
|
|
class="sr-only peer" :value="skipProcessedFiles ? 'true' : 'false'">
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
|
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-white">Skip files that have already been processed</span>
|
|
</label>
|
|
</div>
|
|
<p class="ms-14 text-sm text-gray-500 dark:text-gray-400">
|
|
Files with the same hash that have been successfully processed before will be skipped
|
|
</p>
|
|
|
|
<div class="mt-6">
|
|
<label for="max_concurrent_transfers" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
|
Concurrent Transfers: <span x-text="maxConcurrentTransfers"></span>
|
|
</label>
|
|
<input type="range" id="max_concurrent_transfers" name="max_concurrent_transfers"
|
|
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
|
min="1" max="32" step="1" x-model="maxConcurrentTransfers">
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Number of files to transfer simultaneously (higher values may improve performance but increase resource usage)
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ RcloneFlags(currentCommandID uint) {
|
|
<div class="mb-6">
|
|
<label for="command_id" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Rclone Command</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-terminal text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
@RcloneCommandOptions(currentCommandID) // Pass it down
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Select the rclone command to use for this configuration.
|
|
</p>
|
|
|
|
<!-- Flag container is now rendered directly in ConfigForm -->
|
|
|
|
<label for="rclone_flags" class="block mb-2 mt-6 text-sm font-medium text-gray-900 dark:text-white">Additional Rclone Flags</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-flag text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<input type="text" name="rclone_flags" id="rclone_flags" x-model="rcloneFlags"
|
|
@change="updateCommandRequirements()"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder="--transfers 4 --checkers 8" />
|
|
</div>
|
|
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Optional: Additional rclone flags for fine-tuning the transfer.
|
|
</p>
|
|
</div>
|
|
}
|
|
|
|
// New placeholder templ for rclone command options
|
|
templ RcloneCommandOptions(currentCommandID uint) { // Accept currentCommandID
|
|
<div
|
|
hx-get="/api/rclone/commands"
|
|
hx-trigger="load"
|
|
hx-target="this"
|
|
hx-swap="outerHTML"
|
|
hx-vals={ fmt.Sprintf(`{"commandId": %d}`, currentCommandID) }>
|
|
<!-- Loading placeholder -->
|
|
<option value="">Loading commands...</option>
|
|
</div>
|
|
}
|
|
|
|
templ SourceSelection() {
|
|
<div class="mb-6">
|
|
<label for="source_type" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Source Type</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-server text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<select id="source_type" name="source_type" x-model="sourceType"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
|
<option value="local">Local</option>
|
|
<option value="sftp">SFTP</option>
|
|
<option value="ftp">FTP</option>
|
|
<option value="s3">S3</option>
|
|
<option value="b2">Backblaze B2</option>
|
|
<option value="wasabi">Wasabi</option>
|
|
<option value="minio">MinIO</option>
|
|
<option value="smb">SMB</option>
|
|
<option value="nextcloud">NextCloud</option>
|
|
<option value="webdav">WebDAV</option>
|
|
<option value="gdrive">Google Drive (BETA)</option>
|
|
<option value="gphotos">Google Photos (BETA)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ DestinationSelection() {
|
|
<div class="mb-6">
|
|
<label for="destination_type" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Destination Type</label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3.5 pointer-events-none">
|
|
<i class="fas fa-server text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<select id="destination_type" name="destination_type" x-model="destinationType"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
|
<option value="local">Local</option>
|
|
<option value="sftp">SFTP</option>
|
|
<option value="ftp">FTP</option>
|
|
<option value="s3">S3</option>
|
|
<option value="b2">Backblaze B2</option>
|
|
<option value="wasabi">Wasabi</option>
|
|
<option value="minio">MinIO</option>
|
|
<option value="smb">SMB</option>
|
|
<option value="nextcloud">NextCloud</option>
|
|
<option value="webdav">WebDAV</option>
|
|
<option value="gdrive">Google Drive (BETA)</option>
|
|
<option value="gphotos">Google Photos (BETA)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
// RcloneCommandOptionsContent renders the command options organized by category
|
|
templ RcloneCommandOptionsContent(categoryMap map[string][]db.RcloneCommand, categories []string, currentCommandID uint, commandFlagsJSON string, commandFlagValuesJSON string) { // Add flag JSON strings
|
|
<select id="command_id" name="command_id" x-model="commandId"
|
|
hx-get="/api/rclone/command-flags"
|
|
hx-target="#command-flags-container"
|
|
hx-trigger="change"
|
|
hx-include="[name='command_id']"
|
|
hx-vals={ fmt.Sprintf(`{"commandFlags": %s, "commandFlagValues": %s}`, commandFlagsJSON, commandFlagValuesJSON) }
|
|
@change="updateCommandRequirements()"
|
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
|
<option value="">Select command...</option>
|
|
for _, category := range categories {
|
|
if commands, ok := categoryMap[category]; ok && len(commands) > 0 {
|
|
<optgroup label={ category }>
|
|
for _, cmd := range commands {
|
|
if cmd.ID == currentCommandID {
|
|
<option value={ fmt.Sprintf("%d", cmd.ID) } selected>{ cmd.Name } - { cmd.Description }</option>
|
|
} else {
|
|
<option value={ fmt.Sprintf("%d", cmd.ID) }>{ cmd.Name } - { cmd.Description }</option>
|
|
}
|
|
}
|
|
</optgroup>
|
|
}
|
|
}
|
|
</select>
|
|
}
|
|
|
|
// RcloneCommandFlagsContent renders the command flags for a selected command
|
|
templ RcloneCommandFlagsContent(command *db.RcloneCommand, selectedFlagsMap map[uint]bool, selectedFlagValues map[uint]string) {
|
|
if command == nil {
|
|
<div class="p-4 text-red-500">Command not found</div>
|
|
return
|
|
}
|
|
|
|
<div class="mb-4">
|
|
<h4 class="font-medium text-gray-900 dark:text-white mb-2">{ command.Name }</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">{ command.Description }</p>
|
|
|
|
if len(command.Flags) > 0 {
|
|
<div class="mb-3">
|
|
<h5 class="font-medium text-gray-900 dark:text-white mb-2">Command Flags:</h5>
|
|
<div class="space-y-3">
|
|
for _, flag := range command.Flags {
|
|
if flag.DataType == "bool" {
|
|
<!-- Boolean flag (simple checkbox) -->
|
|
<div class="flex items-start mb-4">
|
|
<input
|
|
type="checkbox"
|
|
id={ fmt.Sprintf("flag_%d", flag.ID) }
|
|
name="command_flags"
|
|
value={ fmt.Sprintf("%d", flag.ID) }
|
|
class="mt-0.5 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:focus:ring-blue-600"
|
|
if selectedFlagsMap[flag.ID] {
|
|
checked
|
|
} />
|
|
<div class="ml-3">
|
|
<label for={ fmt.Sprintf("flag_%d", flag.ID) } class="font-medium text-gray-900 dark:text-white">
|
|
{ flag.Name } - { flag.Description }
|
|
</label>
|
|
if flag.DefaultValue != "" {
|
|
<p class="text-xs text-gray-500 dark:text-gray-400">Default: { flag.DefaultValue }</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
} else {
|
|
<!-- Non-boolean flag (requires value) -->
|
|
<div class="flex items-start mb-4 w-full">
|
|
<div class="w-full">
|
|
<div class="flex items-center mb-2">
|
|
<input
|
|
type="checkbox"
|
|
id={ fmt.Sprintf("flag_enable_%d", flag.ID) }
|
|
name={ fmt.Sprintf("flag_enable_%d", flag.ID) }
|
|
class="mr-2 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:focus:ring-blue-600"
|
|
data-input-id={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
onclick="toggleFlagValue(this)"
|
|
if selectedFlagsMap[flag.ID] {
|
|
checked
|
|
} />
|
|
<label for={ fmt.Sprintf("flag_enable_%d", flag.ID) } class="font-medium text-gray-900 dark:text-white">
|
|
{ flag.Name } - { flag.Description }
|
|
</label>
|
|
</div>
|
|
|
|
<div class="w-full mt-2">
|
|
@renderFlagInput(flag, selectedFlagValues[flag.ID], selectedFlagsMap[flag.ID]) // Pass value and enabled status
|
|
if flag.DefaultValue != "" {
|
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Default: { flag.DefaultValue }</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript to handle enabling/disabling flag value inputs -->
|
|
<script>
|
|
function toggleFlagValue(checkbox) {
|
|
const inputId = checkbox.getAttribute('data-input-id');
|
|
const input = document.getElementById(inputId);
|
|
|
|
if (input) {
|
|
input.disabled = !checkbox.checked;
|
|
if (checkbox.checked) {
|
|
// Focus on the input when enabled
|
|
input.focus();
|
|
}
|
|
|
|
// Also enable/disable the hidden input for flag ID
|
|
const hiddenId = inputId.replace('flag_value_', 'flag_hidden_');
|
|
const hiddenInput = document.getElementById(hiddenId);
|
|
if (hiddenInput) {
|
|
hiddenInput.disabled = !checkbox.checked;
|
|
console.log('Toggle hidden input:', hiddenId, checkbox.checked);
|
|
}
|
|
|
|
// For debugging
|
|
console.log('Toggle flag value:', inputId, checkbox.checked);
|
|
}
|
|
}
|
|
|
|
// Initialize all flag inputs on page load
|
|
// Initialization is now handled by server-side rendering
|
|
</script>
|
|
|
|
<div class="mt-4 p-3 bg-blue-50 text-blue-800 rounded-lg border border-blue-100 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-900 text-sm">
|
|
<div class="flex items-center mb-1">
|
|
<i class="fas fa-info-circle mr-2"></i>
|
|
<span class="font-medium">Usage Examples</span>
|
|
</div>
|
|
if command.Name == "ls" ||
|
|
command.Name == "lsd" ||
|
|
command.Name == "lsl" ||
|
|
command.Name == "lsjson" ||
|
|
command.Name == "lsf" ||
|
|
command.Name == "delete" ||
|
|
command.Name == "purge" ||
|
|
command.Name == "rmdirs" ||
|
|
command.Name == "mkdir" ||
|
|
command.Name == "touch" ||
|
|
command.Name == "md5sum" ||
|
|
command.Name == "sha1sum" ||
|
|
command.Name == "sha256sum" ||
|
|
command.Name == "size" ||
|
|
command.Name == "stat" ||
|
|
command.Name == "version" {
|
|
<code class="block mt-1 font-mono text-xs overflow-x-auto">rclone { command.Name } [flags] source:path</code>
|
|
} else {
|
|
<code class="block mt-1 font-mono text-xs overflow-x-auto">rclone { command.Name } [flags] source:path dest:path</code>
|
|
}
|
|
</div>
|
|
} else {
|
|
<div class="p-3 bg-gray-50 text-gray-600 rounded-lg border border-gray-200 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-700 text-sm">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-info-circle mr-2"></i>
|
|
<span>This command doesn't have any specific flags.</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
// Helper function to render appropriate input based on flag data type
|
|
templ renderFlagInput(flag db.RcloneCommandFlag, value string, enabled bool) {
|
|
if flag.DataType == "int" {
|
|
<input
|
|
type="number"
|
|
id={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
name={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
class="w-full bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder={ flag.DefaultValue }
|
|
value={ value }
|
|
if !enabled {
|
|
disabled
|
|
} />
|
|
<!-- Hidden input to include this flag ID when checked -->
|
|
<input
|
|
type="hidden"
|
|
name="command_flags"
|
|
value={ fmt.Sprintf("%d", flag.ID) }
|
|
if !enabled {
|
|
disabled
|
|
}
|
|
id={ fmt.Sprintf("flag_hidden_%d", flag.ID) }
|
|
data-enable-with={ fmt.Sprintf("flag_enable_%d", flag.ID) }
|
|
/>
|
|
} else if flag.DataType == "float" {
|
|
<input
|
|
type="number"
|
|
id={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
name={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
step="0.01"
|
|
class="w-full bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder={ flag.DefaultValue }
|
|
value={ value }
|
|
if !enabled {
|
|
disabled
|
|
} />
|
|
<!-- Hidden input to include this flag ID when checked -->
|
|
<input
|
|
type="hidden"
|
|
name="command_flags"
|
|
value={ fmt.Sprintf("%d", flag.ID) }
|
|
if !enabled {
|
|
disabled
|
|
}
|
|
id={ fmt.Sprintf("flag_hidden_%d", flag.ID) }
|
|
data-enable-with={ fmt.Sprintf("flag_enable_%d", flag.ID) }
|
|
/>
|
|
} else {
|
|
<!-- Default to text input for string and other types -->
|
|
<input
|
|
type="text"
|
|
id={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
name={ fmt.Sprintf("flag_value_%d", flag.ID) }
|
|
class="w-full bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
placeholder={ flag.DefaultValue }
|
|
value={ value }
|
|
if !enabled {
|
|
disabled
|
|
} />
|
|
<!-- Hidden input to include this flag ID when checked -->
|
|
<input
|
|
type="hidden"
|
|
name="command_flags"
|
|
value={ fmt.Sprintf("%d", flag.ID) }
|
|
if !enabled {
|
|
disabled
|
|
}
|
|
id={ fmt.Sprintf("flag_hidden_%d", flag.ID) }
|
|
data-enable-with={ fmt.Sprintf("flag_enable_%d", flag.ID) }
|
|
/>
|
|
}
|
|
} |