diff --git a/components/admin_tools.templ b/components/admin_tools.templ index 7a51949..dae3fee 100644 --- a/components/admin_tools.templ +++ b/components/admin_tools.templ @@ -85,7 +85,8 @@ script hideDialog(id string) { } script submitFormAndHideDialog(formId string, dialogId string) { - document.getElementById(formId).submit(); + // Use HTMX's API to trigger the request instead of bypassing it + htmx.trigger(document.getElementById(formId), 'submit'); document.getElementById(dialogId).classList.add("hidden"); } diff --git a/components/config_form.templ b/components/config_form.templ index ae4f575..d392ba8 100644 --- a/components/config_form.templ +++ b/components/config_form.templ @@ -75,6 +75,7 @@ func getInitialData(config *db.TransferConfig) string { skipProcessedFiles := true maxConcurrentTransfers := 4 rcloneFlags := "" + useBuiltinAuth := true // If editing an existing config, populate with those values if config != nil { @@ -96,7 +97,7 @@ func getInitialData(config *db.TransferConfig) string { sourceEndpoint = config.SourceEndpoint sourceShare = config.SourceShare sourceDomain = config.SourceDomain - sourcePassiveMode = config.SourcePassiveMode + sourcePassiveMode = config.GetSourcePassiveMode() sourceClientId = config.SourceClientID sourceClientSecret = config.SourceClientSecret sourceDriveId = config.SourceDriveID @@ -122,18 +123,21 @@ func getInitialData(config *db.TransferConfig) string { destEndpoint = config.DestEndpoint destShare = config.DestShare destDomain = config.DestDomain - destPassiveMode = config.DestPassiveMode + destPassiveMode = config.GetDestPassiveMode() destClientId = config.DestClientID destClientSecret = config.DestClientSecret destDriveId = config.DestDriveID destTeamDrive = config.DestTeamDrive archivePath = config.ArchivePath - archiveEnabled = config.ArchiveEnabled - deleteAfterTransfer = config.DeleteAfterTransfer + archiveEnabled = config.GetArchiveEnabled() + deleteAfterTransfer = config.GetDeleteAfterTransfer() skipProcessedFiles = config.GetSkipProcessedFiles() maxConcurrentTransfers = config.MaxConcurrentTransfers rcloneFlags = config.RcloneFlags + if destClientId != "" || destClientSecret != "" { + useBuiltinAuth = false + } } // Return the JSON-formatted string with all the data @@ -183,6 +187,7 @@ func getInitialData(config *db.TransferConfig) string { destClientSecret: '%s', destDriveId: '%s', destTeamDrive: '%s', + useBuiltinAuth: %v, archivePath: '%s', archiveEnabled: %v, @@ -198,6 +203,7 @@ func getInitialData(config *db.TransferConfig) string { destinationType, destinationPath, destHost, destPort, destUser, destPassword, destKeyFile, destAuthType, destBucket, destRegion, destAccessKey, destSecretKey, destEndpoint, destShare, destDomain, destPassiveMode, destClientId, destClientSecret, destDriveId, destTeamDrive, + useBuiltinAuth, archivePath, archiveEnabled, deleteAfterTransfer, skipProcessedFiles, maxConcurrentTransfers, rcloneFlags) } @@ -277,6 +283,9 @@ templ ConfigForm(ctx context.Context, data ConfigFormData) { @source.NextCloudSourceForm() + + @source.GoogleDriveSourceForm() + @common.FilePatternFields() @@ -316,6 +325,10 @@ templ ConfigForm(ctx context.Context, data ConfigFormData) { @destination.WebDAVDestinationForm() + + + @destination.GoogleDriveDestinationForm() + diff --git a/components/configs.templ b/components/configs.templ index f685849..a15ded9 100644 --- a/components/configs.templ +++ b/components/configs.templ @@ -68,6 +68,9 @@ script triggerConfigDelete(dialogId string, configID uint, configName string) { type ConfigsData struct { Configs []db.TransferConfig + Error string + ErrorDetails string + Status string } templ Configs(ctx context.Context, data ConfigsData) { @@ -106,6 +109,27 @@ templ Configs(ctx context.Context, data ConfigsData) { console.log("Notyf initialized:", window.notyf); } + // Show status messages based on URL parameters + document.addEventListener('DOMContentLoaded', function() { + // Check for error message + const urlParams = new URLSearchParams(window.location.search); + const errorMsg = urlParams.get('error'); + const errorDetails = urlParams.get('details'); + const status = urlParams.get('status'); + + if (errorMsg) { + let message = errorMsg; + if (errorDetails) { + message += ": " + errorDetails; + } + window.notyf.error(message); + } + + if (status === 'gdrive_auth_success') { + window.notyf.success("Google Drive authentication completed successfully"); + } + }); + // Track all HTMX events for debugging document.addEventListener('htmx:beforeRequest', function(event) { @@ -244,8 +268,32 @@ templ Configs(ctx context.Context, data ConfigsData) {
{ config.Name }
+ + Google Drive configurations require authentication. Click the "Authenticate" button to complete setup. +
- - Disabled jobs will not run automatically. +
+ Jobs that are not enabled will not run automatically on schedule.
+ Simple one-click authentication using rclone's shared credentials +
+ Client ID from Google Cloud Console +
+ Client Secret from Google Cloud Console +
+ Folder ID to use as the root (leave empty for "My Drive") +
+ ID of the Shared Drive / Team Drive to use +
+ Path within the Drive where files will be uploaded +
After saving this configuration, you will need to authenticate with Google Drive.
The authentication process will require you to:
+ This is a one-time process for each configuration. The application will store your authorization token securely. +
You're using rclone's built-in authentication, which simplifies the setup process:
+ + Note: The built-in authentication uses shared credentials which have rate limits across all rclone users. + If you plan to transfer large amounts of data or run many concurrent transfers, consider creating your own credentials. +
To use Google Drive with your own credentials:
http://localhost:53682/
+ Path within the Drive from which files will be transferred +
After saving this configuration, you'll need to authenticate with Google Drive on the configurations page.