From e9f92e66d08ac7001c31a3ee8f43ee8306bc79a9 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 23 Jul 2025 10:11:03 +0200 Subject: [PATCH] feat: add complete translation support for backup admin page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add comprehensive backup translation keys to en.json and de.json - Update all backup components to use i18next translations: - BackupManagement.jsx: main page with tab navigation - BackupDashboard.jsx: health status and statistics - BackupConfiguration.jsx: settings and destination configuration - BackupHistory.jsx: backup history table and details - RestoreWizard.jsx: multi-step restore process - Replace all hardcoded strings with translation keys - Support dynamic values with interpolation - Fix Drone CI/CD github-release step: - Write release.json to /tmp to avoid permission issues - Use quoted heredoc to prevent shell interpretation errors - Replace placeholders with actual tag values using sed 🤖 Generated with Claude Code Co-Authored-By: Claude --- .drone.yml | 21 +- .../components/admin/BackupConfiguration.jsx | 167 ++++----- .../src/components/admin/BackupDashboard.jsx | 62 ++-- .../src/components/admin/BackupHistory.jsx | 56 +-- .../src/components/admin/RestoreWizard.jsx | 188 +++++----- frontend/src/i18n/locales/de.json | 344 ++++++++++++++++++ frontend/src/i18n/locales/en.json | 344 ++++++++++++++++++ frontend/src/pages/admin/BackupManagement.jsx | 44 ++- 8 files changed, 964 insertions(+), 262 deletions(-) diff --git a/.drone.yml b/.drone.yml index a57c2ae..4433235 100644 --- a/.drone.yml +++ b/.drone.yml @@ -118,25 +118,28 @@ steps: from_secret: GITHUB_TOKEN commands: - | - # Create release payload - cat > release.json < /tmp/release.json <<'RELEASE_EOF' { - "tag_name": "${DRONE_TAG}", + "tag_name": "DRONE_TAG_PLACEHOLDER", "target_commitish": "main", - "name": "PicPeak ${DRONE_TAG}", - "body": "# PicPeak ${DRONE_TAG}\n\n## 🐳 Docker Images\n\nThis release includes Docker images published to GitHub Container Registry:\n\n\`\`\`bash\n# Backend\ndocker pull ghcr.io/the-luap/picpeak-backend:${DRONE_TAG}\ndocker pull ghcr.io/the-luap/picpeak-backend:latest\n\n# Frontend\ndocker pull ghcr.io/the-luap/picpeak-frontend:${DRONE_TAG}\ndocker pull ghcr.io/the-luap/picpeak-frontend:latest\n\`\`\`\n\n## 📦 What's New\n\nSee the [README](https://github.com/the-luap/picpeak#readme) for features and documentation.\n\n## 🚀 Quick Start\n\n\`\`\`bash\n# Clone and deploy\ngit clone https://github.com/the-luap/picpeak.git\ncd picpeak\n\n# Use the tagged version\ndocker-compose -f docker-compose.prod.yml up -d\n\`\`\`\n\n---\n\nFor detailed deployment instructions, see the [Deployment Guide](https://github.com/the-luap/picpeak/blob/main/DEPLOYMENT.md).", + "name": "PicPeak DRONE_TAG_PLACEHOLDER", + "body": "# PicPeak DRONE_TAG_PLACEHOLDER\n\n## 🐳 Docker Images\n\nThis release includes Docker images published to GitHub Container Registry:\n\n```bash\n# Backend\ndocker pull ghcr.io/the-luap/picpeak-backend:DRONE_TAG_PLACEHOLDER\ndocker pull ghcr.io/the-luap/picpeak-backend:latest\n\n# Frontend\ndocker pull ghcr.io/the-luap/picpeak-frontend:DRONE_TAG_PLACEHOLDER\ndocker pull ghcr.io/the-luap/picpeak-frontend:latest\n```\n\n## 📦 What's New\n\nSee the [README](https://github.com/the-luap/picpeak#readme) for features and documentation.\n\n## 🚀 Quick Start\n\n```bash\n# Clone and deploy\ngit clone https://github.com/the-luap/picpeak.git\ncd picpeak\n\n# Use the tagged version\ndocker-compose -f docker-compose.prod.yml up -d\n```\n\n---\n\nFor detailed deployment instructions, see the [Deployment Guide](https://github.com/the-luap/picpeak/blob/main/DEPLOYMENT.md).", "draft": false, "prerelease": false } - EOF - - | + RELEASE_EOF + + # Replace placeholders with actual tag + sed -i "s/DRONE_TAG_PLACEHOLDER/${DRONE_TAG}/g" /tmp/release.json + # Create the release on GitHub curl -X POST \ -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/the-luap/picpeak/releases \ - -d @release.json + -d @/tmp/release.json trigger: event: diff --git a/frontend/src/components/admin/BackupConfiguration.jsx b/frontend/src/components/admin/BackupConfiguration.jsx index 165f19a..ca85e63 100644 --- a/frontend/src/components/admin/BackupConfiguration.jsx +++ b/frontend/src/components/admin/BackupConfiguration.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { Save, Server, @@ -23,38 +24,40 @@ import { import { toast } from 'react-toastify'; import { Button, Card, Input } from '../common'; -const destinationTypes = [ - { - id: 'local', - name: 'Local Storage', - icon: HardDrive, - description: 'Store backups on the local server filesystem', - fields: ['backup_destination_path'] - }, - { - id: 'rsync', - name: 'Remote Server (Rsync)', - icon: Server, - description: 'Sync backups to a remote server via SSH/Rsync', - fields: ['backup_rsync_host', 'backup_rsync_user', 'backup_rsync_path', 'backup_rsync_ssh_key'] - }, - { - id: 's3', - name: 'S3 Compatible Storage', - icon: Cloud, - description: 'Store backups in Amazon S3 or compatible object storage', - fields: ['backup_s3_endpoint', 'backup_s3_bucket', 'backup_s3_access_key', 'backup_s3_secret_key', 'backup_s3_region'] - } -]; - -const scheduleOptions = [ - { value: 'hourly', label: 'Every hour' }, - { value: 'daily', label: 'Daily' }, - { value: 'weekly', label: 'Weekly' }, - { value: 'custom', label: 'Custom cron expression' } -]; - export const BackupConfiguration = ({ config, onSave, isSaving }) => { + const { t } = useTranslation(); + + const destinationTypes = [ + { + id: 'local', + name: t('backup.configuration.destinationTypes.local.name'), + icon: HardDrive, + description: t('backup.configuration.destinationTypes.local.description'), + fields: ['backup_destination_path'] + }, + { + id: 'rsync', + name: t('backup.configuration.destinationTypes.rsync.name'), + icon: Server, + description: t('backup.configuration.destinationTypes.rsync.description'), + fields: ['backup_rsync_host', 'backup_rsync_user', 'backup_rsync_path', 'backup_rsync_ssh_key'] + }, + { + id: 's3', + name: t('backup.configuration.destinationTypes.s3.name'), + icon: Cloud, + description: t('backup.configuration.destinationTypes.s3.description'), + fields: ['backup_s3_endpoint', 'backup_s3_bucket', 'backup_s3_access_key', 'backup_s3_secret_key', 'backup_s3_region'] + } + ]; + + const scheduleOptions = [ + { value: 'hourly', label: t('backup.configuration.schedule.options.hourly') }, + { value: 'daily', label: t('backup.configuration.schedule.options.daily') }, + { value: 'weekly', label: t('backup.configuration.schedule.options.weekly') }, + { value: 'custom', label: t('backup.configuration.schedule.options.custom') } + ]; + const [formData, setFormData] = useState({ backup_enabled: false, backup_destination_type: 'local', @@ -121,7 +124,7 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => { } if (missingFields.length > 0) { - toast.error('Please fill in all required fields'); + toast.error(t('backup.configuration.messages.requiredFields')); return; } @@ -133,9 +136,9 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => { try { // TODO: Implement connection test endpoint await new Promise(resolve => setTimeout(resolve, 2000)); - toast.success('Connection test successful!'); + toast.success(t('backup.configuration.messages.connectionSuccess')); } catch (error) { - toast.error('Connection test failed: ' + error.message); + toast.error(t('backup.configuration.messages.connectionFailed') + ': ' + error.message); } finally { setTestingConnection(false); } @@ -149,9 +152,9 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => {
-

Backup Service

+

{t('backup.configuration.enableBackup')}

- Enable automatic backups to protect your data + {t('backup.configuration.enableBackupHelp')}