Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -122,4 +123,8 @@ CheckCle is released under the MIT License.

---

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=operacle/checkcle&type=Date)](https://www.star-history.com/#operacle/checkcle&Date)

Stay informed, stay online, with CheckCle! 🌐
48 changes: 43 additions & 5 deletions application/src/components/profile/ChangePasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { useState } from "react";
import { z } from "zod";
import { useForm } from "react-hook-form";
Expand All @@ -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({
Expand All @@ -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),
Expand All @@ -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,
Expand All @@ -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({
Expand Down Expand Up @@ -188,4 +226,4 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) {
</form>
</Form>
);
}
}
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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>
Expand All @@ -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>
);
};
Expand Down
6 changes: 3 additions & 3 deletions application/src/translations/de/about.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};


28 changes: 14 additions & 14 deletions application/src/translations/de/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
101 changes: 50 additions & 51 deletions application/src/translations/de/incident.ts
Original file line number Diff line number Diff line change
@@ -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',
};
Loading