package components import ( "fmt" "github.com/starfleetcptn/gomft/internal/db" "context" "github.com/starfleetcptn/gomft/components/providers/source" "github.com/starfleetcptn/gomft/components/providers/destination" "github.com/starfleetcptn/gomft/components/providers/common" ) type ConfigFormData struct { Config *db.TransferConfig IsNew bool } func getConfigFormTitle(isNew bool) string { if isNew { return "New Configuration" } return "Edit Configuration" } func getInitialData(config *db.TransferConfig) string { // Default values for a new configuration name := "" sourceType := "local" sourcePath := "" sourceHost := "" sourcePort := 22 sourceUser := "" sourcePassword := "" sourceKeyFile := "" sourceAuthType := "password" sourceBucket := "" sourceRegion := "" sourceAccessKey := "" sourceSecretKey := "" sourceEndpoint := "" sourceShare := "" sourceDomain := "" sourcePassiveMode := false sourceClientId := "" sourceClientSecret := "" sourceDriveId := "" sourceTeamDrive := "" // Google Photos source fields sourceReadOnly := false sourceStartYear := 2025 sourceIncludeArchived := false filePattern := "" outputPattern := "${filename}" destinationType := "local" destinationPath := "" destHost := "" destPort := 22 destUser := "" destPassword := "" destKeyFile := "" destAuthType := "password" destBucket := "" destRegion := "" destAccessKey := "" destSecretKey := "" destEndpoint := "" destShare := "" destDomain := "" destPassiveMode := false destClientId := "" destClientSecret := "" destDriveId := "" destTeamDrive := "" // Google Photos destination fields destReadOnly := false destStartYear := 2025 destIncludeArchived := false archivePath := "" archiveEnabled := false deleteAfterTransfer := false skipProcessedFiles := true maxConcurrentTransfers := 4 rcloneFlags := "" useBuiltinAuthSource := true useBuiltinAuthDest := true // If editing an existing config, populate with those values if config != nil { name = config.Name sourceType = config.SourceType sourcePath = config.SourcePath sourceHost = config.SourceHost sourcePort = config.SourcePort sourceUser = config.SourceUser sourcePassword = config.SourcePassword sourceKeyFile = config.SourceKeyFile if sourceKeyFile != "" && sourcePassword == "" { sourceAuthType = "key" } sourceBucket = config.SourceBucket sourceRegion = config.SourceRegion sourceAccessKey = config.SourceAccessKey sourceSecretKey = config.SourceSecretKey sourceEndpoint = config.SourceEndpoint sourceShare = config.SourceShare sourceDomain = config.SourceDomain sourcePassiveMode = config.GetSourcePassiveMode() sourceClientId = config.SourceClientID sourceClientSecret = config.SourceClientSecret sourceDriveId = config.SourceDriveID sourceTeamDrive = config.SourceTeamDrive // Google Photos source fields if config.SourceReadOnly != nil { sourceReadOnly = *config.SourceReadOnly } // sourceStartYear = config.SourceStartYear if config.SourceIncludeArchived != nil { sourceIncludeArchived = *config.SourceIncludeArchived } filePattern = config.FilePattern outputPattern = config.OutputPattern destinationType = config.DestinationType destinationPath = config.DestinationPath destHost = config.DestHost destPort = config.DestPort destUser = config.DestUser destPassword = config.DestPassword destKeyFile = config.DestKeyFile if destKeyFile != "" && destPassword == "" { destAuthType = "key" } destBucket = config.DestBucket destRegion = config.DestRegion destAccessKey = config.DestAccessKey destSecretKey = config.DestSecretKey destEndpoint = config.DestEndpoint destShare = config.DestShare destDomain = config.DestDomain destPassiveMode = config.GetDestPassiveMode() destClientId = config.DestClientID destClientSecret = config.DestClientSecret destDriveId = config.DestDriveID destTeamDrive = config.DestTeamDrive // Google Photos destination fields if config.DestReadOnly != nil { destReadOnly = *config.DestReadOnly } // destStartYear = config.DestStartYear if config.DestIncludeArchived != nil { destIncludeArchived = *config.DestIncludeArchived } archivePath = config.ArchivePath archiveEnabled = config.GetArchiveEnabled() deleteAfterTransfer = config.GetDeleteAfterTransfer() skipProcessedFiles = config.GetSkipProcessedFiles() maxConcurrentTransfers = config.MaxConcurrentTransfers rcloneFlags = config.RcloneFlags if config.UseBuiltinAuthSource != nil { useBuiltinAuthSource = *config.UseBuiltinAuthSource } else if sourceClientId != "" || sourceClientSecret != "" { useBuiltinAuthSource = false } if config.UseBuiltinAuthDest != nil { useBuiltinAuthDest = *config.UseBuiltinAuthDest } else if destClientId != "" || destClientSecret != "" { useBuiltinAuthDest = false } } // Return the JSON-formatted string with all the data, add new path validation states return fmt.Sprintf(`{ name: '%s', sourceType: '%s', sourcePath: '%s', sourceHost: '%s', sourcePort: %d, sourceUser: '%s', sourcePassword: '%s', sourceKeyFile: '%s', sourceAuthType: '%s', sourceBucket: '%s', sourceRegion: '%s', sourceAccessKey: '%s', sourceSecretKey: '%s', sourceEndpoint: '%s', sourceShare: '%s', sourceDomain: '%s', sourcePassiveMode: %v, sourceClientId: '%s', sourceClientSecret: '%s', sourceDriveId: '%s', sourceTeamDrive: '%s', sourceReadOnly: %v, sourceStartYear: %d, sourceIncludeArchived: %v, filePattern: '%s', outputPattern: '%s', destinationType: '%s', destinationPath: '%s', destHost: '%s', destPort: %d, destUser: '%s', destPassword: '%s', destKeyFile: '%s', destAuthType: '%s', destBucket: '%s', destRegion: '%s', destAccessKey: '%s', destSecretKey: '%s', destEndpoint: '%s', destShare: '%s', destDomain: '%s', destPassiveMode: %v, destClientId: '%s', destClientSecret: '%s', destDriveId: '%s', destTeamDrive: '%s', destReadOnly: %v, destStartYear: %d, destIncludeArchived: %v, useBuiltinAuthSource: %v, useBuiltinAuthDest: %v, archivePath: '%s', archiveEnabled: %v, deleteAfterTransfer: %v, 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, sourceClientId, sourceClientSecret, sourceDriveId, sourceTeamDrive, sourceReadOnly, sourceStartYear, sourceIncludeArchived, filePattern, outputPattern, destinationType, destinationPath, destHost, destPort, destUser, destPassword, destKeyFile, destAuthType, destBucket, destRegion, destAccessKey, destSecretKey, destEndpoint, destShare, destDomain, destPassiveMode, destClientId, destClientSecret, destDriveId, destTeamDrive, destReadOnly, destStartYear, destIncludeArchived, useBuiltinAuthSource, useBuiltinAuthDest, archivePath, archiveEnabled, deleteAfterTransfer, skipProcessedFiles, maxConcurrentTransfers, rcloneFlags) } templ ConfigForm(ctx context.Context, data ConfigFormData) { @LayoutWithContext(getConfigFormTitle(data.IsNew), ctx) {

{ getConfigFormTitle(data.IsNew) }

Configure your file transfer settings using the form below

Configuration Details

Give your configuration a descriptive name and set up the source and destination locations.

Choose a descriptive name to identify this configuration.

Source Configuration

@common.SourceSelection()

File Patterns

@common.FilePatternFields()

Destination Configuration

@common.DestinationSelection()

Advanced Options

Archive Settings

@common.ArchiveOptions()

Rclone Configuration

@common.RcloneFlags()
Cancel
Configuration Tips

Configure your file transfer settings carefully for optimal performance. Use file patterns to filter which files are transferred, and consider using archive options to keep track of processed files.

} }