Files
zeekayandHanzo Dev e4b373083a elements: name the design system for what it is
Every component in the library carried the upstream project's mascot in its
identifier, its CSS class, its SCSS file and its path. The prefix carried no
information -- a button is a button -- so it is gone: LemonButton is Button,
LemonBanner is Banner, and the set they belong to lives in lib/elements.

lib/ui was the obvious home and is not available: it already holds the
headless primitives (ButtonPrimitive, TabsPrimitive, ListBox), and both
layers define a Label. Folding a styled set into a primitive one is a
redesign; keeping them apart keeps this a rename and nothing more.

--lemon-button-height becomes --height, not --button-height. lib/ui sets a
bare --button-height inline in ButtonPrimitives and reads it back in
DropdownMenu and SelectPrimitive; custom properties inherit, so reusing that
name would silently resize any primitive nested inside a styled button.

Left alone because they are not ours to rename: LemonChiffon and lemonchiffon
(W3C named colours, used as lookup keys), kylelemons (a Go dependency) and
Plemons (a surname in the person-name generator). Words that merely contain
the letters -- disableMonospaceOptimizations, MultipleMonths,
ScheduleMonitorJobInputs -- are untouched; the codemod is case-sensitive so it
never saw them.

capture_request_dump.jsonl keeps the old class names too. Its inputs are
gzipped captures of what a browser actually sent in 2023 and cannot be
rewritten, so renaming only the expected output would have made the fixture
contradict itself.

Storybook titles moved with the files, so story ids still match the snapshot
filenames they are compared against.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-31 11:09:43 -07:00

87 lines
3.0 KiB
TypeScript

import { useValues } from 'kea'
import { IconMinusSquare, IconPlusSquare } from '@hanzo/icons'
import { Button, Table } from '@hanzo/elements'
import { PropertyFilterType, PropertyOperator } from '~/types'
import { attributeBreakdownLogic } from './attributeBreakdownLogic'
export const AttributeBreakdowns = ({
attribute,
type,
addFilter,
id,
}: {
attribute: string
type: PropertyFilterType
addFilter: (key: string, value: string, operator?: PropertyOperator, type?: PropertyFilterType) => void
id: string
}): JSX.Element => {
const logic = attributeBreakdownLogic({ attribute, type, id })
const { attributeValues, logCount, breakdowns } = useValues(logic)
const dataSource = Object.entries(breakdowns)
.sort(([, c1], [, c2]) => c2 - c1)
.slice(0, 10)
.map(([value, count]) => ({
value,
count,
percentage: ((count / attributeValues.length) * 100).toFixed(0),
}))
return (
<div className="flex flex-col p-2 gap-y-2">
{attributeValues.length} of the {logCount} logs have the label {attribute}
<Table
className="w-fit"
hideScrollbar
dataSource={dataSource}
size="small"
columns={[
{
key: 'actions',
width: 0,
render: (_, record) => (
<div className="flex gap-x-0">
<Button
tooltip="Add as filter"
size="xsmall"
onClick={() => addFilter(attribute, record.value, PropertyOperator.Exact, type)}
>
<IconPlusSquare />
</Button>
<Button
tooltip="Exclude as filter"
size="xsmall"
onClick={() => addFilter(attribute, record.value, PropertyOperator.IsNot, type)}
>
<IconMinusSquare />
</Button>
</div>
),
},
{
title: 'Count',
key: 'count',
dataIndex: 'count',
width: 0,
},
{
title: 'Percentage',
key: 'percentage',
dataIndex: 'percentage',
width: 0,
render: (value) => `${value}%`,
},
{
title: 'Value',
key: 'value',
dataIndex: 'value',
},
]}
/>
</div>
)
}