Merge pull request #22 from operacle/develop

feat: release maintenance and incident management features; apply hotfixes
This commit is contained in:
Tola Leng
2025-05-26 21:57:45 +07:00
committed by GitHub
11 changed files with 85 additions and 136 deletions
+3 -1
View File
@@ -21,4 +21,6 @@ dist-ssr
*.ntvs*
*.njsproj
*.sln
*.sw?
*.sw?
application/src/lib/pocketbase.ts
Dockerfile
-39
View File
@@ -1,39 +0,0 @@
# Stage 1: Build the frontend
FROM node:18-alpine AS frontend-builder
WORKDIR /app
COPY application/package*.json ./
RUN npm install
COPY application/ ./
RUN npm run build
# Stage 2: Download PocketBase binary
FROM alpine:3.17 AS pb-builder
WORKDIR /pb
ARG PB_VERSION=0.27.2
RUN apk add --no-cache wget unzip \
&& wget https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip \
&& unzip pocketbase_${PB_VERSION}_linux_amd64.zip \
&& chmod +x /pb/pocketbase
# Stage 3: Final runtime image
FROM alpine:3.17
WORKDIR /app
# Copy PocketBase binary
COPY --from=pb-builder /pb/pocketbase /app/pocketbase
# Copy frontend build to PocketBase public directory
COPY --from=frontend-builder /app/dist /app/pb_public
# Copy backend files
COPY server/pb_migrations /app/pb_migrations
COPY server/pb_data /app/pb_data
# Mark pb_data as a volume for runtime persistence
VOLUME /app/pb_data
# Expose default PocketBase port
EXPOSE 8090
# Launch PocketBase and bind to 0.0.0.0 for external access
CMD ["/app/pocketbase", "serve", "--http=0.0.0.0:8090", "--dir", "/app/pb_data"]
+18 -18
View File
@@ -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
@@ -48,15 +49,12 @@ 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
@@ -64,12 +62,12 @@ volumes:
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
@@ -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
@@ -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)
@@ -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}
@@ -77,4 +77,4 @@ export const ServiceRow = ({
</TableCell>
</TableRow>
);
};
};
@@ -1,4 +1,3 @@
import { useState } from "react";
import { useToast } from "@/hooks/use-toast";
import { useNavigate } from "react-router-dom";
@@ -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}`);
};
@@ -202,4 +202,4 @@ export function useServiceActions(initialServices: Service[]) {
confirmDelete,
handleMuteAlerts
};
}
}
@@ -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[];
@@ -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>
);
};
+1 -1
View File
@@ -37,7 +37,7 @@ export const LanguageProvider = ({ children }: { children: ReactNode }) => {
}
return key;
git fetch origin };
};
return (
<LanguageContext.Provider value={{ language, setLanguage, t }}>
+18 -12
View File
@@ -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');
@@ -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) {
@@ -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');
}
+3 -5
View File
@@ -1,3 +1,4 @@
version: '3.9'
services:
checkcle:
image: operacle/checkcle:latest
@@ -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
+4 -5
View File
@@ -1,3 +1,5 @@
version: '3.9'
services:
checkcle:
build:
@@ -6,13 +8,10 @@ services:
container_name: checkcle
restart: unless-stopped
ports:
- "8090:8090" # Allow access to frontend + PocketBase
- "8090:8090"
volumes:
- pb_data:/app/pb_data # Ensure persistent data across rebuilds
- /var/pb_data:/mnt/pb_data # Updated mount target to match CMD in Dockerfile
ulimits:
nofile:
soft: 4096
hard: 8192
volumes:
pb_data: # Docker-managed volume for persistence
+4 -5
View File
@@ -1,3 +1,5 @@
version: '3.9'
services:
checkcle:
image: operacle/checkcle:latest
@@ -6,11 +8,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