This commit is contained in:
meninjar
2026-08-06 06:14:47 +00:00
parent afb0d434bf
commit ead79d212e
3 changed files with 41 additions and 31 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ services:
volumes: volumes:
- .:/app - .:/app
- /app/node_modules - /app/node_modules
- /mnt/simrs/logs:/app/logs - /mnt/simrs-dev/logs:/app/logs
# ─── Production ──────────────────────────── # ─── Production ────────────────────────────
prod: prod:
+1 -1
View File
@@ -307,7 +307,7 @@ export function App() {
<FilterToolbar <FilterToolbar
filters={filters} filters={filters}
backups={backups} backups={backups}
onChange={(updated) => setFilters((prev) => ({ ...prev, ...updated }))} onApply={(applied) => setFilters(applied)}
onReset={() => onReset={() =>
setFilters({ setFilters({
source: 'auto', source: 'auto',
+39 -29
View File
@@ -1,33 +1,43 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import { Database, Calendar, Clock, Layers, AlertCircle, Search, Filter, RotateCcw } from 'lucide-react'; import { Database, Calendar, Clock, Layers, AlertCircle, Search, Filter, RotateCcw } from 'lucide-react';
import { FilterState, BackupFile } from '../types'; import { FilterState, BackupFile } from '../types';
interface FilterToolbarProps { interface FilterToolbarProps {
filters: FilterState; filters: FilterState;
backups: BackupFile[]; backups: BackupFile[];
onChange: (updated: Partial<FilterState>) => void; onApply: (applied: FilterState) => void;
onReset: () => void; onReset: () => void;
} }
export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups, onChange, onReset }) => { export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups, onApply, onReset }) => {
const [localFilters, setLocalFilters] = useState<FilterState>(filters);
// Sync local filters if parent filters change externally (e.g., Reset or selecting backup ZIP file)
useEffect(() => {
setLocalFilters(filters);
}, [filters]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onApply({ ...localFilters, page: 1 });
};
const handleLocalChange = (updated: Partial<FilterState>) => {
setLocalFilters((prev) => ({ ...prev, ...updated }));
};
return ( return (
<div className="glass-card p-4 rounded-xl mb-6"> <div className="glass-card p-4 rounded-xl mb-6">
<form <form onSubmit={handleSubmit} className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-7 gap-3 items-end">
onSubmit={(e) => {
e.preventDefault();
onChange({ page: 1 });
}}
className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-7 gap-3 items-end"
>
{/* Sumber Log */} {/* Sumber Log */}
<div> <div>
<label className="block text-[11px] font-semibold text-slate-400 mb-1 flex items-center gap-1"> <label className="block text-[11px] font-semibold text-slate-400 mb-1 flex items-center gap-1">
<Database className="w-3.5 h-3.5 text-cyan-400" /> Sumber Log <Database className="w-3.5 h-3.5 text-cyan-400" /> Sumber Log
</label> </label>
<select <select
value={filters.source} value={localFilters.source}
onChange={(e) => onChange({ source: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ source: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none cursor-pointer"
> >
<option value="auto"> Auto (Aktif + ZIP)</option> <option value="auto"> Auto (Aktif + ZIP)</option>
<option value="active">📁 Log Aktif</option> <option value="active">📁 Log Aktif</option>
@@ -51,9 +61,9 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
</label> </label>
<input <input
type="date" type="date"
value={filters.date} value={localFilters.date}
onChange={(e) => onChange({ date: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ date: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none cursor-pointer"
/> />
</div> </div>
@@ -65,15 +75,15 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<input <input
type="time" type="time"
value={filters.time_start} value={localFilters.time_start}
onChange={(e) => onChange({ time_start: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ time_start: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-1.5 py-1.5 text-[11px] text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-1.5 py-1.5 text-[11px] text-white focus:border-cyan-500 outline-none"
/> />
<span className="text-slate-500 text-xs">-</span> <span className="text-slate-500 text-xs">-</span>
<input <input
type="time" type="time"
value={filters.time_end} value={localFilters.time_end}
onChange={(e) => onChange({ time_end: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ time_end: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-1.5 py-1.5 text-[11px] text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-1.5 py-1.5 text-[11px] text-white focus:border-cyan-500 outline-none"
/> />
</div> </div>
@@ -85,9 +95,9 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
<Layers className="w-3.5 h-3.5 text-cyan-400" /> Channel <Layers className="w-3.5 h-3.5 text-cyan-400" /> Channel
</label> </label>
<select <select
value={filters.channel} value={localFilters.channel}
onChange={(e) => onChange({ channel: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ channel: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none cursor-pointer"
> >
<option value="all">-- Semua Channel --</option> <option value="all">-- Semua Channel --</option>
<option value="session">Session Lifecycle</option> <option value="session">Session Lifecycle</option>
@@ -107,9 +117,9 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
<AlertCircle className="w-3.5 h-3.5 text-cyan-400" /> Level <AlertCircle className="w-3.5 h-3.5 text-cyan-400" /> Level
</label> </label>
<select <select
value={filters.level} value={localFilters.level}
onChange={(e) => onChange({ level: e.target.value, page: 1 })} onChange={(e) => handleLocalChange({ level: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2 py-1.5 text-xs text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2 py-1.5 text-xs text-white focus:border-cyan-500 outline-none cursor-pointer"
> >
<option value="all">Semua</option> <option value="all">Semua</option>
<option value="DEBUG">DEBUG</option> <option value="DEBUG">DEBUG</option>
@@ -128,8 +138,8 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
<input <input
type="text" type="text"
placeholder="NIP, URI, IP, Pesan..." placeholder="NIP, URI, IP, Pesan..."
value={filters.search} value={localFilters.search}
onChange={(e) => onChange({ search: e.target.value })} onChange={(e) => handleLocalChange({ search: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none" className="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-xs text-white focus:border-cyan-500 outline-none"
/> />
</div> </div>
@@ -138,7 +148,7 @@ export const FilterToolbar: React.FC<FilterToolbarProps> = ({ filters, backups,
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<button <button
type="submit" type="submit"
className="flex-1 py-1.5 px-3 rounded-lg bg-teal-600 hover:bg-teal-500 text-white font-semibold text-xs flex items-center justify-center gap-1 transition-colors cursor-pointer" className="flex-1 py-1.5 px-3 rounded-lg bg-teal-600 hover:bg-teal-500 text-white font-semibold text-xs flex items-center justify-center gap-1 transition-colors cursor-pointer shadow-lg shadow-teal-900/30"
> >
<Filter className="w-3.5 h-3.5" /> <Filter className="w-3.5 h-3.5" />
Filter Filter