diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 510f23d..4adca31 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -16,7 +16,7 @@ body: attributes: label: ALPR Community version description: Find this under Settings → Release. Include the source revision there when reporting an installation or update problem. - placeholder: v0.1.57 + placeholder: v0.1.58 validations: required: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bb9af5..bb6dbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.58 — 2026-10-21 + +- Resize Recognition Feed and Plate Database columns using draggable header dividers or the keyboard, with separate saved widths per browser and a reset option. +- Keep narrow text readable through ellipses and hover text, protect minimum control widths, and allow horizontal scrolling. +- Start Actions as a compact menu with full labels; widening the column restores the individual action icons. +- Update User Guide 3.26 and current installation/update examples. + ## 0.1.57 — 2026-10-21 - Enable batch correction and recurring OCR-misread aliases by default for administrators; retain the batch preview and unchanged-plate safeguards. Operators retain single-read correction. diff --git a/app/globals.css b/app/globals.css index 6867d27..5ea4a83 100644 --- a/app/globals.css +++ b/app/globals.css @@ -200,3 +200,8 @@ @apply bg-background text-foreground; } } + +/* Fixed column widths keep long content inside its own cell. */ +.resizable-plate-table td { + overflow: hidden; +} diff --git a/components/PlateStateCountryField.jsx b/components/PlateStateCountryField.jsx index 5388949..fec3637 100644 --- a/components/PlateStateCountryField.jsx +++ b/components/PlateStateCountryField.jsx @@ -10,7 +10,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { getPlateStateCountries, updatePlateStateCountry } from "@/app/actions"; -export default function PlateStateCountryField({ plateNumber, value, onSaved }) { +export default function PlateStateCountryField({ plateNumber, value, onSaved, compact = false }) { const { can } = useAccess(); const inputId = useId(); const optionsId = useId(); @@ -37,7 +37,7 @@ export default function PlateStateCountryField({ plateNumber, value, onSaved }) return () => { active = false; }; }, [open]); - if (!can("plate.review")) return {savedValue || "—"}; + if (!can("plate.review")) return {savedValue || "—"}; const save = async (event) => { event.preventDefault(); @@ -58,8 +58,8 @@ export default function PlateStateCountryField({ plateNumber, value, onSaved }) }; return <> - { if (!saving) setOpen(next); }}> diff --git a/components/PlateTable.jsx b/components/PlateTable.jsx index 87ea53d..b4bf512 100644 --- a/components/PlateTable.jsx +++ b/components/PlateTable.jsx @@ -47,10 +47,8 @@ import { SelectValue, } from "@/components/ui/select"; import { - Table, TableBody, TableCell, - TableHead, TableHeader, TableRow, } from "@/components/ui/table"; @@ -98,6 +96,8 @@ import { useRouter } from "next/navigation"; import PlateMatchModeSelect from "@/components/PlateMatchModeSelect"; import PlateImage from "@/components/PlateImage"; import PlateStateCountryField from "@/components/PlateStateCountryField"; +import ResizablePlateTable, { ResizableTableHead, TableValue } from "@/components/ResizablePlateTable"; +import TableRowActions from "@/components/TableRowActions"; import { plateCorrectionDefaults, isAliasOnlyCorrection } from "@/lib/plate-correction-defaults.mjs"; import MultiSelectFilter from "@/components/MultiSelectFilter"; import LiveFeedDateRangeFilter from "@/components/LiveFeedDateRangeFilter"; @@ -156,12 +156,12 @@ const SortButton = ({ label, field, sort, onSort }) => { ); }; @@ -187,7 +187,6 @@ const POPUP_ACTION_ICON_CLASS = "mr-1 h-3.5 w-3.5 shrink-0"; const POPUP_ACTION_LABEL_CLASS = "min-w-0 truncate whitespace-nowrap"; const POPUP_ACTION_GRID_CLASS = "grid w-full grid-cols-7 gap-2"; const POPUP_ACTION_SLOT_CLASS = "min-h-8 min-w-0"; -const TABLE_ACTION_BUTTON_CLASS = "h-8 w-8 p-0"; const CONFIRM_NEXT_SCAN_TIMEOUT_MS = 15000; const SEARCH_FILTER_DEBOUNCE_MS = 250; @@ -245,11 +244,11 @@ function PlateIdentity({ plate, compact = false }) { const wasResolved = observed !== plate.plate_number; return ( -
+
{plate.plate_number} @@ -262,14 +261,10 @@ function PlateIdentity({ plate, compact = false }) {
{wasResolved && ( -
- Camera read {observed} -
+ {`Camera read ${observed}`} )} {plate.known_name && ( -
- {plate.known_name} -
+ {plate.known_name} )}
); @@ -291,13 +286,14 @@ function DirectionBadge({ plate }) { return ( - {label} + {label} ); } @@ -312,15 +308,16 @@ function PlateTimestamp({ timestamp, timeFormat }) { return (