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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ dist-ssr
*.ntvs*
*.njsproj
*.sln
*.sw?
*.sw?
application/src/lib/pocketbase.ts
Dockerfile
39 changes: 0 additions & 39 deletions Dockerfile

This file was deleted.

36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@ CheckCle is an Open Source solution for seamless, real-time monitoring of full-s

## #️⃣ Getting Started

### Installation with Docker Compose
### Installation with Docker Run and Compose
1. Copy ready docker run command
```bash
# Create Docker Volume for data persistence

docker volume create pb_data


# Docker Run Command

docker run --name checkcle --restart unless-stopped -p 8090:8090 -v pb_data:/app/pb_data --ulimit nofile=4096:8192 operacle/checkcle:latest
docker run -d \
--name checkcle \
--restart unless-stopped \
-p 8090:8090 \
-v /opt/pb_data:/mnt/pb_data \
--ulimit nofile=4096:8192 \
operacle/checkcle:latest

```
2. Docker Compose - Recommended
```bash

version: '3.9'

services:
checkcle:
image: operacle/checkcle:latest
Expand All @@ -48,28 +49,25 @@ services:
ports:
- "8090:8090" # Web Application
volumes:
- pb_data:/app/pb_data # Ensure persistent data across rebuilds
- /opt/pb_data:/mnt/pb_data # Host directory mapped to container path
ulimits:
nofile:
soft: 4096
hard: 8192

volumes:
pb_data: # Docker-managed volume for data persistence

```
3. Admin Web Management

Default URL: http://0.0.0.0:8090
User: admin@example.com
Passwd: Admin123456

4. Follow the Quick Start Guide at https://docs.checkcle.com (Coming Soon)
4. Follow the Quick Start Guide at https://docs.checkcle.io

###
![Uptime Monitoring](https://pub-4a4062303020445f8f289a2fee84f9e8.r2.dev/images/checkcle-collapse-black.png)
![checkcle-collapse-black](https://pub-4a4062303020445f8f289a2fee84f9e8.r2.dev/images/checkcle-black.png)
![Service Detail Page](https://pub-4a4062303020445f8f289a2fee84f9e8.r2.dev/images/checkcle-detailpage.png)
![Schedule Maintenance](https://pub-4a4062303020445f8f289a2fee84f9e8.r2.dev/images/maintenance-dahboard.png)

## 📝 Development Roadmap

Expand All @@ -80,15 +78,16 @@ volumes:
- [x] Docker containerization
- [x] CheckCle Website
- [x] CheckCle Demo Server
- [x] SSL & Domain Monitoring - added in release of https://github.com/operacle/checkcle/releases/tag/v1.1.0
- [x] SSL & Domain Monitoring
- [x] Schedule Maintenance
- [x] Incident Management
- [ ] Uptime monitoring (PING - Inprogress)
- [ ] Infrastructure Server Monitoring
- [ ] Schedule Maintenance & Incident Management
- [ ] Operational Status / Public Status Pages
- [ ] Uptime monitoring (TCP, PING, DNS)
- [ ] User Permission Roles & Service Group
- [ ] Notifications (Email/Slack/Discord/Signal)
- [ ] Open-source release with full documentation
- [x] Open-source release with full documentation

## 🌟 CheckCle for Communities?
- **Built with Passion**: Created by an open-source enthusiast for the community
Expand All @@ -111,6 +110,7 @@ Here are some ways you can help improve CheckCle:

## 🌍 Stay Connected
- Website: [checkcle.io](https://checkcle.io)
- Documentation: [docs.checkcle.io](https://docs.checkcle.io)
- GitHub Repository: ⭐ [CheckCle](https://github.com/operacle/checkcle.git)
- Community Channels: Engage via discussions and issues!
- Discord: Join our community [@discord](https://discord.gg/xs9gbubGwX)
Expand Down
14 changes: 7 additions & 7 deletions application/src/components/services/ServiceRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ export const ServiceRow = ({
className={`border-b ${theme === 'dark' ? 'border-gray-800 hover:bg-gray-900/60' : 'border-gray-200 hover:bg-gray-50'} cursor-pointer`}
onClick={handleRowClick}
>
<TableCell className="font-medium py-4" onClick={(e) => e.stopPropagation()}>
<TableCell className="font-medium py-4">
<ServiceRowHeader service={service} />
</TableCell>
<TableCell onClick={(e) => e.stopPropagation()} className={`text-base py-4 ${theme === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
<TableCell className={`text-base py-4 ${theme === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
{service.type}
</TableCell>
<TableCell onClick={(e) => e.stopPropagation()} className="py-4">
<TableCell className="py-4">
<StatusBadge status={service.status} size="md" />
</TableCell>
<TableCell onClick={(e) => e.stopPropagation()} className="py-4">
<TableCell className="py-4">
<ServiceRowResponseTime responseTime={service.responseTime} />
</TableCell>
<TableCell className="w-52 py-4" onClick={(e) => e.stopPropagation()}>
<TableCell className="w-52 py-4">
<UptimeBar uptime={service.uptime} status={service.status} serviceId={service.id} />
</TableCell>
<TableCell onClick={(e) => e.stopPropagation()} className="py-4">
<TableCell className="py-4">
<LastCheckedTime
lastCheckedTime={displayTimestamp}
status={service.status}
Expand All @@ -77,4 +77,4 @@ export const ServiceRow = ({
</TableCell>
</TableRow>
);
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { useState } from "react";
import { useToast } from "@/hooks/use-toast";
import { useNavigate } from "react-router-dom";
Expand All @@ -24,6 +23,7 @@ export function useServiceActions(initialServices: Service[]) {
};

const handleViewDetail = (service: Service) => {
console.log(`Navigating to service detail for service ID: ${service.id}`);
navigate(`/service/${service.id}`);
};

Expand Down Expand Up @@ -202,4 +202,4 @@ export function useServiceActions(initialServices: Service[]) {
confirmDelete,
handleMuteAlerts
};
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

import React from "react";
import { Card } from "@/components/ui/card";
import { SSLCertificate } from "@/types/ssl.types";
import { useLanguage } from "@/contexts/LanguageContext";
import { OverviewCard } from "@/components/schedule-incident/common/OverviewCard";
import { Shield, ShieldAlert, ShieldX } from "lucide-react";

interface SSLCertificateStatusCardsProps {
certificates: SSLCertificate[];
Expand All @@ -16,48 +18,30 @@ export const SSLCertificateStatusCards = ({ certificates }: SSLCertificateStatus
const expiredCount = certificates.filter(cert => cert.status === 'expired').length;

return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<Card className="p-6 flex items-center space-x-4">
<div className="bg-green-100 dark:bg-green-900/20 p-3 rounded-full">
<div className="h-12 w-12 rounded-full bg-green-500/20 flex items-center justify-center">
<div className="h-8 w-8 rounded-full bg-green-500 flex items-center justify-center text-white">
</div>
</div>
</div>
<div>
<p className="text-sm font-medium text-muted-foreground">{t('validCertificates')}</p>
<p className="text-3xl font-bold">{validCount}</p>
</div>
</Card>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<OverviewCard
title={t('validCertificates')}
value={validCount}
icon={<Shield className="h-6 w-6 text-white" />}
color="green"
className="hover:scale-105 transition-transform duration-200"
/>

<Card className="p-6 flex items-center space-x-4">
<div className="bg-yellow-100 dark:bg-yellow-900/20 p-3 rounded-full">
<div className="h-12 w-12 rounded-full bg-yellow-500/20 flex items-center justify-center">
<div className="h-8 w-8 rounded-full bg-yellow-500 flex items-center justify-center text-white">
!
</div>
</div>
</div>
<div>
<p className="text-sm font-medium text-muted-foreground">{t('expiringSoon')}</p>
<p className="text-3xl font-bold">{expiringCount}</p>
</div>
</Card>
<OverviewCard
title={t('expiringSoon')}
value={expiringCount}
icon={<ShieldAlert className="h-6 w-6 text-white" />}
color="amber"
className="hover:scale-105 transition-transform duration-200"
/>

<Card className="p-6 flex items-center space-x-4">
<div className="bg-red-100 dark:bg-red-900/20 p-3 rounded-full">
<div className="h-12 w-12 rounded-full bg-red-500/20 flex items-center justify-center">
<div className="h-8 w-8 rounded-full bg-red-500 flex items-center justify-center text-white">
</div>
</div>
</div>
<div>
<p className="text-sm font-medium text-muted-foreground">{t('expired')}</p>
<p className="text-3xl font-bold">{expiredCount}</p>
</div>
</Card>
<OverviewCard
title={t('expired')}
value={expiredCount}
icon={<ShieldX className="h-6 w-6 text-white" />}
color="red"
className="hover:scale-105 transition-transform duration-200"
/>
</div>
);
};
2 changes: 1 addition & 1 deletion application/src/contexts/LanguageContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const LanguageProvider = ({ children }: { children: ReactNode }) => {
}

return key;
git fetch origin };
};

return (
<LanguageContext.Provider value={{ language, setLanguage, t }}>
Expand Down
30 changes: 18 additions & 12 deletions application/src/lib/pocketbase.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import PocketBase from 'pocketbase';

// Auto-detect base URL from browser location
// Dynamically detect API base URL from current host (for use in browser)
const dynamicBaseUrl =
typeof window !== 'undefined'
? window.location.origin
? `${window.location.protocol}//${window.location.hostname}:8090`
: 'http://localhost:8090';

// Define API endpoints
// Define available API endpoints
export const API_ENDPOINTS = {
REMOTE: dynamicBaseUrl
};

// Get the current endpoint from localStorage or use remote as default
export const getCurrentEndpoint = (): string => {
if (typeof window !== 'undefined') {
const savedEndpoint = localStorage.getItem('pocketbase_endpoint');
Expand All @@ -19,19 +20,26 @@ export const getCurrentEndpoint = (): string => {
return API_ENDPOINTS.REMOTE;
};

// Set the API endpoint and reinitialize PocketBase
export const setApiEndpoint = (endpoint: string): void => {
if (typeof window !== 'undefined') {
localStorage.setItem('pocketbase_endpoint', endpoint);
window.location.reload();
window.location.reload(); // Reload to reinitialize PocketBase with new endpoint
}
};

// Initialize the PocketBase client with the current API URL
export const pb = new PocketBase(getCurrentEndpoint());

export const isAuthenticated = () => pb.authStore.isValid;
// Helper to check if user is authenticated
export const isAuthenticated = () => {
return pb.authStore.isValid;
};

// Export the auth store for use in components
export const authStore = pb.authStore;

// Configure PocketBase to persist authentication between page reloads
if (typeof window !== 'undefined') {
const storedAuthData = localStorage.getItem('pocketbase_auth');
if (storedAuthData) {
Expand All @@ -44,15 +52,13 @@ if (typeof window !== 'undefined') {
}
}

// Subscribe to authStore changes to persist authentication
pb.authStore.onChange(() => {
if (pb.authStore.isValid) {
localStorage.setItem(
'pocketbase_auth',
JSON.stringify({
token: pb.authStore.token,
model: pb.authStore.model
})
);
localStorage.setItem('pocketbase_auth', JSON.stringify({
token: pb.authStore.token,
model: pb.authStore.model
}));
} else {
localStorage.removeItem('pocketbase_auth');
}
Expand Down
8 changes: 3 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
version: '3.9'
services:
checkcle:
image: operacle/checkcle:latest
Expand All @@ -6,11 +7,8 @@ services:
ports:
- "8090:8090" # Web Application
volumes:
- pb_data:/app/pb_data # Ensure persistent data across rebuilds
- /opt/pb_data:/mnt/pb_data # Host directory mapped to container path
ulimits:
nofile:
soft: 4096
hard: 8192

volumes:
pb_data: # Docker-managed volume for data persistence
hard: 8192
Loading