Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/local-ui/src/shell/filter-drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const cloneNode = (node: VNode): VNode => ({
export const filterRailOf = (model: Model, page: Html): Option.Option<LiftedRail> =>
model.filterDrawer.isOpen
? Option.map(splitPageRails(page).maybeFilters, (rail) => ({
...rail,
children: rail.children.map((child) => (child === null ? child : cloneNode(child))),
}))
: Option.none()
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/page/agent-sessions/list/view-filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Option } from "effect"
import { AsyncData } from "foldkit"
import type { Html, HtmlBuilder } from "foldkit/html"
import * as Checkbox from "../../../ui/checkbox"
import { separator } from "../../../ui/display"
import { filterDescriptionMark, filterSection } from "../../../ui/filters/filter-section"
import {
filterSidebarBody,
Expand All @@ -13,6 +12,7 @@ import {
filterSidebarFrame,
filterSidebarHeader,
filterSidebarLoading,
filterSidebarDivider,
} from "../../../ui/filters/filter-sidebar"
import { percentilePresets, toLogBuckets } from "../../../ui/filters/range-distribution"
import { type RangePreset, rangeFilterSection } from "../../../ui/filters/range-filter-section"
Expand Down Expand Up @@ -175,7 +175,7 @@ const singleCheckbox = (h: H, title: string, isChecked: boolean, onToggle: Messa
h,
{
className:
"flex-1 min-w-0 flex items-center gap-1.5 cursor-pointer text-xs text-foreground font-normal",
"flex-1 min-w-0 flex items-center gap-1.5 cursor-pointer text-xs text-foreground font-normal sm:text-xs",
attributes: [h.For(inputId), h.Id(Checkbox.labelId(inputId)), h.Title(title)],
},
[h.span([h.Class("truncate")], [title]), filterDescriptionMark(h, title)],
Expand Down Expand Up @@ -237,9 +237,9 @@ const loadedRail = (h: H, model: Model, facets: Facets): Html => {
{ title: "Environment", facet: "environments", isSearchable: false, hasDescription: false },
facets.environments,
),
separator(h, "horizontal", "my-2"),
filterSidebarDivider(h),
...RANGES.map((spec) => rangeSection(h, model, distributions, spec)),
separator(h, "horizontal", "my-2"),
filterSidebarDivider(h),
singleCheckbox(
h,
"Hide single-trace sessions",
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/page/analytics/view-filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { countryLabel, languageLabel, referrerLabel, utmLabel } from "../../comp
import { Option } from "effect"
import { AsyncData } from "foldkit"
import type { Html, HtmlBuilder } from "foldkit/html"
import { separator } from "../../ui/display"
import { eyebrow } from "../../ui/eyebrow"
import { type FilterOption, filterSection, singleCheckboxFilter } from "../../ui/filters/filter-section"
import * as FilterSections from "../../ui/filters/filter-sections"
import {
Expand All @@ -15,6 +13,8 @@ import {
filterSidebarFrame,
filterSidebarHeader,
filterSidebarLoading,
filterSidebarDivider,
filterSidebarGroupLabel,
} from "../../ui/filters/filter-sidebar"
import { icon, type IconName } from "../../ui/icon"
import { browserIconFor, deviceIconFor } from "../replays/kit/sessions-parts"
Expand Down Expand Up @@ -58,7 +58,7 @@ const section = (
}

const checkboxGroup = (h: H, title: string, children: ReadonlyArray<Html>): Html =>
h.div([h.Class("py-1")], [eyebrow(h, { as: "h4", variant: "label", className: "py-1" }, [title]), ...children])
h.div([h.Class("pb-3")], [filterSidebarGroupLabel(h, title), ...children])

const loadedRail = (h: H, model: Model, breakdowns: Breakdowns): Html => {
const filters = filtersOf(model.search)
Expand All @@ -85,7 +85,7 @@ const loadedRail = (h: H, model: Model, breakdowns: Breakdowns): Html => {
onToggle: Message.ToggledTraffic({ which: "bots", isOn: !trafficIncludes(filters.traffic, "bots") }),
}),
]),
separator(h, "horizontal", "my-1"),
filterSidebarDivider(h),
section(h, model, "host", breakdowns.hosts, { renderOptionIcon: hostIcon }),
section(h, model, "pagePath", breakdowns.entryPaths),
events.length > 0 || filters.eventName !== undefined
Expand All @@ -96,7 +96,7 @@ const loadedRail = (h: H, model: Model, breakdowns: Breakdowns): Html => {
events.map((event) => ({ name: event.name, count: event.sessions })),
)
: null,
separator(h, "horizontal", "my-1"),
filterSidebarDivider(h),
section(h, model, "referrerHost", breakdowns.referrerHosts, {
getOptionLabel: referrerLabel,
renderOptionIcon: (name) =>
Expand All @@ -110,7 +110,7 @@ const loadedRail = (h: H, model: Model, breakdowns: Breakdowns): Html => {
}),
section(h, model, "utmMedium", breakdowns.utmMediums, { isSearchable: false, getOptionLabel: utmLabel }),
section(h, model, "utmCampaign", breakdowns.utmCampaigns, { getOptionLabel: utmLabel }),
separator(h, "horizontal", "my-1"),
filterSidebarDivider(h),
checkboxGroup(h, FILTER_SECTION_LABEL.visitorType, [
singleCheckboxFilter(h, {
title: "New",
Expand All @@ -128,7 +128,7 @@ const loadedRail = (h: H, model: Model, breakdowns: Breakdowns): Html => {
]),
section(h, model, "country", breakdowns.countries, { getOptionLabel: countryLabel }),
section(h, model, "language", breakdowns.languages, { getOptionLabel: languageLabel }),
separator(h, "horizontal", "my-1"),
filterSidebarDivider(h),
section(h, model, "deviceType", breakdowns.deviceTypes, { isSearchable: false, getOptionIcon: deviceIconFor }),
section(h, model, "browserName", breakdowns.browsers, { isSearchable: false, getOptionIcon: browserIconFor }),
section(h, model, "osName", breakdowns.operatingSystems, { isSearchable: false }),
Expand Down
96 changes: 77 additions & 19 deletions apps/web/src/page/anomalies/detail/view-sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ import { Message } from "./message"

type H = HtmlBuilder<Message>

export type SidebarInput = Readonly<{ incident: AnomalyIncidentDocument; isBusy: boolean; nowMs: number; timeZone: string }>
export type SidebarInput = Readonly<{
incident: AnomalyIncidentDocument
isBusy: boolean
nowMs: number
timeZone: string
}>

const row = (h: H, label: string, children: ReadonlyArray<Html | string>, title?: string): Html =>
detailRailRow(h, { label, title }, children)
Expand All @@ -48,7 +53,7 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
const time = (value: string, className?: string) =>
relativeTime(h, { value, nowMs: input.nowMs, timeZone: input.timeZone, tooltip: "title", className })
return h.div(
[h.Class("flex h-full w-72 shrink-0 flex-col overflow-y-auto border-l bg-card/30")],
[h.Class("flex flex-col")],
[
detailRailGroup(h, "Actions", [
...(isOpen
Expand Down Expand Up @@ -95,11 +100,21 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
h.span(
[h.Class("text-right text-sm text-foreground")],
isStale
? ["stale · ", relativeTime(h, { value: incident.lastTriggeredAt, nowMs: input.nowMs, timeZone: input.timeZone, prefix: "last seen" })]
? [
"stale · ",
relativeTime(h, {
value: incident.lastTriggeredAt,
nowMs: input.nowMs,
timeZone: input.timeZone,
prefix: "last seen",
}),
]
: [isOpen ? "open" : "resolved"],
),
]),
row(h, "Signal", [h.span([h.Class("text-sm text-foreground")], [SIGNAL_LABEL[incident.signalType]])]),
row(h, "Signal", [
h.span([h.Class("text-sm text-foreground")], [SIGNAL_LABEL[incident.signalType]]),
]),
row(h, "Severity", [
h.span(
[h.Class(cn("text-sm font-medium", live ? tone.text : "text-muted-foreground"))],
Expand All @@ -120,11 +135,18 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
],
incident.serviceName,
),
row(h, "Environment", [h.span([h.Class("text-sm text-foreground")], [incident.deploymentEnv || EMPTY_VALUE])]),
row(h, "Environment", [
h.span([h.Class("text-sm text-foreground")], [incident.deploymentEnv || EMPTY_VALUE]),
]),
row(
h,
"Detector",
[h.code([h.Class("block max-w-full truncate font-mono text-xs text-muted-foreground")], [incident.detectorKey])],
[
h.code(
[h.Class("block max-w-full truncate font-mono text-xs text-muted-foreground")],
[incident.detectorKey],
),
],
incident.detectorKey,
),
...(incident.fingerprintHash === null
Expand All @@ -135,7 +157,11 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
"Fingerprint",
[
h.code(
[h.Class("block max-w-full truncate font-mono text-xs text-muted-foreground")],
[
h.Class(
"block max-w-full truncate font-mono text-xs text-muted-foreground",
),
],
[incident.fingerprintHash],
),
],
Expand All @@ -144,7 +170,9 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
]),
]),
detailRailGroup(h, "Values", [
row(h, "Observed", [mono(h, fmt(incident.lastObservedValue), live ? tone.text : "text-foreground")]),
row(h, "Observed", [
mono(h, fmt(incident.lastObservedValue), live ? tone.text : "text-foreground"),
]),
row(h, "At open", [mono(h, fmt(incident.openedValue), "text-muted-foreground")]),
row(h, "Baseline", [mono(h, fmt(incident.baselineMedian), "text-muted-foreground")]),
row(h, "Threshold", [mono(h, fmt(incident.thresholdValue), "text-muted-foreground")]),
Expand All @@ -160,7 +188,9 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
h.div(
[
h.Key(fingerprint.fingerprintHash),
h.Class("grid min-h-7 grid-cols-[1fr_auto] items-center gap-x-2 py-0.5"),
h.Class(
"grid min-h-7 grid-cols-[1fr_auto] items-center gap-x-2 py-0.5",
),
h.Title(fingerprint.fingerprintHash),
],
[
Expand All @@ -186,13 +216,18 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
: truncatedId(h, {
value: fingerprint.fingerprintHash,
length: 10,
className: "truncate text-xs text-muted-foreground",
className:
"truncate text-xs text-muted-foreground",
}),
],
),
h.span(
[h.Class("font-mono text-xs tabular-nums text-muted-foreground")],
[fingerprint.resolvedAt !== null ? "resolved" : fmt(fingerprint.lastValue)],
[
fingerprint.resolvedAt !== null
? "resolved"
: fmt(fingerprint.lastValue),
],
),
],
),
Expand All @@ -201,7 +236,9 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
]
: []),
detailRailGroup(h, "Timing", [
row(h, "First triggered", [time(incident.firstTriggeredAt, "text-right text-sm tabular-nums text-foreground")]),
row(h, "First triggered", [
time(incident.firstTriggeredAt, "text-right text-sm tabular-nums text-foreground"),
]),
...(incident.reopenCount > 0 && incident.lastReopenedAt !== null
? [
row(h, "Reopened", [
Expand All @@ -215,24 +252,45 @@ export const anomalySidebar = (h: H, input: SidebarInput): Html => {
]),
]
: []),
row(h, "Last triggered", [time(incident.lastTriggeredAt, "text-right text-sm tabular-nums text-foreground")]),
row(h, "Last triggered", [
time(incident.lastTriggeredAt, "text-right text-sm tabular-nums text-foreground"),
]),
...(incident.resolvedAt === null
? []
: [row(h, "Resolved", [time(incident.resolvedAt, "text-right text-sm tabular-nums text-muted-foreground")])]),
: [
row(h, "Resolved", [
time(
incident.resolvedAt,
"text-right text-sm tabular-nums text-muted-foreground",
),
]),
]),
...(incident.resolveReason === null
? []
: [
row(h, "Reason", [
h.span([h.Class("text-right text-sm text-muted-foreground")], [RESOLVE_REASON_LABEL[incident.resolveReason]]),
h.span(
[h.Class("text-right text-sm text-muted-foreground")],
[RESOLVE_REASON_LABEL[incident.resolveReason]],
),
]),
]),
]),
detailRailGroup(h, "Triage", [
triageChip === null
? h.p([h.Class("text-xs text-muted-foreground")], ["No AI triage has run for this incident."])
: badge(h, { pill: true, size: "sm", className: cn(META_CHIP_CLASS, "w-fit font-medium", triageChip.tone) }, [
triageChip.label,
]),
? h.p(
[h.Class("text-xs text-muted-foreground")],
["No AI triage has run for this incident."],
)
: badge(
h,
{
pill: true,
size: "sm",
className: cn(META_CHIP_CLASS, "w-fit font-medium", triageChip.tone),
},
[triageChip.label],
),
]),
],
)
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/page/dashboards/view/view-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ const list = (h: H, model: Model, versions: ReadonlyArray<VersionRow>, clock: Cl
export const historyPanel = (h: H, model: Model, clock: Clock): Html => {
const versions = model.history.versions
const count = AsyncData.getOrElse(versions, () => []).length
return h.aside(
[h.Class("flex h-full w-80 shrink-0 flex-col border-l bg-background")],
return h.div(
[h.Class("flex h-full flex-col")],
[
h.div(
[h.Class("flex items-center gap-2 border-b px-4 py-3")],
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/page/dashboards/view/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ export const view = Submodel.defineView<Model, Message, PageViewInputs>((model,
nowMs: model.nowMs ?? 0,
timeZone: inputs.context.timeZone,
}),
rightPanelWidth: "w-80",
}
: undefined),
},
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/page/errors/issue/view-sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ export const issueSidebar = (
const isTerminal = issue.workflowState === "cancelled" || issue.workflowState === "done"
const canClaim = issue.leaseHolder === null && !isTerminal
return h.div(
[h.Class("flex flex-col bg-card/30")],
[h.Class("flex flex-col")],
[
detailRailGroup(h, "Details", [
detailRailRow(h, { label: "Status" }, [stateSelect(h, model, issue.workflowState)]),
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/page/errors/issue/view-skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const railRow = (h: H, label: string, width: string): Html =>

const railSkeleton = (h: H): Html =>
h.div(
[h.Class("flex flex-col bg-card/30")],
[h.Class("flex flex-col")],
[
detailRailGroup(h, "Details", [
railRow(h, "Status", "w-24"),
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/page/infra/containers/detail/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const METRIC_LABELS = new Map<ContainerMetric, string>([
])

const rail = (h: H, summary: Summary): Html =>
resourceAttributesCard(h, "DockerIcon", [
resourceAttributesCard(h, [
metaRow(h, { label: "container.name", value: summary.containerName }),
metaRow(h, { label: "container.id", value: summary.containerId }),
metaRow(h, { label: "container.image.name", value: summary.imageName }),
Expand All @@ -62,7 +62,7 @@ const rightPanel = (h: H, model: Model): Html | undefined => {
const summary = AsyncData.getOrElse(model.summary.data, () => null)
if (summary !== null) return rail(h, summary)
return AsyncData.isLoading(model.summary.data) || AsyncData.isIdle(model.summary.data)
? resourceAttributesCardSkeleton(h, "DockerIcon")
? resourceAttributesCardSkeleton(h)
: undefined
}

Expand Down
Loading
Loading