Rework tickets filter bar into two-row layout with consistent CTI styling
Build & Push / Test (client) (push) Successful in 27s
Build & Push / Test (server) (push) Successful in 31s
Build & Push / Build Client (push) Successful in 1m5s
Build & Push / Build Server (push) Successful in 1m43s

Split the dense single-row filter bar into two rows: search + saved views on top,
filter selectors below. Fix CTI selectors to use design system tokens instead of
hardcoded dark classes, and upgrade the saved views button with an icon and badge count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 22:20:29 -04:00
parent 2177162300
commit cfe7ad56ff
2 changed files with 117 additions and 61 deletions
+52 -5
View File
@@ -4,9 +4,10 @@ interface CTISelectProps {
value: { categoryId: string; typeId: string; itemId: string };
onChange: (value: { categoryId: string; typeId: string; itemId: string }) => void;
disabled?: boolean;
compact?: boolean;
}
export default function CTISelect({ value, onChange, disabled }: CTISelectProps) {
export default function CTISelect({ value, onChange, disabled, compact }: CTISelectProps) {
const { data: categories = [] } = useCategories();
const { data: types = [] } = useTypes(value.categoryId || undefined);
const { data: items = [] } = useItems(value.typeId || undefined);
@@ -24,12 +25,58 @@ export default function CTISelect({ value, onChange, disabled }: CTISelectProps)
};
const selectClass =
'block w-full bg-gray-800 border border-gray-700 text-gray-100 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed';
'block w-full rounded-md border border-input bg-background px-3 py-1.5 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50';
if (compact) {
return (
<div className="flex gap-2">
<select
value={value.categoryId}
onChange={(e) => handleCategory(e.target.value)}
disabled={disabled}
className={selectClass}
>
<option value="">Category...</option>
{categories.map((c) => (
<option key={c.id} value={c.id}>
{c.name}
</option>
))}
</select>
<select
value={value.typeId}
onChange={(e) => handleType(e.target.value)}
disabled={disabled || !value.categoryId}
className={selectClass}
>
<option value="">Type...</option>
{types.map((t) => (
<option key={t.id} value={t.id}>
{t.name}
</option>
))}
</select>
<select
value={value.itemId}
onChange={(e) => handleItem(e.target.value)}
disabled={disabled || !value.typeId}
className={selectClass}
>
<option value="">Item...</option>
{items.map((i) => (
<option key={i.id} value={i.id}>
{i.name}
</option>
))}
</select>
</div>
);
}
return (
<div className="grid grid-cols-3 gap-3">
<div>
<label className="block text-xs font-medium text-gray-400 mb-1">Category</label>
<label className="block text-xs font-medium text-muted-foreground mb-1">Category</label>
<select
value={value.categoryId}
onChange={(e) => handleCategory(e.target.value)}
@@ -46,7 +93,7 @@ export default function CTISelect({ value, onChange, disabled }: CTISelectProps)
</div>
<div>
<label className="block text-xs font-medium text-gray-400 mb-1">Type</label>
<label className="block text-xs font-medium text-muted-foreground mb-1">Type</label>
<select
value={value.typeId}
onChange={(e) => handleType(e.target.value)}
@@ -63,7 +110,7 @@ export default function CTISelect({ value, onChange, disabled }: CTISelectProps)
</div>
<div>
<label className="block text-xs font-medium text-gray-400 mb-1">Item</label>
<label className="block text-xs font-medium text-muted-foreground mb-1">Item</label>
<select
value={value.itemId}
onChange={(e) => handleItem(e.target.value)}