Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 250fb93021 | |||
| c0bb2aa5d1 | |||
| 8b0c1655a1 | |||
| ff950244d5 | |||
| cd3d6fc704 | |||
| c536fe45ff | |||
| 42c8ef1c0e | |||
| d07d742528 | |||
| dbc9f0a605 | |||
| 3eb8550cbf | |||
| bebc045029 |
+40
-27
@@ -110,36 +110,49 @@ steps:
|
||||
|
||||
# -------- NEW: Create GitHub Release --------
|
||||
- name: github-release
|
||||
image: curlimages/curl:latest
|
||||
image: plugins/github-release
|
||||
when:
|
||||
event: tag
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: GITHUB_TOKEN
|
||||
commands:
|
||||
- |
|
||||
# Create release payload in /tmp to avoid permission issues
|
||||
cat > /tmp/release.json <<'RELEASE_EOF'
|
||||
{
|
||||
"tag_name": "DRONE_TAG_PLACEHOLDER",
|
||||
"target_commitish": "main",
|
||||
"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
|
||||
}
|
||||
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 "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/the-luap/picpeak/releases \
|
||||
-d @/tmp/release.json
|
||||
files: []
|
||||
title: PicPeak ${DRONE_TAG}
|
||||
note: |
|
||||
# PicPeak ${DRONE_TAG}
|
||||
|
||||
## 🐳 Docker Images
|
||||
|
||||
This release includes Docker images published to GitHub Container Registry:
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
docker pull ghcr.io/the-luap/picpeak-backend:${DRONE_TAG}
|
||||
docker pull ghcr.io/the-luap/picpeak-backend:latest
|
||||
|
||||
# Frontend
|
||||
docker pull ghcr.io/the-luap/picpeak-frontend:${DRONE_TAG}
|
||||
docker pull ghcr.io/the-luap/picpeak-frontend:latest
|
||||
```
|
||||
|
||||
## 📦 What's New
|
||||
|
||||
See the [README](https://github.com/the-luap/picpeak#readme) for features and documentation.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
```bash
|
||||
# Clone and deploy
|
||||
git clone https://github.com/the-luap/picpeak.git
|
||||
cd picpeak
|
||||
|
||||
# Use the tagged version
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
For detailed deployment instructions, see the [Deployment Guide](https://github.com/the-luap/picpeak/blob/main/DEPLOYMENT.md).
|
||||
|
||||
trigger:
|
||||
event:
|
||||
|
||||
@@ -94,6 +94,20 @@ Perfect for:
|
||||
- **Email**: SMTP with customizable templates
|
||||
- **Analytics**: Privacy-focused with Umami integration
|
||||
|
||||
## 💻 System Requirements
|
||||
|
||||
### Minimum Requirements
|
||||
- **CPU**: 2 CPU cores
|
||||
- **RAM**: 2GB minimum
|
||||
- **Storage**: 20GB minimum (plus photo storage needs)
|
||||
- **OS**: Linux (Ubuntu 20.04+), macOS, or Windows with WSL2
|
||||
- **Node.js**: v18.0.0 or higher
|
||||
- **Database**: SQLite (included) or PostgreSQL 12+
|
||||
|
||||
### Docker Requirements (Recommended)
|
||||
- **Docker**: v20.10.0+
|
||||
- **Docker Compose**: v2.0.0+
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We love contributions! PicPeak is built by photographers, for photographers. Whether you're fixing bugs, adding features, or improving documentation, your help is welcome.
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"version": "1.0.85",
|
||||
"version": "1.0.89",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "picpeak-frontend",
|
||||
"version": "1.0.85",
|
||||
"version": "1.0.89",
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"@tiptap/extension-character-count": "^2.26.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"private": true,
|
||||
"version": "1.0.85",
|
||||
"version": "1.0.89",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Info,
|
||||
Eye,
|
||||
EyeOff,
|
||||
TestTube,
|
||||
Wifi,
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
Loader2,
|
||||
@@ -386,7 +386,7 @@ export const BackupConfiguration = ({ config, onSave, isSaving }) => {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TestTube className="mr-2 h-4 w-4" />
|
||||
<Wifi className="mr-2 h-4 w-4" />
|
||||
{t('backup.actions.testConnection')}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -183,7 +183,7 @@ export const BackupDashboard = ({ status, config, onRunBackup, isBackupRunning }
|
||||
label={t('backup.dashboard.stats.backupSize')}
|
||||
value={formatBytes(statistics.total_size || 0)}
|
||||
color="green"
|
||||
subtext={`${statistics.files_processed || 0} files`}
|
||||
subtext={`${statistics.files_processed || 0} ${t('backup.dashboard.stats.files')}`}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
@@ -294,7 +294,7 @@ export const BackupDashboard = ({ status, config, onRunBackup, isBackupRunning }
|
||||
<div>
|
||||
<p className="font-medium text-gray-900">
|
||||
{config?.backup_destination_type
|
||||
? config.backup_destination_type.toUpperCase()
|
||||
? t(`backup.configuration.destinationTypes.${config.backup_destination_type}.name`)
|
||||
: t('backup.dashboard.notConfigured.title')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Download,
|
||||
Eye,
|
||||
@@ -41,6 +42,7 @@ const formatBytes = (bytes) => {
|
||||
};
|
||||
|
||||
export const BackupHistory = () => {
|
||||
const { t } = useTranslation();
|
||||
const [expandedRows, setExpandedRows] = useState(new Set());
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [filterStatus, setFilterStatus] = useState('all');
|
||||
|
||||
@@ -187,8 +187,8 @@ export const RestoreWizard = () => {
|
||||
const renderSourceSelection = () => (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Select Backup Source</h3>
|
||||
<p className="text-sm text-gray-600">Choose where to restore the backup from</p>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">{t('backup.restore.source.title')}</h3>
|
||||
<p className="text-sm text-gray-600">{t('backup.restore.source.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
@@ -203,8 +203,8 @@ export const RestoreWizard = () => {
|
||||
<HardDrive className={`h-12 w-12 mb-3 mx-auto ${
|
||||
restoreData.source === 'local' ? 'text-primary' : 'text-gray-400'
|
||||
}`} />
|
||||
<h4 className="font-medium text-gray-900">Local Backup</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">Restore from local filesystem</p>
|
||||
<h4 className="font-medium text-gray-900">{t('backup.restore.source.local.name')}</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.local.description')}</p>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -218,8 +218,8 @@ export const RestoreWizard = () => {
|
||||
<Cloud className={`h-12 w-12 mb-3 mx-auto ${
|
||||
restoreData.source === 's3' ? 'text-primary' : 'text-gray-400'
|
||||
}`} />
|
||||
<h4 className="font-medium text-gray-900">S3 Storage</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">Restore from S3 bucket</p>
|
||||
<h4 className="font-medium text-gray-900">{t('backup.restore.source.s3.name')}</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.s3.description')}</p>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -233,8 +233,8 @@ export const RestoreWizard = () => {
|
||||
<Upload className={`h-12 w-12 mb-3 mx-auto ${
|
||||
restoreData.source === 'upload' ? 'text-primary' : 'text-gray-400'
|
||||
}`} />
|
||||
<h4 className="font-medium text-gray-900">Upload Backup</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">Upload a backup file</p>
|
||||
<h4 className="font-medium text-gray-900">{t('backup.restore.source.upload.name')}</h4>
|
||||
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.upload.description')}</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -22,7 +22,14 @@ export const useLocalizedDate = () => {
|
||||
const format = (date: Date | string, formatStr?: string) => {
|
||||
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||||
// Use admin-configured date format if available and no format string provided
|
||||
const dateFormat = formatStr || settings?.general_date_format || 'PPP';
|
||||
let dateFormat = formatStr;
|
||||
if (!dateFormat && settings?.general_date_format) {
|
||||
// Handle both string and object formats
|
||||
dateFormat = typeof settings.general_date_format === 'string'
|
||||
? settings.general_date_format
|
||||
: settings.general_date_format.format || 'PPP';
|
||||
}
|
||||
dateFormat = dateFormat || 'PPP';
|
||||
return dateFnsFormat(dateObj, dateFormat, { locale: getLocale() });
|
||||
};
|
||||
|
||||
@@ -35,6 +42,10 @@ export const useLocalizedDate = () => {
|
||||
format,
|
||||
formatDistanceToNow,
|
||||
locale: getLocale(),
|
||||
dateFormat: settings?.general_date_format || 'PPP'
|
||||
dateFormat: settings?.general_date_format
|
||||
? (typeof settings.general_date_format === 'string'
|
||||
? settings.general_date_format
|
||||
: settings.general_date_format.format || 'PPP')
|
||||
: 'PPP'
|
||||
};
|
||||
};
|
||||
@@ -959,8 +959,9 @@
|
||||
"active": "Aktiv",
|
||||
"inactive": "Inaktiv"
|
||||
},
|
||||
"recentActivity": "Letzte Backup-Aktivitäten",
|
||||
"backupCoverage": "Backup-Abdeckung",
|
||||
"recentActivity": {
|
||||
"title": "Letzte Backup-Aktivitäten"
|
||||
},
|
||||
"notConfigured": {
|
||||
"title": "Backup nicht konfiguriert",
|
||||
"message": "Bitte konfigurieren Sie die Backup-Einstellungen im Konfiguration-Tab, bevor Sie Backups ausführen."
|
||||
@@ -977,7 +978,7 @@
|
||||
"storageDestination": "Speicherziel",
|
||||
"nextScheduledBackup": "Nächstes geplantes Backup",
|
||||
"backupType": "{{type}} Backup",
|
||||
"noBackupsYet": "Noch keine Backups"
|
||||
"noDestinationSet": "Kein Ziel festgelegt"
|
||||
},
|
||||
"configuration": {
|
||||
"enableBackup": "Automatisierte Backups aktivieren",
|
||||
@@ -999,24 +1000,34 @@
|
||||
"fields": {
|
||||
"destinationPath": "Zielpfad",
|
||||
"destinationPathHelp": "Lokaler Verzeichnispfad für Backup-Speicherung",
|
||||
"destinationPathPlaceholder": "/pfad/zum/backup/verzeichnis",
|
||||
"rsyncHost": "Remote-Host",
|
||||
"rsyncHostHelp": "SSH-Hostname oder IP-Adresse",
|
||||
"rsyncHostPlaceholder": "backup.beispiel.de",
|
||||
"rsyncUser": "SSH-Benutzer",
|
||||
"rsyncUserHelp": "Benutzername für SSH-Verbindung",
|
||||
"rsyncUserPlaceholder": "backup-benutzer",
|
||||
"rsyncPath": "Remote-Pfad",
|
||||
"rsyncPathHelp": "Verzeichnispfad auf Remote-Server",
|
||||
"rsyncPathPlaceholder": "/home/backup/foto-sharing",
|
||||
"rsyncSshKey": "SSH Private Key",
|
||||
"rsyncSshKeyHelp": "SSH Private Key für Authentifizierung (optional)",
|
||||
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
|
||||
"s3Endpoint": "S3-Endpunkt",
|
||||
"s3EndpointHelp": "S3 API-Endpunkt (z.B. s3.amazonaws.com)",
|
||||
"s3EndpointPlaceholder": "https://s3.amazonaws.com",
|
||||
"s3Bucket": "Bucket-Name",
|
||||
"s3BucketHelp": "S3-Bucket für Backup-Speicherung",
|
||||
"s3BucketPlaceholder": "mein-backup-bucket",
|
||||
"s3AccessKey": "Zugriffsschlüssel-ID",
|
||||
"s3AccessKeyHelp": "AWS/S3 Zugriffsschlüssel-ID",
|
||||
"s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
|
||||
"s3SecretKey": "Geheimer Zugriffsschlüssel",
|
||||
"s3SecretKeyHelp": "AWS/S3 geheimer Zugriffsschlüssel",
|
||||
"s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"s3Region": "Region",
|
||||
"s3RegionHelp": "S3-Region (z.B. eu-central-1)"
|
||||
"s3RegionHelp": "S3-Region (z.B. eu-central-1)",
|
||||
"s3RegionPlaceholder": "eu-central-1"
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Backup-Zeitplan",
|
||||
@@ -1027,6 +1038,12 @@
|
||||
"weekly": "Wöchentlich",
|
||||
"custom": "Benutzerdefinierter Cron-Ausdruck"
|
||||
},
|
||||
"options": {
|
||||
"hourly": "Jede Stunde",
|
||||
"daily": "Täglich",
|
||||
"weekly": "Wöchentlich",
|
||||
"custom": "Benutzerdefinierter Cron-Ausdruck"
|
||||
},
|
||||
"customCron": "Cron-Ausdruck",
|
||||
"customCronHelp": "Geben Sie einen gültigen Cron-Ausdruck ein (z.B. 0 3 * * *)",
|
||||
"retention": "Aufbewahrungszeitraum",
|
||||
@@ -1063,6 +1080,11 @@
|
||||
"connectionTestFailed": "Verbindungstest fehlgeschlagen",
|
||||
"connectionTestSuccess": "Verbindungstest erfolgreich!"
|
||||
},
|
||||
"messages": {
|
||||
"requiredFields": "Bitte füllen Sie alle erforderlichen Felder aus",
|
||||
"connectionSuccess": "Verbindungstest erfolgreich!",
|
||||
"connectionFailed": "Verbindungstest fehlgeschlagen"
|
||||
},
|
||||
"testingConnection": "Teste Verbindung...",
|
||||
"saveSettings": "Konfiguration speichern",
|
||||
"savingSettings": "Speichern..."
|
||||
@@ -1086,6 +1108,14 @@
|
||||
"duration": "Dauer",
|
||||
"actions": "Aktionen"
|
||||
},
|
||||
"columns": {
|
||||
"status": "Status",
|
||||
"dateTime": "Datum & Zeit",
|
||||
"type": "Typ",
|
||||
"size": "Größe",
|
||||
"duration": "Dauer",
|
||||
"actions": "Aktionen"
|
||||
},
|
||||
"details": "Details",
|
||||
"statistics": "Statistiken",
|
||||
"errors": "Fehler",
|
||||
@@ -1104,6 +1134,27 @@
|
||||
"showing": "Zeige {{from}}-{{to}} von {{total}} Backups",
|
||||
"previous": "Zurück",
|
||||
"next": "Weiter"
|
||||
},
|
||||
"filter": {
|
||||
"allStatus": "Alle Status",
|
||||
"completed": "Abgeschlossen",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"running": "Läuft",
|
||||
"partial": "Teilweise"
|
||||
},
|
||||
"noBackupsFound": "Keine Backups gefunden",
|
||||
"backupsWillAppear": "Backups werden hier angezeigt, sobald sie erstellt wurden",
|
||||
"messages": {
|
||||
"deleteSuccess": "Backup erfolgreich gelöscht"
|
||||
},
|
||||
"details": {
|
||||
"backupDetails": "Backup-Details",
|
||||
"destination": "Ziel",
|
||||
"started": "Gestartet",
|
||||
"completed": "Abgeschlossen",
|
||||
"contentBackedUp": "Gesicherter Inhalt",
|
||||
"errorDetails": "Fehlerdetails",
|
||||
"manifest": "Manifest"
|
||||
}
|
||||
},
|
||||
"restore": {
|
||||
@@ -1147,10 +1198,7 @@
|
||||
"enterPassphrase": "Verschlüsselungs-Passphrase eingeben",
|
||||
"at": "um"
|
||||
},
|
||||
"options": {
|
||||
"title": "Wiederherstellungsoptionen",
|
||||
"subtitle": "Wählen Sie, was wiederhergestellt werden soll",
|
||||
"types": {
|
||||
"restoreTypes": {
|
||||
"full": {
|
||||
"name": "Vollständige Wiederherstellung",
|
||||
"description": "Alles wiederherstellen, einschließlich Datenbank, Fotos und Archive",
|
||||
@@ -1171,7 +1219,10 @@
|
||||
"description": "Bestimmte Elemente zur Wiederherstellung auswählen",
|
||||
"warning": "Nur ausgewählte Elemente werden wiederhergestellt"
|
||||
}
|
||||
},
|
||||
},
|
||||
"options": {
|
||||
"title": "Wiederherstellungsoptionen",
|
||||
"subtitle": "Wählen Sie, was wiederhergestellt werden soll",
|
||||
"additionalOptions": {
|
||||
"title": "Zusätzliche Optionen",
|
||||
"skipPreBackup": "Vor-Wiederherstellungs-Backup überspringen",
|
||||
@@ -1234,6 +1285,9 @@
|
||||
"starting": "Starte...",
|
||||
"validating": "Validiere...",
|
||||
"startNewRestore": "Neue Wiederherstellung starten"
|
||||
},
|
||||
"messages": {
|
||||
"restoreStarted": "Wiederherstellung erfolgreich gestartet"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
|
||||
@@ -990,12 +990,15 @@
|
||||
"warning": "Warning",
|
||||
"critical": "Critical"
|
||||
},
|
||||
"health": {
|
||||
"title": "Backup Health"
|
||||
},
|
||||
"healthMessages": {
|
||||
"noBackups": "No backups found",
|
||||
"failed": "Last backup failed",
|
||||
"lastBackupFailed": "Last backup failed",
|
||||
"upToDate": "Backup is up to date",
|
||||
"recent": "Backup is recent",
|
||||
"old": "Backup is getting old",
|
||||
"gettingOld": "Backup is getting old",
|
||||
"outdated": "Backup is outdated"
|
||||
},
|
||||
"stats": {
|
||||
@@ -1007,15 +1010,18 @@
|
||||
"files": "files",
|
||||
"minutes": "{{count}}m",
|
||||
"active": "Active",
|
||||
"inactive": "Inactive"
|
||||
"inactive": "Inactive",
|
||||
"noBackupsYet": "No backups yet"
|
||||
},
|
||||
"recentActivity": {
|
||||
"title": "Recent Backup Activity"
|
||||
},
|
||||
"recentActivity": "Recent Backup Activity",
|
||||
"backupCoverage": "Backup Coverage",
|
||||
"notConfigured": {
|
||||
"title": "Backup Not Configured",
|
||||
"message": "Please configure backup settings in the Configuration tab before running backups."
|
||||
},
|
||||
"coverage": {
|
||||
"title": "Backup Coverage",
|
||||
"database": "Database",
|
||||
"photos": "Photos",
|
||||
"archives": "Archives",
|
||||
@@ -1027,10 +1033,11 @@
|
||||
"storageDestination": "Storage Destination",
|
||||
"nextScheduledBackup": "Next Scheduled Backup",
|
||||
"backupType": "{{type}} backup",
|
||||
"noBackupsYet": "No backups yet"
|
||||
"noDestinationSet": "No destination set"
|
||||
},
|
||||
"configuration": {
|
||||
"enableBackup": "Enable Automated Backups",
|
||||
"enableBackupHelp": "Automatically create backups according to the configured schedule",
|
||||
"destinationType": "Backup Destination",
|
||||
"destinationTypes": {
|
||||
"local": {
|
||||
@@ -1049,24 +1056,34 @@
|
||||
"fields": {
|
||||
"destinationPath": "Destination Path",
|
||||
"destinationPathHelp": "Local directory path for storing backups",
|
||||
"destinationPathPlaceholder": "/path/to/backup/directory",
|
||||
"rsyncHost": "Remote Host",
|
||||
"rsyncHostHelp": "SSH hostname or IP address",
|
||||
"rsyncHostPlaceholder": "backup.example.com",
|
||||
"rsyncUser": "SSH User",
|
||||
"rsyncUserHelp": "Username for SSH connection",
|
||||
"rsyncUserPlaceholder": "backup-user",
|
||||
"rsyncPath": "Remote Path",
|
||||
"rsyncPathHelp": "Directory path on remote server",
|
||||
"rsyncPathPlaceholder": "/home/backup/photo-sharing",
|
||||
"rsyncSshKey": "SSH Private Key",
|
||||
"rsyncSshKeyHelp": "SSH private key for authentication (optional)",
|
||||
"rsyncSshKeyPlaceholder": "-----BEGIN RSA PRIVATE KEY-----",
|
||||
"s3Endpoint": "S3 Endpoint",
|
||||
"s3EndpointHelp": "S3 API endpoint (e.g., s3.amazonaws.com)",
|
||||
"s3EndpointPlaceholder": "https://s3.amazonaws.com",
|
||||
"s3Bucket": "Bucket Name",
|
||||
"s3BucketHelp": "S3 bucket for storing backups",
|
||||
"s3BucketPlaceholder": "my-backup-bucket",
|
||||
"s3AccessKey": "Access Key ID",
|
||||
"s3AccessKeyHelp": "AWS/S3 access key ID",
|
||||
"s3AccessKeyPlaceholder": "AKIAIOSFODNN7EXAMPLE",
|
||||
"s3SecretKey": "Secret Access Key",
|
||||
"s3SecretKeyHelp": "AWS/S3 secret access key",
|
||||
"s3SecretKeyPlaceholder": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"s3Region": "Region",
|
||||
"s3RegionHelp": "S3 region (e.g., us-east-1)"
|
||||
"s3RegionHelp": "S3 region (e.g., us-east-1)",
|
||||
"s3RegionPlaceholder": "us-east-1"
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Backup Schedule",
|
||||
@@ -1077,6 +1094,12 @@
|
||||
"weekly": "Weekly",
|
||||
"custom": "Custom cron expression"
|
||||
},
|
||||
"options": {
|
||||
"hourly": "Every hour",
|
||||
"daily": "Daily",
|
||||
"weekly": "Weekly",
|
||||
"custom": "Custom cron expression"
|
||||
},
|
||||
"customCron": "Cron Expression",
|
||||
"customCronHelp": "Enter a valid cron expression (e.g., 0 3 * * *)",
|
||||
"retention": "Retention Period",
|
||||
@@ -1113,6 +1136,11 @@
|
||||
"connectionTestFailed": "Connection test failed",
|
||||
"connectionTestSuccess": "Connection test successful!"
|
||||
},
|
||||
"messages": {
|
||||
"requiredFields": "Please fill in all required fields",
|
||||
"connectionSuccess": "Connection test successful!",
|
||||
"connectionFailed": "Connection test failed"
|
||||
},
|
||||
"testingConnection": "Testing connection...",
|
||||
"saveSettings": "Save Configuration",
|
||||
"savingSettings": "Saving..."
|
||||
@@ -1136,6 +1164,14 @@
|
||||
"duration": "Duration",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"columns": {
|
||||
"status": "Status",
|
||||
"dateTime": "Date & Time",
|
||||
"type": "Type",
|
||||
"size": "Size",
|
||||
"duration": "Duration",
|
||||
"actions": "Actions"
|
||||
},
|
||||
"details": "Details",
|
||||
"statistics": "Statistics",
|
||||
"errors": "Errors",
|
||||
@@ -1154,6 +1190,27 @@
|
||||
"showing": "Showing {{from}}-{{to}} of {{total}} backups",
|
||||
"previous": "Previous",
|
||||
"next": "Next"
|
||||
},
|
||||
"filter": {
|
||||
"allStatus": "All Status",
|
||||
"completed": "Completed",
|
||||
"failed": "Failed",
|
||||
"running": "Running",
|
||||
"partial": "Partial"
|
||||
},
|
||||
"noBackupsFound": "No backups found",
|
||||
"backupsWillAppear": "Backups will appear here once created",
|
||||
"messages": {
|
||||
"deleteSuccess": "Backup deleted successfully"
|
||||
},
|
||||
"details": {
|
||||
"backupDetails": "Backup Details",
|
||||
"destination": "Destination",
|
||||
"started": "Started",
|
||||
"completed": "Completed",
|
||||
"contentBackedUp": "Content Backed Up",
|
||||
"errorDetails": "Error Details",
|
||||
"manifest": "Manifest"
|
||||
}
|
||||
},
|
||||
"restore": {
|
||||
@@ -1197,10 +1254,7 @@
|
||||
"enterPassphrase": "Enter encryption passphrase",
|
||||
"at": "at"
|
||||
},
|
||||
"options": {
|
||||
"title": "Restore Options",
|
||||
"subtitle": "Choose what to restore",
|
||||
"types": {
|
||||
"restoreTypes": {
|
||||
"full": {
|
||||
"name": "Full Restore",
|
||||
"description": "Restore everything including database, photos, and archives",
|
||||
@@ -1221,7 +1275,10 @@
|
||||
"description": "Choose specific items to restore",
|
||||
"warning": "Only selected items will be restored"
|
||||
}
|
||||
},
|
||||
},
|
||||
"options": {
|
||||
"title": "Restore Options",
|
||||
"subtitle": "Choose what to restore",
|
||||
"additionalOptions": {
|
||||
"title": "Additional Options",
|
||||
"skipPreBackup": "Skip Pre-Restore Backup",
|
||||
@@ -1284,6 +1341,9 @@
|
||||
"starting": "Starting...",
|
||||
"validating": "Validating...",
|
||||
"startNewRestore": "Start New Restore"
|
||||
},
|
||||
"messages": {
|
||||
"restoreStarted": "Restore started successfully"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
|
||||
@@ -84,7 +84,7 @@ export const CreateEventPageEnhanced: React.FC = () => {
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
event_type: 'wedding',
|
||||
event_name: '',
|
||||
event_date: format(new Date(), 'yyyy-MM-dd'),
|
||||
event_date: new Date().toISOString().split('T')[0], // Initialize with ISO date format
|
||||
host_name: '',
|
||||
host_email: '',
|
||||
admin_email: '',
|
||||
|
||||
@@ -57,7 +57,7 @@ export const SettingsPage: React.FC = () => {
|
||||
enable_registration: false,
|
||||
maintenance_mode: false,
|
||||
default_language: 'en',
|
||||
date_format: { format: 'DD/MM/YYYY', locale: 'en-GB' }
|
||||
date_format: { format: 'dd/MM/yyyy', locale: 'en-GB' }
|
||||
});
|
||||
|
||||
// Security settings state
|
||||
@@ -99,7 +99,11 @@ export const SettingsPage: React.FC = () => {
|
||||
enable_registration: settings.general_enable_registration || false,
|
||||
maintenance_mode: settings.general_maintenance_mode || false,
|
||||
default_language: settings.general_default_language || 'en',
|
||||
date_format: settings.general_date_format || { format: 'DD/MM/YYYY', locale: 'en-GB' }
|
||||
date_format: settings.general_date_format
|
||||
? (typeof settings.general_date_format === 'string'
|
||||
? { format: settings.general_date_format, locale: settings.general_date_format.includes('MM/dd') ? 'en-US' : 'en-GB' }
|
||||
: settings.general_date_format)
|
||||
: { format: 'dd/MM/yyyy', locale: 'en-GB' }
|
||||
});
|
||||
|
||||
// Extract security settings
|
||||
@@ -130,7 +134,12 @@ export const SettingsPage: React.FC = () => {
|
||||
// Convert to the format expected by the API
|
||||
const settingsData: Record<string, any> = {};
|
||||
Object.entries(generalSettings).forEach(([key, value]) => {
|
||||
settingsData[`general_${key}`] = value;
|
||||
// Special handling for date_format - only send the format string
|
||||
if (key === 'date_format' && typeof value === 'object' && value.format) {
|
||||
settingsData[`general_${key}`] = value.format;
|
||||
} else {
|
||||
settingsData[`general_${key}`] = value;
|
||||
}
|
||||
});
|
||||
return settingsService.updateSettings(settingsData);
|
||||
},
|
||||
@@ -395,10 +404,10 @@ export const SettingsPage: React.FC = () => {
|
||||
{t('settings.general.dateFormat')}
|
||||
</label>
|
||||
<select
|
||||
value={generalSettings.date_format?.format || 'DD/MM/YYYY'}
|
||||
value={generalSettings.date_format?.format || 'dd/MM/yyyy'}
|
||||
onChange={(e) => {
|
||||
const format = e.target.value;
|
||||
const locale = format === 'MM/DD/YYYY' ? 'en-US' : 'en-GB';
|
||||
const locale = format === 'MM/dd/yyyy' ? 'en-US' : 'en-GB';
|
||||
setGeneralSettings(prev => ({
|
||||
...prev,
|
||||
date_format: { format, locale }
|
||||
@@ -406,10 +415,10 @@ export const SettingsPage: React.FC = () => {
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
>
|
||||
<option value="DD/MM/YYYY">DD/MM/YYYY (European)</option>
|
||||
<option value="MM/DD/YYYY">MM/DD/YYYY (US)</option>
|
||||
<option value="YYYY-MM-DD">YYYY-MM-DD (ISO)</option>
|
||||
<option value="DD.MM.YYYY">DD.MM.YYYY (German)</option>
|
||||
<option value="dd/MM/yyyy">DD/MM/YYYY (European)</option>
|
||||
<option value="MM/dd/yyyy">MM/DD/YYYY (US)</option>
|
||||
<option value="yyyy-MM-dd">YYYY-MM-DD (ISO)</option>
|
||||
<option value="dd.MM.yyyy">DD.MM.YYYY (German)</option>
|
||||
</select>
|
||||
<p className="text-xs text-neutral-500 mt-1">
|
||||
{t('settings.general.dateFormatHelp')}
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface PublicSettings {
|
||||
theme_config: any;
|
||||
default_language: string;
|
||||
enable_analytics: boolean;
|
||||
general_date_format: string;
|
||||
general_date_format: string | { format: string; locale: string };
|
||||
enable_recaptcha: boolean;
|
||||
recaptcha_site_key: string | null;
|
||||
maintenance_mode: boolean;
|
||||
|
||||
Reference in New Issue
Block a user