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