@@ -9,11 +9,30 @@ import {
|
||||
} from "react-icons/fi";
|
||||
import { useLogFilterStore, type LogLevel } from "../store/logFilter.store";
|
||||
|
||||
const logLevelColors: Record<LogLevel, { bg: string; text: string; border: string }> = {
|
||||
INFO: { bg: "var(--info-bg)", text: "var(--info-text)", border: "var(--info-border)" },
|
||||
WARNING: { bg: "var(--warning-bg)", text: "var(--warning-text)", border: "var(--warning-border)" },
|
||||
ERROR: { bg: "var(--error-bg)", text: "var(--error-text)", border: "var(--error-border)" },
|
||||
FATAL: { bg: "var(--fatal-bg)", text: "var(--fatal-text)", border: "var(--fatal-border)" },
|
||||
const logLevelColors: Record<
|
||||
LogLevel,
|
||||
{ bg: string; text: string; border: string }
|
||||
> = {
|
||||
INFO: {
|
||||
bg: "var(--info-bg)",
|
||||
text: "var(--info-text)",
|
||||
border: "var(--info-border)",
|
||||
},
|
||||
WARNING: {
|
||||
bg: "var(--warning-bg)",
|
||||
text: "var(--warning-text)",
|
||||
border: "var(--warning-border)",
|
||||
},
|
||||
ERROR: {
|
||||
bg: "var(--error-bg)",
|
||||
text: "var(--error-text)",
|
||||
border: "var(--error-border)",
|
||||
},
|
||||
FATAL: {
|
||||
bg: "var(--fatal-bg)",
|
||||
text: "var(--fatal-text)",
|
||||
border: "var(--fatal-border)",
|
||||
},
|
||||
};
|
||||
|
||||
interface LogFiltersProps {
|
||||
@@ -22,7 +41,11 @@ interface LogFiltersProps {
|
||||
availableAgents: string[];
|
||||
}
|
||||
|
||||
export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServices, availableAgents }) => {
|
||||
export const LogFilters: React.FC<LogFiltersProps> = ({
|
||||
onApply,
|
||||
availableServices,
|
||||
availableAgents,
|
||||
}) => {
|
||||
const {
|
||||
searchQuery,
|
||||
startDate,
|
||||
@@ -72,7 +95,14 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
setSelectedService(localService);
|
||||
setSelectedAgent(localAgent);
|
||||
onApply();
|
||||
}, [localSearchQuery, localStartDate, localEndDate, localService, localAgent, onApply]);
|
||||
}, [
|
||||
localSearchQuery,
|
||||
localStartDate,
|
||||
localEndDate,
|
||||
localService,
|
||||
localAgent,
|
||||
onApply,
|
||||
]);
|
||||
|
||||
const handleReset = useCallback(() => {
|
||||
setLocalSearchQuery("");
|
||||
@@ -130,7 +160,10 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<FiFilter size={14} style={{ color: "var(--accent)" }} />
|
||||
<h3 className="text-sm font-semibold" style={{ color: "var(--text-primary)" }}>
|
||||
<h3
|
||||
className="text-sm font-semibold"
|
||||
style={{ color: "var(--text-primary)" }}
|
||||
>
|
||||
Фильтры логов
|
||||
</h3>
|
||||
</div>
|
||||
@@ -140,7 +173,7 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
</div>
|
||||
|
||||
{/* Filters Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
<FiSearch
|
||||
@@ -195,17 +228,31 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={localStartDate ? localStartDate.toISOString().split("T")[0] : ""}
|
||||
onChange={(e) => setLocalStartDate(e.target.value ? new Date(e.target.value) : null)}
|
||||
style={inputStyle}
|
||||
value={
|
||||
localStartDate ? localStartDate.toISOString().split("T")[0] : ""
|
||||
}
|
||||
onChange={(e) =>
|
||||
setLocalStartDate(
|
||||
e.target.value ? new Date(e.target.value) : null,
|
||||
)
|
||||
}
|
||||
style={{ ...inputStyle, minWidth: 0 }}
|
||||
placeholder="Дата от"
|
||||
className="flex-1 min-w-0"
|
||||
/>
|
||||
<input
|
||||
type="date"
|
||||
value={localEndDate ? localEndDate.toISOString().split("T")[0] : ""}
|
||||
onChange={(e) => setLocalEndDate(e.target.value ? new Date(e.target.value) : null)}
|
||||
style={inputStyle}
|
||||
value={
|
||||
localEndDate ? localEndDate.toISOString().split("T")[0] : ""
|
||||
}
|
||||
onChange={(e) =>
|
||||
setLocalEndDate(
|
||||
e.target.value ? new Date(e.target.value) : null,
|
||||
)
|
||||
}
|
||||
style={{ ...inputStyle, minWidth: 0 }}
|
||||
placeholder="Дата до"
|
||||
className="flex-1 min-w-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,7 +261,10 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<FiTag size={12} style={{ color: "var(--text-secondary)" }} />
|
||||
<span className="text-xs font-medium" style={{ color: "var(--text-secondary)" }}>
|
||||
<span
|
||||
className="text-xs font-medium"
|
||||
style={{ color: "var(--text-secondary)" }}
|
||||
>
|
||||
Уровни логов
|
||||
</span>
|
||||
<span className="text-xs" style={{ color: "var(--text-muted)" }}>
|
||||
@@ -222,36 +272,42 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["INFO", "WARNING", "ERROR", "FATAL"] as LogLevel[]).map((level) => {
|
||||
const isSelected = selectedLogLevels.includes(level);
|
||||
const colors = logLevelColors[level];
|
||||
return (
|
||||
<button
|
||||
key={level}
|
||||
onClick={() => toggleLogLevel(level)}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium transition-all border"
|
||||
style={{
|
||||
backgroundColor: isSelected ? colors.bg : "transparent",
|
||||
color: isSelected ? colors.text : "var(--text-secondary)",
|
||||
borderColor: isSelected ? colors.border : "var(--border)",
|
||||
}}
|
||||
>
|
||||
{isSelected && <FiCheck size={10} className="inline mr-1" />}
|
||||
{level}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
{(["INFO", "WARNING", "ERROR", "FATAL"] as LogLevel[]).map(
|
||||
(level) => {
|
||||
const isSelected = selectedLogLevels.includes(level);
|
||||
const colors = logLevelColors[level];
|
||||
return (
|
||||
<button
|
||||
key={level}
|
||||
onClick={() => toggleLogLevel(level)}
|
||||
className="px-3 py-2 rounded-lg text-xs font-medium transition-all border flex-shrink-0"
|
||||
style={{
|
||||
backgroundColor: isSelected ? colors.bg : "transparent",
|
||||
color: isSelected ? colors.text : "var(--text-secondary)",
|
||||
borderColor: isSelected ? colors.border : "var(--border)",
|
||||
minHeight: "36px",
|
||||
}}
|
||||
>
|
||||
{isSelected && (
|
||||
<FiCheck size={10} className="inline mr-1" />
|
||||
)}
|
||||
{level}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<button
|
||||
onClick={handleApply}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 rounded-lg transition-all text-sm font-medium"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg transition-all text-sm font-medium"
|
||||
style={{
|
||||
backgroundColor: "var(--button-primary)",
|
||||
color: "var(--button-primary-text)",
|
||||
minHeight: "44px",
|
||||
}}
|
||||
>
|
||||
<FiCheck size={14} />
|
||||
@@ -259,23 +315,31 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
</button>
|
||||
<button
|
||||
onClick={handleReset}
|
||||
className="px-4 py-2 rounded-lg transition-all text-sm font-medium border"
|
||||
className="flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg transition-all text-sm font-medium border"
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
color: "var(--text-secondary)",
|
||||
borderColor: "var(--border)",
|
||||
minHeight: "44px",
|
||||
}}
|
||||
>
|
||||
<FiX size={14} />
|
||||
Сбросить
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Active Filters Display */}
|
||||
{activeFiltersCount > 0 && (
|
||||
<div className="mt-4 pt-4 border-t" style={{ borderColor: "var(--border)" }}>
|
||||
<div
|
||||
className="mt-4 pt-4 border-t"
|
||||
style={{ borderColor: "var(--border)" }}
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<FiFilter size={10} style={{ color: "var(--accent)" }} />
|
||||
<span className="text-xs" style={{ color: "var(--text-secondary)" }}>
|
||||
<span
|
||||
className="text-xs"
|
||||
style={{ color: "var(--text-secondary)" }}
|
||||
>
|
||||
Активные фильтры:
|
||||
</span>
|
||||
</div>
|
||||
@@ -289,14 +353,21 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
}}
|
||||
>
|
||||
<FiSearch size={10} />
|
||||
<span style={{ color: "var(--text-primary)" }}>Поиск: {searchQuery}</span>
|
||||
<span style={{ color: "var(--text-primary)" }}>
|
||||
Поиск: {searchQuery}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setLocalSearchQuery("");
|
||||
setSearchQuery("");
|
||||
onApply();
|
||||
}}
|
||||
style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)" }}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
<FiX size={10} />
|
||||
</button>
|
||||
@@ -311,14 +382,21 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
}}
|
||||
>
|
||||
<FiTag size={10} />
|
||||
<span style={{ color: "var(--text-primary)" }}>Сервис: {selectedService}</span>
|
||||
<span style={{ color: "var(--text-primary)" }}>
|
||||
Сервис: {selectedService}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setLocalService("");
|
||||
setSelectedService("");
|
||||
onApply();
|
||||
}}
|
||||
style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)" }}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
<FiX size={10} />
|
||||
</button>
|
||||
@@ -333,14 +411,21 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
}}
|
||||
>
|
||||
<FiTag size={10} />
|
||||
<span style={{ color: "var(--text-primary)" }}>Агент: {selectedAgent}</span>
|
||||
<span style={{ color: "var(--text-primary)" }}>
|
||||
Агент: {selectedAgent}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setLocalAgent("");
|
||||
setSelectedAgent("");
|
||||
onApply();
|
||||
}}
|
||||
style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)" }}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
<FiX size={10} />
|
||||
</button>
|
||||
@@ -355,14 +440,21 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
}}
|
||||
>
|
||||
<FiCalendar size={10} />
|
||||
<span style={{ color: "var(--text-primary)" }}>С: {formatDate(startDate)}</span>
|
||||
<span style={{ color: "var(--text-primary)" }}>
|
||||
С: {formatDate(startDate)}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setLocalStartDate(null);
|
||||
setStartDate(null);
|
||||
onApply();
|
||||
}}
|
||||
style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)" }}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
<FiX size={10} />
|
||||
</button>
|
||||
@@ -377,14 +469,21 @@ export const LogFilters: React.FC<LogFiltersProps> = ({ onApply, availableServic
|
||||
}}
|
||||
>
|
||||
<FiCalendar size={10} />
|
||||
<span style={{ color: "var(--text-primary)" }}>По: {formatDate(endDate)}</span>
|
||||
<span style={{ color: "var(--text-primary)" }}>
|
||||
По: {formatDate(endDate)}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setLocalEndDate(null);
|
||||
setEndDate(null);
|
||||
onApply();
|
||||
}}
|
||||
style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)" }}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "var(--text-muted)",
|
||||
}}
|
||||
>
|
||||
<FiX size={10} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user