mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
feat: Refactor Google Drive and Google Photos authentication handling
- Separate built-in authentication options for source and destination in configuration forms. - Update UI components to reflect changes in authentication handling for Google Drive and Google Photos. - Implement path validation for local directories in the configuration forms, enhancing user experience. - Revise README to clarify supported source and destination types, including updated terminology for Google Drive. - Introduce new API endpoint for path validation, improving error handling and user feedback.
This commit is contained in:
@@ -84,7 +84,8 @@ func getInitialData(config *db.TransferConfig) string {
|
||||
skipProcessedFiles := true
|
||||
maxConcurrentTransfers := 4
|
||||
rcloneFlags := ""
|
||||
useBuiltinAuth := true
|
||||
useBuiltinAuthSource := true
|
||||
useBuiltinAuthDest := true
|
||||
|
||||
// If editing an existing config, populate with those values
|
||||
if config != nil {
|
||||
@@ -162,14 +163,19 @@ func getInitialData(config *db.TransferConfig) string {
|
||||
skipProcessedFiles = config.GetSkipProcessedFiles()
|
||||
maxConcurrentTransfers = config.MaxConcurrentTransfers
|
||||
rcloneFlags = config.RcloneFlags
|
||||
if config.UseBuiltinAuth != nil {
|
||||
useBuiltinAuth = *config.UseBuiltinAuth
|
||||
if config.UseBuiltinAuthSource != nil {
|
||||
useBuiltinAuthSource = *config.UseBuiltinAuthSource
|
||||
} else if sourceClientId != "" || sourceClientSecret != "" {
|
||||
useBuiltinAuthSource = false
|
||||
}
|
||||
if config.UseBuiltinAuthDest != nil {
|
||||
useBuiltinAuthDest = *config.UseBuiltinAuthDest
|
||||
} else if destClientId != "" || destClientSecret != "" {
|
||||
useBuiltinAuth = false
|
||||
useBuiltinAuthDest = false
|
||||
}
|
||||
}
|
||||
|
||||
// Return the JSON-formatted string with all the data
|
||||
// Return the JSON-formatted string with all the data, add new path validation states
|
||||
return fmt.Sprintf(`{
|
||||
name: '%s',
|
||||
sourceType: '%s',
|
||||
@@ -223,7 +229,8 @@ func getInitialData(config *db.TransferConfig) string {
|
||||
destStartYear: %d,
|
||||
destIncludeArchived: %v,
|
||||
|
||||
useBuiltinAuth: %v,
|
||||
useBuiltinAuthSource: %v,
|
||||
useBuiltinAuthDest: %v,
|
||||
|
||||
archivePath: '%s',
|
||||
archiveEnabled: %v,
|
||||
@@ -231,6 +238,32 @@ func getInitialData(config *db.TransferConfig) string {
|
||||
skipProcessedFiles: %v,
|
||||
maxConcurrentTransfers: %d,
|
||||
rcloneFlags: '%s',
|
||||
|
||||
// Path validation states
|
||||
sourcePathValid: null,
|
||||
sourcePathError: '',
|
||||
destPathValid: null,
|
||||
destPathError: '',
|
||||
|
||||
// Methods for path validation
|
||||
checkPath(path, type) {
|
||||
if (!path) {
|
||||
this[type + 'PathValid'] = false;
|
||||
this[type + 'PathError'] = 'Path cannot be empty';
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/check-path?path=' + encodeURIComponent(path))
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this[type + 'PathValid'] = data.valid;
|
||||
this[type + 'PathError'] = data.error || '';
|
||||
})
|
||||
.catch(error => {
|
||||
this[type + 'PathValid'] = false;
|
||||
this[type + 'PathError'] = 'Error checking path: ' + error.message;
|
||||
});
|
||||
}
|
||||
}`,
|
||||
name, sourceType, sourcePath, sourceHost, sourcePort, sourceUser, sourcePassword, sourceKeyFile, sourceAuthType,
|
||||
sourceBucket, sourceRegion, sourceAccessKey, sourceSecretKey, sourceEndpoint, sourceShare, sourceDomain, sourcePassiveMode,
|
||||
@@ -241,7 +274,7 @@ func getInitialData(config *db.TransferConfig) string {
|
||||
destBucket, destRegion, destAccessKey, destSecretKey, destEndpoint, destShare, destDomain, destPassiveMode,
|
||||
destClientId, destClientSecret, destDriveId, destTeamDrive,
|
||||
destReadOnly, destStartYear, destIncludeArchived,
|
||||
useBuiltinAuth,
|
||||
useBuiltinAuthSource, useBuiltinAuthDest,
|
||||
archivePath, archiveEnabled, deleteAfterTransfer, skipProcessedFiles, maxConcurrentTransfers, rcloneFlags)
|
||||
}
|
||||
|
||||
@@ -321,7 +354,7 @@ templ ConfigForm(ctx context.Context, data ConfigFormData) {
|
||||
@source.NextCloudSourceForm()
|
||||
</template>
|
||||
|
||||
<template x-if="sourceType === 'google_drive'">
|
||||
<template x-if="sourceType === 'gdrive'">
|
||||
@source.GoogleDriveSourceForm()
|
||||
</template>
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ templ Configs(ctx context.Context, data ConfigsData) {
|
||||
<!-- Google Drive Authentication Button -->
|
||||
if (config.DestinationType == "gdrive" || config.SourceType == "gdrive" || config.SourceType == "gphotos" || config.DestinationType == "gphotos") && !config.GetGoogleAuthenticated() {
|
||||
<a href={ templ.SafeURL(fmt.Sprintf("/configs/%d/gdrive-auth", config.ID)) } class="btn-warning btn-sm">
|
||||
<i class="fab fa-google-drive mr-1"></i>
|
||||
<i class="fab fa-google mr-1"></i>
|
||||
Authenticate
|
||||
</a>
|
||||
}
|
||||
@@ -356,8 +356,8 @@ templ Configs(ctx context.Context, data ConfigsData) {
|
||||
<!-- Google Drive Auth Help -->
|
||||
<div class="mt-4 text-center">
|
||||
<p class="text-sm text-secondary-500 dark:text-secondary-400">
|
||||
<i class="fab fa-google-drive mr-1 text-blue-500 inline-flex items-center"></i>
|
||||
Google Drive configurations require authentication. Click the "Authenticate" button to complete setup.
|
||||
<i class="fab fa-google mr-1 text-blue-500 inline-flex items-center"></i>
|
||||
Google Drive and Google Photos configurations require authentication. Click the "Authenticate" button to complete setup.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -194,7 +194,7 @@ templ SourceSelection() {
|
||||
<option value="smb">SMB</option>
|
||||
<option value="nextcloud">NextCloud</option>
|
||||
<option value="webdav">WebDAV</option>
|
||||
<option value="google_drive">Google Drive</option>
|
||||
<option value="gdrive">Google Drive</option>
|
||||
<option value="gphotos">Google Photos</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
package destination
|
||||
|
||||
templ GoogleDriveDestinationForm() {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuth', value => {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuthDest', value => {
|
||||
if(value) {
|
||||
destClientId = '';
|
||||
destClientSecret = '';
|
||||
}
|
||||
})">
|
||||
<div class="mb-6">
|
||||
<label for="use_builtin_auth" class="flex items-center cursor-pointer">
|
||||
<label for="use_builtin_auth_dest" class="flex items-center cursor-pointer">
|
||||
<div class="relative">
|
||||
<input id="use_builtin_auth" name="use_builtin_auth" type="checkbox"
|
||||
<input id="use_builtin_auth_dest" name="use_builtin_auth_dest" type="checkbox"
|
||||
class="sr-only"
|
||||
x-model="useBuiltinAuth"
|
||||
x-model="useBuiltinAuthDest"
|
||||
:value="useBuiltinAuthDest ? 'true' : 'false'"
|
||||
/>
|
||||
<div class="block bg-secondary-200 dark:bg-secondary-700 w-14 h-8 rounded-full"></div>
|
||||
<div class="dot absolute left-1 top-1 bg-white dark:bg-secondary-100 w-6 h-6 rounded-full transition"
|
||||
:class="useBuiltinAuth ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
:class="useBuiltinAuthDest ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-secondary-700 dark:text-secondary-300 font-medium">
|
||||
Use rclone's built-in Google authentication (recommended)
|
||||
@@ -27,11 +28,11 @@ templ GoogleDriveDestinationForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuth }">
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuthDest }">
|
||||
<div>
|
||||
<label for="dest_client_id" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client ID
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthDest" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -39,7 +40,7 @@ templ GoogleDriveDestinationForm() {
|
||||
</div>
|
||||
<input type="text" id="dest_client_id" name="dest_client_id" x-model="destClientId"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthDest"
|
||||
placeholder="Google Drive OAuth Client ID" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -50,7 +51,7 @@ templ GoogleDriveDestinationForm() {
|
||||
<div class="mt-4">
|
||||
<label for="dest_client_secret" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client Secret
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthDest" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -58,7 +59,7 @@ templ GoogleDriveDestinationForm() {
|
||||
</div>
|
||||
<input type="password" id="dest_client_secret" name="dest_client_secret" x-model="destClientSecret"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthDest"
|
||||
placeholder="Google Drive OAuth Client Secret" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -140,7 +141,7 @@ templ GoogleDriveDestinationForm() {
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">Authentication Information</h3>
|
||||
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
<template x-if="useBuiltinAuth">
|
||||
<template x-if="useBuiltinAuthDest">
|
||||
<div>
|
||||
<p>You're using rclone's built-in authentication, which simplifies the setup process:</p>
|
||||
<ul class="list-disc list-inside mt-1 space-y-1">
|
||||
@@ -155,7 +156,7 @@ templ GoogleDriveDestinationForm() {
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!useBuiltinAuth">
|
||||
<template x-if="!useBuiltinAuthDest">
|
||||
<div>
|
||||
<p>To use Google Drive with your own credentials:</p>
|
||||
<ol class="list-decimal list-inside mt-1 space-y-1">
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
package destination
|
||||
|
||||
templ GooglePhotosDestinationForm() {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuth', value => {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuthDest', value => {
|
||||
if(value) {
|
||||
destClientId = '';
|
||||
destClientSecret = '';
|
||||
}
|
||||
})">
|
||||
<div class="mb-6">
|
||||
<label for="use_builtin_auth" class="flex items-center cursor-pointer">
|
||||
<label for="use_builtin_auth_dest" class="flex items-center cursor-pointer">
|
||||
<div class="relative">
|
||||
<input id="use_builtin_auth" name="use_builtin_auth" type="checkbox"
|
||||
<input id="use_builtin_auth_dest" name="use_builtin_auth_dest" type="checkbox"
|
||||
class="sr-only"
|
||||
x-model="useBuiltinAuth"
|
||||
x-model="useBuiltinAuthDest"
|
||||
:value="useBuiltinAuthDest ? 'true' : 'false'"
|
||||
/>
|
||||
<div class="block bg-secondary-200 dark:bg-secondary-700 w-14 h-8 rounded-full"></div>
|
||||
<div class="dot absolute left-1 top-1 bg-white dark:bg-secondary-100 w-6 h-6 rounded-full transition"
|
||||
:class="useBuiltinAuth ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
:class="useBuiltinAuthDest ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-secondary-700 dark:text-secondary-300 font-medium">
|
||||
Use rclone's built-in Google authentication (recommended)
|
||||
@@ -27,11 +28,11 @@ templ GooglePhotosDestinationForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuth }">
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuthDest }">
|
||||
<div>
|
||||
<label for="dest_client_id" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client ID
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthDest" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -39,7 +40,7 @@ templ GooglePhotosDestinationForm() {
|
||||
</div>
|
||||
<input type="text" id="dest_client_id" name="dest_client_id" x-model="destClientId"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthDest"
|
||||
placeholder="Google Photos OAuth Client ID" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -50,7 +51,7 @@ templ GooglePhotosDestinationForm() {
|
||||
<div class="mt-4">
|
||||
<label for="dest_client_secret" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client Secret
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthDest" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -58,7 +59,7 @@ templ GooglePhotosDestinationForm() {
|
||||
</div>
|
||||
<input type="password" id="dest_client_secret" name="dest_client_secret" x-model="destClientSecret"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthDest"
|
||||
placeholder="Google Photos OAuth Client Secret" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -130,10 +131,10 @@ templ GooglePhotosDestinationForm() {
|
||||
</div>
|
||||
<input type="text" id="destination_path" name="destination_path" x-model="destinationPath"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
placeholder="Album path (e.g., /album/my-photos)" />
|
||||
placeholder="Album path (e.g., album/my-photos)" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Path within Google Photos where files will be uploaded
|
||||
Path within Google Photos where files will be uploaded.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -165,7 +166,7 @@ templ GooglePhotosDestinationForm() {
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">Authentication Information</h3>
|
||||
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
<template x-if="useBuiltinAuth">
|
||||
<template x-if="useBuiltinAuthDest">
|
||||
<div>
|
||||
<p>You're using rclone's built-in authentication, which simplifies the setup process:</p>
|
||||
<ul class="list-disc list-inside mt-1 space-y-1">
|
||||
@@ -180,7 +181,7 @@ templ GooglePhotosDestinationForm() {
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!useBuiltinAuth">
|
||||
<template x-if="!useBuiltinAuthDest">
|
||||
<div>
|
||||
<p>To use Google Photos with your own credentials:</p>
|
||||
<ol class="list-decimal list-inside mt-1 space-y-1">
|
||||
|
||||
@@ -6,7 +6,7 @@ templ LocalDestinationForm() {
|
||||
<label for="destination_path" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Local Path</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<i class="fas fa-folder text-secondary-400 dark:text-secondary-600"></i>
|
||||
<i class="fas fa-folder-open text-secondary-400 dark:text-secondary-600"></i>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
@@ -14,13 +14,26 @@ templ LocalDestinationForm() {
|
||||
id="destination_path"
|
||||
x-model="destinationPath"
|
||||
required
|
||||
aria-describedby="destination_path_help"
|
||||
:class="{ 'border-red-300 dark:border-red-700': destPathValid === false, 'border-green-300 dark:border-green-700': destPathValid === true }"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
placeholder="/path/to/destination"/>
|
||||
placeholder="Local directory path (e.g., /path/to/destination)"
|
||||
/>
|
||||
</div>
|
||||
<p id="destination_path_help" class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Absolute path to the local directory where files will be saved.
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Full path to the local directory where files will be saved
|
||||
</p>
|
||||
<!-- Path validation message -->
|
||||
<template x-if="destPathValid !== null">
|
||||
<p x-show="destPathError" class="mt-1 text-sm" :class="destPathValid ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'" x-text="destPathError"></p>
|
||||
</template>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-secondary h-10 whitespace-nowrap"
|
||||
@click="checkPath(destinationPath, 'dest')"
|
||||
>
|
||||
<i class="fas fa-check-circle mr-2"></i>
|
||||
Check Location
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package source
|
||||
|
||||
templ GoogleDriveSourceForm() {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuth', value => {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuthSource', value => {
|
||||
if(value) {
|
||||
sourceClientId = '';
|
||||
sourceClientSecret = '';
|
||||
@@ -12,11 +12,12 @@ templ GoogleDriveSourceForm() {
|
||||
<div class="relative">
|
||||
<input id="use_builtin_auth_source" name="use_builtin_auth_source" type="checkbox"
|
||||
class="sr-only"
|
||||
x-model="useBuiltinAuth"
|
||||
x-model="useBuiltinAuthSource"
|
||||
:value="useBuiltinAuthSource ? 'true' : 'false'"
|
||||
/>
|
||||
<div class="block bg-secondary-200 dark:bg-secondary-700 w-14 h-8 rounded-full"></div>
|
||||
<div class="dot absolute left-1 top-1 bg-white dark:bg-secondary-100 w-6 h-6 rounded-full transition"
|
||||
:class="useBuiltinAuth ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
:class="useBuiltinAuthSource ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-secondary-700 dark:text-secondary-300 font-medium">
|
||||
Use rclone's built-in Google authentication (recommended)
|
||||
@@ -27,11 +28,11 @@ templ GoogleDriveSourceForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuth }">
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuthSource }">
|
||||
<div>
|
||||
<label for="source_client_id" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client ID
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthSource" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -39,7 +40,7 @@ templ GoogleDriveSourceForm() {
|
||||
</div>
|
||||
<input type="text" id="source_client_id" name="source_client_id" x-model="sourceClientId"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthSource"
|
||||
placeholder="Google Drive OAuth Client ID" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -50,7 +51,7 @@ templ GoogleDriveSourceForm() {
|
||||
<div class="mt-4">
|
||||
<label for="source_client_secret" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client Secret
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthSource" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -58,7 +59,7 @@ templ GoogleDriveSourceForm() {
|
||||
</div>
|
||||
<input type="password" id="source_client_secret" name="source_client_secret" x-model="sourceClientSecret"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthSource"
|
||||
placeholder="Google Drive OAuth Client Secret" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -140,7 +141,7 @@ templ GoogleDriveSourceForm() {
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">Authentication Information</h3>
|
||||
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
<template x-if="useBuiltinAuth">
|
||||
<template x-if="useBuiltinAuthSource">
|
||||
<div>
|
||||
<p>You're using rclone's built-in authentication, which simplifies the setup process:</p>
|
||||
<ul class="list-disc list-inside mt-1 space-y-1">
|
||||
@@ -155,7 +156,7 @@ templ GoogleDriveSourceForm() {
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!useBuiltinAuth">
|
||||
<template x-if="!useBuiltinAuthSource">
|
||||
<div>
|
||||
<p>To use Google Drive with your own credentials:</p>
|
||||
<ol class="list-decimal list-inside mt-1 space-y-1">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package source
|
||||
|
||||
templ GooglePhotosSourceForm() {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuth', value => {
|
||||
<div class="space-y-6" x-init="$watch('useBuiltinAuthSource', value => {
|
||||
if(value) {
|
||||
sourceClientId = '';
|
||||
sourceClientSecret = '';
|
||||
@@ -12,11 +12,12 @@ templ GooglePhotosSourceForm() {
|
||||
<div class="relative">
|
||||
<input id="use_builtin_auth_source" name="use_builtin_auth_source" type="checkbox"
|
||||
class="sr-only"
|
||||
x-model="useBuiltinAuth"
|
||||
x-model="useBuiltinAuthSource"
|
||||
:value="useBuiltinAuthSource ? 'true' : 'false'"
|
||||
/>
|
||||
<div class="block bg-secondary-200 dark:bg-secondary-700 w-14 h-8 rounded-full"></div>
|
||||
<div class="dot absolute left-1 top-1 bg-white dark:bg-secondary-100 w-6 h-6 rounded-full transition"
|
||||
:class="useBuiltinAuth ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
:class="useBuiltinAuthSource ? 'transform translate-x-6 bg-primary-500' : ''"></div>
|
||||
</div>
|
||||
<div class="ml-3 text-secondary-700 dark:text-secondary-300 font-medium">
|
||||
Use rclone's built-in Google authentication (recommended)
|
||||
@@ -27,11 +28,11 @@ templ GooglePhotosSourceForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuth }">
|
||||
<div x-bind:class="{ 'opacity-50': useBuiltinAuthSource }">
|
||||
<div>
|
||||
<label for="source_client_id" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client ID
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthSource" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -39,7 +40,7 @@ templ GooglePhotosSourceForm() {
|
||||
</div>
|
||||
<input type="text" id="source_client_id" name="source_client_id" x-model="sourceClientId"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthSource"
|
||||
placeholder="Google Photos OAuth Client ID" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -50,7 +51,7 @@ templ GooglePhotosSourceForm() {
|
||||
<div class="mt-4">
|
||||
<label for="source_client_secret" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">
|
||||
Google Client Secret
|
||||
<span x-show="useBuiltinAuth" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
<span x-show="useBuiltinAuthSource" class="text-secondary-400 dark:text-secondary-600 text-xs font-normal">(Using rclone default)</span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
@@ -58,7 +59,7 @@ templ GooglePhotosSourceForm() {
|
||||
</div>
|
||||
<input type="password" id="source_client_secret" name="source_client_secret" x-model="sourceClientSecret"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
x-bind:disabled="useBuiltinAuth"
|
||||
x-bind:disabled="useBuiltinAuthSource"
|
||||
placeholder="Google Photos OAuth Client Secret" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
@@ -130,7 +131,7 @@ templ GooglePhotosSourceForm() {
|
||||
</div>
|
||||
<input type="text" id="source_path" name="source_path" x-model="sourcePath"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
placeholder="Album path (e.g., /album/my-photos)" />
|
||||
placeholder="Album path (e.g., album/my-photos)" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Path within Google Photos to download files from
|
||||
@@ -165,7 +166,7 @@ templ GooglePhotosSourceForm() {
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">Authentication Information</h3>
|
||||
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
<template x-if="useBuiltinAuth">
|
||||
<template x-if="useBuiltinAuthSource">
|
||||
<div>
|
||||
<p>You're using rclone's built-in authentication, which simplifies the setup process:</p>
|
||||
<ul class="list-disc list-inside mt-1 space-y-1">
|
||||
@@ -180,7 +181,7 @@ templ GooglePhotosSourceForm() {
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!useBuiltinAuth">
|
||||
<template x-if="!useBuiltinAuthSource">
|
||||
<div>
|
||||
<p>To use Google Photos with your own credentials:</p>
|
||||
<ol class="list-decimal list-inside mt-1 space-y-1">
|
||||
|
||||
@@ -6,7 +6,7 @@ templ LocalSourceForm() {
|
||||
<label for="source_path" class="block text-sm font-medium text-secondary-700 dark:text-secondary-300 mb-1">Local Path</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<i class="fas fa-folder text-secondary-400 dark:text-secondary-600"></i>
|
||||
<i class="fas fa-folder-open text-secondary-400 dark:text-secondary-600"></i>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
@@ -14,13 +14,26 @@ templ LocalSourceForm() {
|
||||
id="source_path"
|
||||
x-model="sourcePath"
|
||||
required
|
||||
aria-describedby="source_path_help"
|
||||
:class="{ 'border-red-300 dark:border-red-700': sourcePathValid === false, 'border-green-300 dark:border-green-700': sourcePathValid === true }"
|
||||
class="form-input pl-10 w-full rounded-lg border-secondary-300 dark:border-secondary-700 dark:bg-secondary-800 dark:text-secondary-100 focus:ring-primary-500 focus:border-primary-500"
|
||||
placeholder="/path/to/source"/>
|
||||
placeholder="Local directory path (e.g., /path/to/files)"
|
||||
/>
|
||||
</div>
|
||||
<p id="source_path_help" class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Absolute path to the local directory containing the files to transfer.
|
||||
<p class="mt-1 text-xs text-secondary-500 dark:text-secondary-400">
|
||||
Full path to the local directory containing your files
|
||||
</p>
|
||||
<!-- Path validation message -->
|
||||
<template x-if="sourcePathValid !== null">
|
||||
<p x-show="sourcePathError" class="mt-1 text-sm" :class="sourcePathValid ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'" x-text="sourcePathError"></p>
|
||||
</template>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-secondary h-10 whitespace-nowrap"
|
||||
@click="checkPath(sourcePath, 'source')"
|
||||
>
|
||||
<i class="fas fa-check-circle mr-2"></i>
|
||||
Check Location
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user