Merge pull request #25 from operacle/develop
feat: Auto logout after password change
This commit is contained in:
@@ -85,7 +85,8 @@ services:
|
||||
- [ ] Infrastructure Server Monitoring
|
||||
- [ ] Operational Status / Public Status Pages
|
||||
- [ ] Uptime monitoring (TCP, PING, DNS)
|
||||
- [ ] User Permission Roles & Service Group
|
||||
- [x] System Setting Panel and Mail Settings
|
||||
- [x] User Permission Roles
|
||||
- [ ] Notifications (Email/Slack/Discord/Signal)
|
||||
- [x] Open-source release with full documentation
|
||||
|
||||
@@ -122,4 +123,8 @@ CheckCle is released under the MIT License.
|
||||
|
||||
---
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#operacle/checkcle&Date)
|
||||
|
||||
Stay informed, stay online, with CheckCle! 🌐
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
@@ -10,6 +9,7 @@ import { useToast } from "@/hooks/use-toast";
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
import { pb } from "@/lib/pocketbase";
|
||||
import { authService } from "@/services/authService";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
// Password change form schema
|
||||
const passwordFormSchema = z.object({
|
||||
@@ -34,6 +34,7 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) {
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
|
||||
const { toast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const form = useForm<PasswordFormValues>({
|
||||
resolver: zodResolver(passwordFormSchema),
|
||||
@@ -44,12 +45,35 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) {
|
||||
},
|
||||
});
|
||||
|
||||
// Function to determine which collection the user belongs to
|
||||
const getUserCollection = async (userId: string): Promise<string> => {
|
||||
try {
|
||||
// First try to find the user in the regular users collection
|
||||
await pb.collection('users').getOne(userId);
|
||||
return 'users';
|
||||
} catch (error) {
|
||||
try {
|
||||
// If not found, try the superadmin collection
|
||||
await pb.collection('_superusers').getOne(userId);
|
||||
return '_superusers';
|
||||
} catch (error) {
|
||||
throw new Error('User not found in any collection');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function onSubmit(data: PasswordFormValues) {
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
console.log("Starting password change for user:", userId);
|
||||
|
||||
// Determine which collection the user belongs to
|
||||
const collection = await getUserCollection(userId);
|
||||
console.log("User found in collection:", collection);
|
||||
|
||||
// PocketBase requires the old password along with the new one
|
||||
await pb.collection('users').update(userId, {
|
||||
await pb.collection(collection).update(userId, {
|
||||
oldPassword: data.currentPassword,
|
||||
password: data.newPassword,
|
||||
passwordConfirm: data.confirmPassword,
|
||||
@@ -60,17 +84,31 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) {
|
||||
|
||||
toast({
|
||||
title: "Password updated",
|
||||
description: "Your password has been changed successfully.",
|
||||
description: "Your password has been changed successfully. You will be logged out in 3 seconds for security.",
|
||||
});
|
||||
|
||||
// Reset the form
|
||||
form.reset();
|
||||
|
||||
// Auto logout after successful password change
|
||||
setTimeout(() => {
|
||||
console.log("Auto logout after password change");
|
||||
authService.logout();
|
||||
navigate("/login");
|
||||
}, 3000);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Password change error:", error);
|
||||
|
||||
let errorMessage = "Failed to update password. Please try again.";
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message;
|
||||
if (error.message.includes("Failed to authenticate")) {
|
||||
errorMessage = "Current password is incorrect. Please try again.";
|
||||
} else if (error.message.includes("User not found")) {
|
||||
errorMessage = "User account not found. Please contact your administrator.";
|
||||
} else {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
@@ -188,4 +226,4 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) {
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form";
|
||||
import { useLanguage } from "@/contexts/LanguageContext";
|
||||
import { SettingsTabProps } from "./types";
|
||||
@@ -48,7 +47,7 @@ const SystemSettingsTab: React.FC<SettingsTabProps> = ({ form, isEditing, settin
|
||||
<Input
|
||||
{...field}
|
||||
disabled={!isEditing}
|
||||
placeholder="https://localhost:8090"
|
||||
placeholder="https://pb-api.k8sops.asia"
|
||||
className="bg-background border-input text-foreground placeholder:text-muted-foreground disabled:bg-muted disabled:text-muted-foreground"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -57,72 +56,6 @@ const SystemSettingsTab: React.FC<SettingsTabProps> = ({ form, isEditing, settin
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.senderName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-sm font-medium text-foreground">
|
||||
{t("senderName", "settings")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
disabled={!isEditing}
|
||||
placeholder="System Administrator"
|
||||
className="bg-background border-input text-foreground placeholder:text-muted-foreground disabled:bg-muted disabled:text-muted-foreground"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.senderAddress"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-sm font-medium text-foreground">
|
||||
{t("senderEmail", "settings")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
disabled={!isEditing}
|
||||
placeholder="admin@example.com"
|
||||
type="email"
|
||||
className="bg-background border-input text-foreground placeholder:text-muted-foreground disabled:bg-muted disabled:text-muted-foreground"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-3 pt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="meta.hideControls"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
disabled={!isEditing}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="text-sm font-medium text-foreground cursor-pointer">
|
||||
{t("hideControls", "settings")}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ export const aboutTranslations: AboutTranslations = {
|
||||
viewDocumentation: "Dokumentation ansehen",
|
||||
followOnX: "Auf X folgen",
|
||||
joinDiscord: "Discord beitreten",
|
||||
quickActions: "Quick Actions",
|
||||
quickActionsDescription: "Access common monitoring operations and features quickly. Select an action below to get started.",
|
||||
quickTips: "Quick Tips",
|
||||
quickActions: "Schnelle Aktionen",
|
||||
quickActionsDescription: "Greifen Sie schnell auf gängige Überwachungsvorgänge und -funktionen zu. Wählen Sie unten eine Aktion aus, um loszulegen.",
|
||||
quickTips: "Schnelle Tipps",
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,19 +11,19 @@ export const commonTranslations: CommonTranslations = {
|
||||
goodMorning: "Guten Morgen",
|
||||
goodAfternoon: "Guten Nachmittag",
|
||||
goodEvening: "Guten Abend",
|
||||
profile: "Profile",
|
||||
settings: "Settings",
|
||||
documentation: "Documentation",
|
||||
notifications: "Notifications",
|
||||
close: "Close",
|
||||
cancel: "Cancel",
|
||||
view: "View",
|
||||
edit: "Edit",
|
||||
delete: "Delete",
|
||||
profile: "Profil",
|
||||
settings: "Einstellungen",
|
||||
documentation: "Dokumentation",
|
||||
notifications: "Benachrichtigungen",
|
||||
close: "Schließen",
|
||||
cancel: "Abbrechen",
|
||||
view: "Anzeigen",
|
||||
edit: "Bearbeiten",
|
||||
delete: "Löschen",
|
||||
status: "Status",
|
||||
time: "Time",
|
||||
title: "Title",
|
||||
description: "Description",
|
||||
success: "Success",
|
||||
error: "Error",
|
||||
time: "Zeit",
|
||||
title: "Titel",
|
||||
description: "Beschreibung",
|
||||
success: "Erfolg",
|
||||
error: "Fehler",
|
||||
};
|
||||
|
||||
@@ -1,55 +1,54 @@
|
||||
|
||||
import { IncidentTranslations } from '../types/incident';
|
||||
|
||||
export const incidentTranslations: IncidentTranslations = {
|
||||
incidentManagement: 'Incident Management',
|
||||
incidentsManagementDesc: 'Track and manage service incidents and their resolutions',
|
||||
unresolvedIncidents: 'Unresolved',
|
||||
resolvedIncidents: 'Resolved',
|
||||
activeIncidents: 'Active Incidents',
|
||||
criticalIssues: 'Critical Issues',
|
||||
avgResolutionTime: 'Avg. Resolution Time',
|
||||
noIncidents: 'No Active Incidents',
|
||||
createIncident: 'Create Incident',
|
||||
investigating: 'Investigating',
|
||||
identified: 'Identified',
|
||||
monitoring: 'Monitoring',
|
||||
resolved: 'Resolved',
|
||||
scheduleIncidentManagement: 'Schedule & Incident Management',
|
||||
incidentName: 'Incident Name',
|
||||
incidentStatus: 'Incident Status',
|
||||
highPriority: 'High Priority',
|
||||
configurationSettings: 'Configuration Settings',
|
||||
incidentCreatedSuccess: 'Incident created successfully',
|
||||
basicInfo: 'Basic Information',
|
||||
serviceId: 'Service ID',
|
||||
assignedTo: 'Assigned To',
|
||||
unassigned: 'Unassigned',
|
||||
timeline: 'Timeline',
|
||||
incidentTime: 'Incident Time',
|
||||
resolutionTime: 'Resolution Time',
|
||||
systems: 'Systems',
|
||||
noSystems: 'No systems affected',
|
||||
impactAnalysis: 'Impact Analysis',
|
||||
rootCause: 'Root Cause',
|
||||
resolutionSteps: 'Resolution Steps',
|
||||
lessonsLearned: 'Lessons Learned',
|
||||
resolutionDetails: 'Resolution Details',
|
||||
assignment: 'Assignment',
|
||||
download: 'Download',
|
||||
downloadPdf: 'Download PDF',
|
||||
print: 'Print',
|
||||
confidentialNote: 'This document is confidential and intended for internal use only.',
|
||||
generatedOn: 'Generated on',
|
||||
enterResolutionSteps: 'Enter steps taken to resolve the incident',
|
||||
enterLessonsLearned: 'Enter lessons learned from this incident',
|
||||
editIncident: 'Edit Incident',
|
||||
editIncidentDesc: 'Update details for this incident',
|
||||
updating: 'Updating...',
|
||||
update: 'Update',
|
||||
create: 'Create',
|
||||
creating: 'Creating...',
|
||||
configuration: 'Configuration',
|
||||
failedToUpdateStatus: 'Failed to update status',
|
||||
inProgress: 'In Progress',
|
||||
incidentManagement: 'Vorfallmanagement',
|
||||
incidentsManagementDesc: 'Verfolgen und Verwalten von Servicevorfällen und deren Lösungen',
|
||||
unresolvedIncidents: 'Ungelöst',
|
||||
resolvedIncidents: 'Gelöst',
|
||||
activeIncidents: 'Aktive Vorfälle',
|
||||
criticalIssues: 'Kritische Probleme',
|
||||
avgResolutionTime: 'Durchschn. Lösungszeit',
|
||||
noIncidents: 'Keine aktiven Vorfälle',
|
||||
createIncident: 'Vorfall erstellen',
|
||||
investigating: 'Untersuchung läuft',
|
||||
identified: 'Identifiziert',
|
||||
monitoring: 'Überwachung',
|
||||
resolved: 'Gelöst',
|
||||
scheduleIncidentManagement: 'Zeitplanung & Vorfallmanagement',
|
||||
incidentName: 'Vorfallname',
|
||||
incidentStatus: 'Vorfallstatus',
|
||||
highPriority: 'Hohe Priorität',
|
||||
configurationSettings: 'Konfigurationseinstellungen',
|
||||
incidentCreatedSuccess: 'Vorfall erfolgreich erstellt',
|
||||
basicInfo: 'Grundinformationen',
|
||||
serviceId: 'Service-ID',
|
||||
assignedTo: 'Zugewiesen an',
|
||||
unassigned: 'Nicht zugewiesen',
|
||||
timeline: 'Zeitverlauf',
|
||||
incidentTime: 'Vorfallszeit',
|
||||
resolutionTime: 'Lösungszeit',
|
||||
systems: 'Systeme',
|
||||
noSystems: 'Keine betroffenen Systeme',
|
||||
impactAnalysis: 'Auswirkungsanalyse',
|
||||
rootCause: 'Ursache',
|
||||
resolutionSteps: 'Lösungsschritte',
|
||||
lessonsLearned: 'Erkenntnisse',
|
||||
resolutionDetails: 'Details zur Lösung',
|
||||
assignment: 'Zuweisung',
|
||||
download: 'Herunterladen',
|
||||
downloadPdf: 'PDF herunterladen',
|
||||
print: 'Drucken',
|
||||
confidentialNote: 'Dieses Dokument ist vertraulich und nur für den internen Gebrauch bestimmt.',
|
||||
generatedOn: 'Erstellt am',
|
||||
enterResolutionSteps: 'Geben Sie die zur Lösung ergriffenen Schritte ein',
|
||||
enterLessonsLearned: 'Geben Sie die aus diesem Vorfall gewonnenen Erkenntnisse ein',
|
||||
editIncident: 'Vorfall bearbeiten',
|
||||
editIncidentDesc: 'Details zu diesem Vorfall aktualisieren',
|
||||
updating: 'Aktualisiere...',
|
||||
update: 'Aktualisieren',
|
||||
create: 'Erstellen',
|
||||
creating: 'Erstelle...',
|
||||
configuration: 'Konfiguration',
|
||||
failedToUpdateStatus: 'Fehler beim Aktualisieren des Status',
|
||||
inProgress: 'In Bearbeitung',
|
||||
};
|
||||
|
||||
@@ -1,68 +1,67 @@
|
||||
|
||||
import { MaintenanceTranslations } from '../types/maintenance';
|
||||
|
||||
export const maintenanceTranslations: MaintenanceTranslations = {
|
||||
scheduledMaintenance: 'Scheduled Maintenance',
|
||||
scheduledMaintenanceDesc: 'View and manage planned maintenance windows for your systems and services',
|
||||
upcomingMaintenance: 'Upcoming',
|
||||
ongoingMaintenance: 'Ongoing',
|
||||
completedMaintenance: 'Completed',
|
||||
createMaintenanceWindow: 'Create Maintenance',
|
||||
totalScheduledHours: 'Total Scheduled Hours',
|
||||
maintenanceName: 'Maintenance Name',
|
||||
scheduledMaintenance: 'Geplante Wartung',
|
||||
scheduledMaintenanceDesc: 'Anzeigen und Verwalten geplanter Wartungsfenster für Ihre Systeme und Dienste',
|
||||
upcomingMaintenance: 'Bevorstehend',
|
||||
ongoingMaintenance: 'Laufend',
|
||||
completedMaintenance: 'Abgeschlossen',
|
||||
createMaintenanceWindow: 'Wartung erstellen',
|
||||
totalScheduledHours: 'Geplante Gesamtstunden',
|
||||
maintenanceName: 'Wartungsname',
|
||||
maintenanceStatus: 'Status',
|
||||
scheduledStart: 'Scheduled Start',
|
||||
scheduledEnd: 'Scheduled End',
|
||||
affectedServices: 'Affected Services',
|
||||
impact: 'Impact',
|
||||
minor: 'Minor',
|
||||
major: 'Major',
|
||||
critical: 'Critical',
|
||||
none: 'None',
|
||||
actions: 'Actions',
|
||||
scheduled: 'Scheduled',
|
||||
inprogress: 'In Progress',
|
||||
completed: 'Completed',
|
||||
cancelled: 'Cancelled',
|
||||
markAsInProgress: 'Mark as In Progress',
|
||||
markAsCompleted: 'Mark as Completed',
|
||||
markAsCancelled: 'Mark as Cancelled',
|
||||
confirmDelete: 'Confirm Delete',
|
||||
deleteMaintenanceConfirmation: 'Are you sure you want to delete this maintenance window?',
|
||||
thisActionCannotBeUndone: 'This action cannot be undone.',
|
||||
maintenanceDeleted: 'Maintenance Deleted',
|
||||
maintenanceDeletedDesc: 'The maintenance window has been deleted successfully.',
|
||||
errorDeletingMaintenance: 'There was an error deleting the maintenance window.',
|
||||
statusUpdated: 'Status Updated',
|
||||
maintenanceStatusUpdated: 'Maintenance status has been updated successfully.',
|
||||
errorUpdatingMaintenanceStatus: 'There was an error updating the maintenance status.',
|
||||
createMaintenance: 'Create Maintenance',
|
||||
createMaintenanceDesc: 'Schedule a new maintenance window for your services',
|
||||
enterTitle: 'Enter maintenance title',
|
||||
enterDescription: 'Enter detailed description of the maintenance',
|
||||
startTime: 'Start Time',
|
||||
endTime: 'End Time',
|
||||
selectDate: 'Select a date',
|
||||
enterAffectedServices: 'Enter affected services',
|
||||
separateServicesWithComma: 'Separate multiple services with commas',
|
||||
priority: 'Priority',
|
||||
selectPriority: 'Select priority',
|
||||
selectStatus: 'Select status',
|
||||
selectImpact: 'Select impact',
|
||||
notifySubscribers: 'Notify Subscribers',
|
||||
notifySubscribersDesc: 'Send notifications to all subscribers when this maintenance starts',
|
||||
maintenanceCreated: 'Maintenance Created',
|
||||
maintenanceCreatedDesc: 'The maintenance window has been scheduled successfully.',
|
||||
errorCreatingMaintenance: 'There was an error creating the maintenance window.',
|
||||
errorFetchingMaintenanceData: 'There was an error fetching maintenance data.',
|
||||
low: 'Low',
|
||||
medium: 'Medium',
|
||||
high: 'High',
|
||||
created: 'Created',
|
||||
lastUpdated: 'Last Updated',
|
||||
subscribersWillBeNotified: 'Subscribers will be notified when maintenance begins',
|
||||
noNotifications: 'No notifications will be sent',
|
||||
noScheduledMaintenance: 'No Scheduled Maintenance',
|
||||
noMaintenanceWindows: 'There are no maintenance windows for this period. Create one by clicking the "Create Maintenance" button.',
|
||||
maintenanceCreatedSuccess: 'Maintenance window created successfully',
|
||||
scheduledStart: 'Geplanter Start',
|
||||
scheduledEnd: 'Geplantes Ende',
|
||||
affectedServices: 'Betroffene Dienste',
|
||||
impact: 'Auswirkung',
|
||||
minor: 'Geringfügig',
|
||||
major: 'Gravierend',
|
||||
critical: 'Kritisch',
|
||||
none: 'Keine',
|
||||
actions: 'Aktionen',
|
||||
scheduled: 'Geplant',
|
||||
inprogress: 'In Bearbeitung',
|
||||
completed: 'Abgeschlossen',
|
||||
cancelled: 'Abgebrochen',
|
||||
markAsInProgress: 'Als in Bearbeitung markieren',
|
||||
markAsCompleted: 'Als abgeschlossen markieren',
|
||||
markAsCancelled: 'Als abgebrochen markieren',
|
||||
confirmDelete: 'Löschen bestätigen',
|
||||
deleteMaintenanceConfirmation: 'Möchten Sie dieses Wartungsfenster wirklich löschen?',
|
||||
thisActionCannotBeUndone: 'Diese Aktion kann nicht rückgängig gemacht werden.',
|
||||
maintenanceDeleted: 'Wartung gelöscht',
|
||||
maintenanceDeletedDesc: 'Das Wartungsfenster wurde erfolgreich gelöscht.',
|
||||
errorDeletingMaintenance: 'Fehler beim Löschen des Wartungsfensters.',
|
||||
statusUpdated: 'Status aktualisiert',
|
||||
maintenanceStatusUpdated: 'Wartungsstatus wurde erfolgreich aktualisiert.',
|
||||
errorUpdatingMaintenanceStatus: 'Fehler beim Aktualisieren des Wartungsstatus.',
|
||||
createMaintenance: 'Wartung erstellen',
|
||||
createMaintenanceDesc: 'Planen Sie ein neues Wartungsfenster für Ihre Dienste',
|
||||
enterTitle: 'Wartungstitel eingeben',
|
||||
enterDescription: 'Geben Sie eine detaillierte Beschreibung der Wartung ein',
|
||||
startTime: 'Startzeit',
|
||||
endTime: 'Endzeit',
|
||||
selectDate: 'Datum auswählen',
|
||||
enterAffectedServices: 'Betroffene Dienste eingeben',
|
||||
separateServicesWithComma: 'Mehrere Dienste durch Kommas trennen',
|
||||
priority: 'Priorität',
|
||||
selectPriority: 'Priorität auswählen',
|
||||
selectStatus: 'Status auswählen',
|
||||
selectImpact: 'Auswirkung auswählen',
|
||||
notifySubscribers: 'Abonnenten benachrichtigen',
|
||||
notifySubscribersDesc: 'Beim Start dieser Wartung eine Benachrichtigung an alle Abonnenten senden',
|
||||
maintenanceCreated: 'Wartung erstellt',
|
||||
maintenanceCreatedDesc: 'Das Wartungsfenster wurde erfolgreich geplant.',
|
||||
errorCreatingMaintenance: 'Fehler beim Erstellen des Wartungsfensters.',
|
||||
errorFetchingMaintenanceData: 'Fehler beim Abrufen der Wartungsdaten.',
|
||||
low: 'Niedrig',
|
||||
medium: 'Mittel',
|
||||
high: 'Hoch',
|
||||
created: 'Erstellt',
|
||||
lastUpdated: 'Zuletzt aktualisiert',
|
||||
subscribersWillBeNotified: 'Abonnenten werden benachrichtigt, wenn die Wartung beginnt',
|
||||
noNotifications: 'Es werden keine Benachrichtigungen gesendet',
|
||||
noScheduledMaintenance: 'Keine geplanten Wartungen',
|
||||
noMaintenanceWindows: 'Für diesen Zeitraum sind keine Wartungsfenster vorhanden. Erstellen Sie eines über die Schaltfläche „Wartung erstellen“.',
|
||||
maintenanceCreatedSuccess: 'Wartungsfenster erfolgreich erstellt',
|
||||
};
|
||||
|
||||
@@ -9,5 +9,5 @@ export const servicesTranslations: ServicesTranslations = {
|
||||
responseTime: "Antwortzeit",
|
||||
uptime: "Betriebszeit",
|
||||
lastChecked: "Zuletzt überprüft",
|
||||
noServices: "No services match your filter criteria.",
|
||||
noServices: "Keine Dienste entsprechen Ihren Filterkriterien.",
|
||||
};
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
|
||||
import { SettingsTranslations } from '../types/settings';
|
||||
|
||||
export const settingsTranslations: SettingsTranslations = {
|
||||
// Tabs
|
||||
systemSettings: "System Settings",
|
||||
mailSettings: "Mail Settings",
|
||||
|
||||
systemSettings: "Systemeinstellungen",
|
||||
mailSettings: "E-Mail-Einstellungen",
|
||||
|
||||
// System Settings
|
||||
appName: "Application Name",
|
||||
appURL: "Application URL",
|
||||
senderName: "Sender Name",
|
||||
senderEmail: "Sender Email Address",
|
||||
hideControls: "Hide Controls",
|
||||
|
||||
appName: "Anwendungsname",
|
||||
appURL: "Anwendungs-URL",
|
||||
senderName: "Absendername",
|
||||
senderEmail: "Absender-E-Mail-Adresse",
|
||||
hideControls: "Steuerelemente ausblenden",
|
||||
|
||||
// Mail Settings
|
||||
smtpSettings: "SMTP Configuration",
|
||||
smtpEnabled: "Enable SMTP",
|
||||
smtpHost: "SMTP Host",
|
||||
smtpPort: "SMTP Port",
|
||||
smtpUsername: "SMTP Username",
|
||||
smtpAuthMethod: "Authentication Method",
|
||||
enableTLS: "Enable TLS",
|
||||
localName: "Local Name",
|
||||
|
||||
smtpSettings: "SMTP-Konfiguration",
|
||||
smtpEnabled: "SMTP aktivieren",
|
||||
smtpHost: "SMTP-Host",
|
||||
smtpPort: "SMTP-Port",
|
||||
smtpUsername: "SMTP-Benutzername",
|
||||
smtpAuthMethod: "Authentifizierungsmethode",
|
||||
enableTLS: "TLS aktivieren",
|
||||
localName: "Lokaler Name",
|
||||
|
||||
// Actions and status
|
||||
save: "Save Changes",
|
||||
saving: "Saving...",
|
||||
settingsUpdated: "Settings updated successfully",
|
||||
errorSavingSettings: "Error saving settings",
|
||||
testConnection: "Test Connection",
|
||||
testingConnection: "Testing Connection...",
|
||||
connectionSuccess: "Connection successful",
|
||||
connectionFailed: "Connection failed"
|
||||
};
|
||||
save: "Änderungen speichern",
|
||||
saving: "Speichere...",
|
||||
settingsUpdated: "Einstellungen erfolgreich aktualisiert",
|
||||
errorSavingSettings: "Fehler beim Speichern der Einstellungen",
|
||||
testConnection: "Verbindung testen",
|
||||
testingConnection: "Verbindung wird getestet...",
|
||||
connectionSuccess: "Verbindung erfolgreich",
|
||||
connectionFailed: "Verbindung fehlgeschlagen"
|
||||
};
|
||||
|
||||
@@ -43,65 +43,66 @@ export const sslTranslations: SSLTranslations = {
|
||||
expirationDate: "Ablaufdatum",
|
||||
daysLeft: "Verbleibende Tage",
|
||||
status: "Status",
|
||||
lastNotified: "Last Notified",
|
||||
actions: "Actions",
|
||||
validFrom: "Valid From",
|
||||
validUntil: "Valid Until",
|
||||
validityDays: "Validity Days",
|
||||
organization: "Organization",
|
||||
commonName: "Common Name",
|
||||
serialNumber: "Serial Number",
|
||||
algorithm: "Algorithm",
|
||||
subjectAltNames: "Subject Alternative Names",
|
||||
lastNotified: "Zuletzt benachrichtigt",
|
||||
actions: "Aktionen",
|
||||
validFrom: "Gültig von",
|
||||
validUntil: "Gültig bis",
|
||||
validityDays: "Gültigkeitsdauer Tage",
|
||||
organization: "Organisation",
|
||||
commonName: "Allgemeiner Name",
|
||||
serialNumber: "Seriennummer",
|
||||
algorithm: "Algorithmus",
|
||||
subjectAltNames: "Thema Alternative Bezeichnungen",
|
||||
|
||||
// Buttons and actions
|
||||
addDomain: "Add Domain",
|
||||
refreshAll: "Refresh All",
|
||||
cancel: "Cancel",
|
||||
addCertificate: "Add Certificate",
|
||||
check: "Check",
|
||||
view: "View",
|
||||
edit: "Edit",
|
||||
delete: "Delete",
|
||||
close: "Close",
|
||||
saveChanges: "Save Changes",
|
||||
updating: "Updating",
|
||||
|
||||
addDomain: "Domain hinzufügen",
|
||||
refreshAll: "Alle aktualisieren",
|
||||
cancel: "Abbrechen",
|
||||
addCertificate: "Zertifikat hinzufügen",
|
||||
check: "Prüfen",
|
||||
view: "Ansehen",
|
||||
edit: "Bearbeiten",
|
||||
delete: "Löschen",
|
||||
close: "Schließen",
|
||||
saveChanges: "Änderungen speichern",
|
||||
updating: "Aktualisiere",
|
||||
|
||||
// Sections in detail view
|
||||
basicInformation: "Basic Information",
|
||||
validity: "Validity",
|
||||
issuerInfo: "Issuer Information",
|
||||
technicalDetails: "Technical Details",
|
||||
monitoringConfig: "Monitoring Configuration",
|
||||
recordInfo: "Record Information",
|
||||
|
||||
basicInformation: "Basisinformationen",
|
||||
validity: "Gültigkeit",
|
||||
issuerInfo: "Informationen zum Aussteller",
|
||||
technicalDetails: "Technische Details",
|
||||
monitoringConfig: "Monitoring-Konfiguration",
|
||||
recordInfo: "Aufzeichnungsinformationen",
|
||||
|
||||
// Notifications and messages
|
||||
sslCertificateAdded: "SSL Certificate added successfully",
|
||||
sslCertificateUpdated: "SSL Certificate updated successfully",
|
||||
sslCertificateDeleted: "SSL Certificate deleted successfully",
|
||||
sslCertificateRefreshed: "SSL Certificate for {domain} refreshed successfully",
|
||||
allCertificatesRefreshed: "All {count} certificates refreshed successfully",
|
||||
someCertificatesFailed: "{success} certificates refreshed, {failed} failed",
|
||||
failedToAddCertificate: "Failed to add SSL certificate",
|
||||
failedToLoadCertificates: "Failed to load SSL certificates",
|
||||
failedToUpdateCertificate: "Failed to update SSL certificate",
|
||||
failedToDeleteCertificate: "Failed to delete SSL certificate",
|
||||
failedToCheckCertificate: "Failed to check SSL certificate",
|
||||
noCertificatesToRefresh: "No certificates to refresh",
|
||||
startingRefreshAll: "Starting refresh of {count} certificates",
|
||||
checkingSSLCertificate: "Checking SSL certificate...",
|
||||
deleteConfirmation: "Are you sure you want to delete the certificate for",
|
||||
deleteWarning: "This action cannot be undone. This will permanently delete the certificate.",
|
||||
|
||||
sslCertificateAdded: "SSL-Zertifikat erfolgreich hinzugefügt",
|
||||
sslCertificateUpdated: "SSL-Zertifikat erfolgreich aktualisiert",
|
||||
sslCertificateDeleted: "SSL-Zertifikat erfolgreich gelöscht",
|
||||
sslCertificateRefreshed: "SSL-Zertifikat für {domain} erfolgreich aktualisiert",
|
||||
allCertificatesRefreshed: "Alle {count} Zertifikate wurden erfolgreich aktualisiert",
|
||||
someCertificatesFailed: "{success} Zertifikate aktualisiert, {failed} fehlgeschlagen",
|
||||
failedToAddCertificate: "Fehler beim Hinzufügen des SSL-Zertifikats",
|
||||
failedToLoadCertificates: "Fehler beim Laden der SSL-Zertifikate",
|
||||
failedToUpdateCertificate: "Fehler beim Aktualisieren des SSL-Zertifikats",
|
||||
failedToDeleteCertificate: "Fehler beim Löschen des SSL-Zertifikats",
|
||||
failedToCheckCertificate: "Fehler beim Prüfen des SSL-Zertifikats",
|
||||
noCertificatesToRefresh: "Keine Zertifikate zum Aktualisieren vorhanden",
|
||||
startingRefreshAll: "Starte Aktualisierung von {count} Zertifikaten",
|
||||
checkingSSLCertificate: "SSL-Zertifikat wird überprüft...",
|
||||
deleteConfirmation: "Möchten Sie das Zertifikat für wirklich löschen?",
|
||||
deleteWarning: "Diese Aktion kann nicht rückgängig gemacht werden. Das Zertifikat wird dauerhaft gelöscht.",
|
||||
|
||||
// Misc
|
||||
unknown: "Unknown",
|
||||
never: "Never",
|
||||
none: "None",
|
||||
loadingChannels: "Loading channels...",
|
||||
noChannelsFound: "No notification channels found",
|
||||
noSSLCertificates: "No SSL certificates found",
|
||||
created: "Created",
|
||||
lastUpdated: "Last Updated",
|
||||
lastNotification: "Last Notification",
|
||||
collectionId: "Collection ID"
|
||||
};
|
||||
unknown: "Unbekannt",
|
||||
never: "Nie",
|
||||
none: "Keine",
|
||||
loadingChannels: "Lade Kanäle...",
|
||||
noChannelsFound: "Keine Benachrichtigungskanäle gefunden",
|
||||
noSSLCertificates: "Keine SSL-Zertifikate gefunden",
|
||||
created: "Erstellt",
|
||||
lastUpdated: "Zuletzt aktualisiert",
|
||||
lastNotification: "Letzte Benachrichtigung",
|
||||
collectionId: "Sammlungs-ID"
|
||||
}
|
||||
|
||||
|
||||
+44
-67
@@ -2,82 +2,59 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting Checkcle Installation..."
|
||||
REPO_URL="https://github.com/operacle/checkcle.git"
|
||||
CLONE_DIR="/opt/checkcle"
|
||||
DATA_DIR="/opt/pb_data"
|
||||
PORT=8090
|
||||
|
||||
# Check if npm is installed
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo "📦 npm is not installed. Installing Node.js and npm..."
|
||||
|
||||
# Install Node.js and npm (Ubuntu/Debian-based systems)
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
echo "🚀 Installing Checkcle from $REPO_URL"
|
||||
|
||||
# Step 1: Check if port 8090 is already in use
|
||||
if lsof -i :"$PORT" &>/dev/null; then
|
||||
echo "❗ ERROR: Port $PORT is already in use. Please free the port or change the Docker Compose configuration."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clone the repo
|
||||
if [ ! -d "checkcle" ]; then
|
||||
echo "📁 Cloning repository..."
|
||||
git clone https://github.com/operacle/checkcle.git
|
||||
# Step 2: Ensure Docker is installed
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "🔧 Docker not found. Installing Docker..."
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
fi
|
||||
|
||||
cd checkcle
|
||||
# Step 3: Ensure Docker Compose v2 is available
|
||||
if ! docker compose version &> /dev/null; then
|
||||
echo "❗ Docker Compose v2 not found. Please install Docker Compose v2 and rerun this script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set up paths
|
||||
PROJECT_DIR=$(pwd)
|
||||
APP_DIR="$PROJECT_DIR/application"
|
||||
PB_DIR="$PROJECT_DIR/server"
|
||||
PB_BINARY="$PB_DIR/pocketbase"
|
||||
# Step 4: Clone the repository
|
||||
if [ -d "$CLONE_DIR" ]; then
|
||||
echo "📁 Directory $CLONE_DIR already exists. Pulling latest changes..."
|
||||
git -C "$CLONE_DIR" pull
|
||||
else
|
||||
echo "📥 Cloning repo to $CLONE_DIR"
|
||||
git clone "$REPO_URL" "$CLONE_DIR"
|
||||
fi
|
||||
|
||||
# Install web dependencies
|
||||
echo "📦 Installing Web Application dependencies..."
|
||||
cd "$APP_DIR"
|
||||
npm install
|
||||
# Step 5: Create data volume directory if it doesn’t exist
|
||||
if [ ! -d "$DATA_DIR" ]; then
|
||||
echo "📁 Creating data volume directory at $DATA_DIR"
|
||||
sudo mkdir -p "$DATA_DIR"
|
||||
sudo chown "$(whoami)":"$(whoami)" "$DATA_DIR"
|
||||
fi
|
||||
|
||||
# Create systemd service for frontend
|
||||
echo "🛠️ Setting up systemd service for Web Application..."
|
||||
sudo tee /etc/systemd/system/checkcle-web.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Checkcle Web Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$APP_DIR
|
||||
ExecStart=/usr/bin/npm run dev
|
||||
Restart=on-failure
|
||||
User=$USER
|
||||
Environment=NODE_ENV=development
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create systemd service for PocketBase
|
||||
echo "🛠️ Setting up systemd service for PocketBase..."
|
||||
sudo tee /etc/systemd/system/checkcle-pb.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Checkcle PocketBase Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$PB_DIR
|
||||
ExecStart=$PB_BINARY serve --dir pb_data
|
||||
Restart=on-failure
|
||||
User=$USER
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Reload systemd and start services
|
||||
echo "🔄 Enabling and starting services..."
|
||||
sudo systemctl daemon-reexec
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now checkcle-web
|
||||
sudo systemctl enable --now checkcle-pb
|
||||
# Step 6: Start the service
|
||||
cd "$CLONE_DIR"
|
||||
echo "📦 Starting Checkcle service with Docker Compose..."
|
||||
docker compose up -d
|
||||
|
||||
# Step 7: Show success output
|
||||
echo ""
|
||||
echo "✅ All done!"
|
||||
echo "🌐 Admin Panel: http://0.0.0.0:8090"
|
||||
echo "✅ Checkcle has been successfully installed and started."
|
||||
echo ""
|
||||
echo "🛠️ Admin Web Management"
|
||||
echo "🔗 Default URL: http://0.0.0.0:$PORT"
|
||||
echo "👤 User: admin@example.com"
|
||||
echo "🔑 Passwd: Admin123456"
|
||||
echo ""
|
||||
echo "📌 Make sure port $PORT is accessible from your host system or cloud firewall."
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user