mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor: update styles and layout for log viewer components
This commit is contained in:
@@ -54,14 +54,14 @@ const CopyTextButton: FunctionComponent<ComponentProps> = (
|
||||
|
||||
const variantClasses: Record<typeof variant, string> = {
|
||||
ghost:
|
||||
"bg-transparent border border-slate-600 text-slate-300 hover:bg-slate-700/40",
|
||||
soft: "bg-slate-700 text-white border border-slate-600 hover:bg-slate-600",
|
||||
"bg-transparent border border-gray-200 text-gray-400 hover:bg-gray-50 hover:text-gray-600",
|
||||
soft: "bg-gray-100 text-gray-600 border border-gray-200 hover:bg-gray-200",
|
||||
solid:
|
||||
"bg-indigo-600 text-white border border-indigo-600 hover:bg-indigo-500",
|
||||
} as const;
|
||||
|
||||
const copiedClasses: string =
|
||||
"bg-emerald-600/20 border border-emerald-500 text-emerald-300";
|
||||
"bg-emerald-50 border border-emerald-200 text-emerald-600";
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -427,7 +427,7 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
||||
props.showFacetSidebar !== false && !!props.facetData;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
{props.showFilters && (
|
||||
<div>
|
||||
<LogsFilterCard
|
||||
@@ -476,7 +476,7 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
||||
)}
|
||||
|
||||
{/* Main content: sidebar + table */}
|
||||
<div className="flex gap-4">
|
||||
<div className="flex gap-3">
|
||||
{showSidebar && props.facetData && (
|
||||
<LogsFacetSidebar
|
||||
facetData={props.facetData}
|
||||
|
||||
@@ -38,7 +38,7 @@ const FacetSection: FunctionComponent<FacetSectionProps> = (
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div className="border-b border-gray-100 py-2.5">
|
||||
<div className="border-b border-gray-100 py-2">
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between px-2 py-1 text-left"
|
||||
|
||||
@@ -42,7 +42,7 @@ const FacetValueRow: FunctionComponent<FacetValueRowProps> = (
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="w-14">
|
||||
<div className="w-12">
|
||||
<div className="h-1.5 w-full rounded-full bg-gray-100">
|
||||
<div
|
||||
className="h-1.5 rounded-full opacity-70 transition-all"
|
||||
@@ -53,7 +53,7 @@ const FacetValueRow: FunctionComponent<FacetValueRowProps> = (
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span className="min-w-[2.5rem] text-right font-mono text-[11px] text-gray-400">
|
||||
<span className="min-w-[2rem] text-right font-mono text-[10px] tabular-nums text-gray-400">
|
||||
{props.count.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -106,7 +106,7 @@ const LogsFacetSidebar: FunctionComponent<LogsFacetSidebarProps> = (
|
||||
}, [props.facetData]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-52 flex-none flex-col overflow-y-auto rounded-lg border border-gray-200 bg-white">
|
||||
<div className="flex h-full w-56 flex-none flex-col overflow-y-auto rounded-lg border border-gray-200 bg-white">
|
||||
<div className="border-b border-gray-100 px-3 py-2.5">
|
||||
<h3 className="text-[11px] font-semibold uppercase tracking-widest text-gray-400">
|
||||
Filters
|
||||
|
||||
@@ -33,9 +33,9 @@ const LogsFilterCard: FunctionComponent<LogsFilterCardProps> = (
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-200 bg-white shadow-sm">
|
||||
<div className="p-4">
|
||||
<div className="mb-3">
|
||||
<div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<LogSearchBar
|
||||
value={props.searchQuery}
|
||||
onChange={props.onSearchQueryChange}
|
||||
@@ -43,45 +43,44 @@ const LogsFilterCard: FunctionComponent<LogsFilterCardProps> = (
|
||||
suggestions={searchBarSuggestions}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FiltersForm<Log>
|
||||
id="logs-filter"
|
||||
showFilter={true}
|
||||
filterData={props.filterData}
|
||||
onFilterChanged={props.onFilterChanged}
|
||||
onAdvancedFiltersToggle={props.onAdvancedFiltersToggle}
|
||||
isFilterLoading={props.isFilterLoading}
|
||||
filterError={props.filterError}
|
||||
onFilterRefreshClick={props.onFilterRefreshClick}
|
||||
filters={[
|
||||
{
|
||||
key: "severityText",
|
||||
filterDropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(LogSeverity),
|
||||
type: FieldType.Dropdown,
|
||||
title: "Log Severity",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "time",
|
||||
type: FieldType.DateTime,
|
||||
title: "Start and End Date",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "attributes",
|
||||
type: FieldType.JSON,
|
||||
title: "Filter by Attributes",
|
||||
jsonKeys: props.logAttributes,
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="flex-none pt-0.5">
|
||||
{props.toolbar}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-100 bg-gray-50/50 px-4 py-2.5">
|
||||
{props.toolbar}
|
||||
</div>
|
||||
<FiltersForm<Log>
|
||||
id="logs-filter"
|
||||
showFilter={true}
|
||||
filterData={props.filterData}
|
||||
onFilterChanged={props.onFilterChanged}
|
||||
onAdvancedFiltersToggle={props.onAdvancedFiltersToggle}
|
||||
isFilterLoading={props.isFilterLoading}
|
||||
filterError={props.filterError}
|
||||
onFilterRefreshClick={props.onFilterRefreshClick}
|
||||
filters={[
|
||||
{
|
||||
key: "severityText",
|
||||
filterDropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(LogSeverity),
|
||||
type: FieldType.Dropdown,
|
||||
title: "Log Severity",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "time",
|
||||
type: FieldType.DateTime,
|
||||
title: "Start and End Date",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "attributes",
|
||||
type: FieldType.JSON,
|
||||
title: "Filter by Attributes",
|
||||
jsonKeys: props.logAttributes,
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -145,7 +145,7 @@ const LogsHistogram: FunctionComponent<LogsHistogramProps> = (
|
||||
|
||||
if (props.isLoading && pivotedData.length === 0) {
|
||||
return (
|
||||
<div className="flex h-20 items-center justify-center rounded-lg border border-gray-100 bg-white">
|
||||
<div className="flex h-16 items-center justify-center bg-white">
|
||||
<ComponentLoader />
|
||||
</div>
|
||||
);
|
||||
@@ -156,8 +156,8 @@ const LogsHistogram: FunctionComponent<LogsHistogramProps> = (
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-100 bg-white px-2 pb-1 pt-3">
|
||||
<div className="h-20">
|
||||
<div className="bg-white px-2 pb-0 pt-2">
|
||||
<div className="h-16">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={pivotedData}
|
||||
@@ -165,7 +165,7 @@ const LogsHistogram: FunctionComponent<LogsHistogramProps> = (
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
barCategoryGap="12%"
|
||||
barCategoryGap="15%"
|
||||
>
|
||||
<XAxis
|
||||
dataKey="time"
|
||||
@@ -192,7 +192,7 @@ const LogsHistogram: FunctionComponent<LogsHistogramProps> = (
|
||||
dataKey={severity}
|
||||
stackId="severity"
|
||||
fill={getSeverityColor(severity).fill}
|
||||
radius={[1, 1, 0, 0]}
|
||||
radius={[3, 3, 0, 0]}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -6,6 +6,7 @@ import OneUptimeDate from "../../../../Types/Date";
|
||||
import CopyTextButton from "../../CopyTextButton/CopyTextButton";
|
||||
import ComponentLoader from "../../ComponentLoader/ComponentLoader";
|
||||
import SeverityBadge from "./SeverityBadge";
|
||||
import { getSeverityTheme, SeverityTheme } from "./severityTheme";
|
||||
import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
|
||||
import Icon from "../../Icon/Icon";
|
||||
import IconProp from "../../../../Types/Icon/IconProp";
|
||||
@@ -114,7 +115,7 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
</button>
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Service
|
||||
<span>Service</span>
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
<button
|
||||
@@ -162,6 +163,9 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
const spanId: string = log.spanId?.toString() || "";
|
||||
|
||||
const isSelected: boolean = props.selectedLogId === rowId;
|
||||
const severityTheme: SeverityTheme = getSeverityTheme(
|
||||
log.severityText,
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment key={rowId}>
|
||||
@@ -169,7 +173,7 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
onClick={() => {
|
||||
props.onRowClick(log, rowId);
|
||||
}}
|
||||
className={`group cursor-pointer align-top transition-colors hover:bg-gray-50/70 ${
|
||||
className={`group cursor-pointer align-top transition-colors hover:bg-gray-50/70 border-l-[3px] ${severityTheme.borderClass} ${
|
||||
isSelected
|
||||
? "bg-indigo-50/50 ring-1 ring-inset ring-indigo-200"
|
||||
: ""
|
||||
@@ -177,14 +181,14 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
aria-selected={isSelected}
|
||||
aria-expanded={isSelected}
|
||||
>
|
||||
<td className="whitespace-nowrap px-4 py-2.5 text-[13px] font-mono text-gray-600">
|
||||
<td className="whitespace-nowrap px-4 py-2 text-[13px] font-mono text-gray-600">
|
||||
{log.time
|
||||
? OneUptimeDate.getDateAsUserFriendlyFormattedString(
|
||||
log.time,
|
||||
)
|
||||
: "-"}
|
||||
</td>
|
||||
<td className="px-4 py-2.5">
|
||||
<td className="px-4 py-2">
|
||||
<div className="flex items-center gap-3 text-sm text-gray-700">
|
||||
<span
|
||||
className="h-2.5 w-2.5 flex-none rounded-full shadow-sm"
|
||||
@@ -196,10 +200,10 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-2.5">
|
||||
<td className="px-4 py-2">
|
||||
<SeverityBadge severity={log.severityText} />
|
||||
</td>
|
||||
<td className="px-4 py-2.5">
|
||||
<td className="px-4 py-2">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
||||
<p
|
||||
@@ -221,6 +225,7 @@ const LogsTable: FunctionComponent<LogsTableProps> = (
|
||||
variant="ghost"
|
||||
iconOnly={true}
|
||||
title="Copy log message"
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -271,13 +271,6 @@ These changes directly improve the daily log investigation experience for every
|
||||
|
||||
## Phase 4: Advanced Features (P3) — Differentiation
|
||||
|
||||
### 4.1 Log Patterns (ML Clustering)
|
||||
|
||||
- Implement a clustering algorithm that groups logs by message structure
|
||||
- Replace variable parts (IPs, UUIDs, numbers) with wildcards
|
||||
- Show pattern frequency over time with sparklines
|
||||
- Enable creating alerts directly from a pattern
|
||||
- This is a significant backend feature requiring a background job that periodically clusters recent logs
|
||||
|
||||
### 4.2 Keyboard Shortcuts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user