@open-mercato/ui 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +204 -121
- package/dist/backend/AppShell.js +25 -28
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/ContextHelp.js +1 -1
- package/dist/backend/ContextHelp.js.map +1 -1
- package/dist/backend/CrudForm.js +12 -15
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +9 -10
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/FilterBar.js +6 -8
- package/dist/backend/FilterBar.js.map +2 -2
- package/dist/backend/FilterOverlay.js +10 -10
- package/dist/backend/FilterOverlay.js.map +2 -2
- package/dist/backend/FlashMessages.js +1 -1
- package/dist/backend/FlashMessages.js.map +2 -2
- package/dist/backend/JsonBuilder.js +6 -6
- package/dist/backend/JsonBuilder.js.map +1 -1
- package/dist/backend/NextStepCallout.js +1 -1
- package/dist/backend/NextStepCallout.js.map +1 -1
- package/dist/backend/PerspectiveSidebar.js +2 -2
- package/dist/backend/PerspectiveSidebar.js.map +2 -2
- package/dist/backend/ProfileDropdown.js +1 -1
- package/dist/backend/ProfileDropdown.js.map +1 -1
- package/dist/backend/RowActions.js +1 -1
- package/dist/backend/RowActions.js.map +1 -1
- package/dist/backend/UserMenu.js +2 -2
- package/dist/backend/UserMenu.js.map +1 -1
- package/dist/backend/WebhookSetupGuide.js +11 -11
- package/dist/backend/WebhookSetupGuide.js.map +2 -2
- package/dist/backend/charts/KpiCard.js +3 -3
- package/dist/backend/charts/KpiCard.js.map +1 -1
- package/dist/backend/columns/ColumnChooserPanel.js +1 -1
- package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js +3 -3
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
- package/dist/backend/dashboard/DashboardScreen.js +1 -1
- package/dist/backend/dashboard/DashboardScreen.js.map +1 -1
- package/dist/backend/date-range/DateRangeSelect.js +1 -1
- package/dist/backend/date-range/DateRangeSelect.js.map +1 -1
- package/dist/backend/date-range/InlineDateRangeSelect.js +1 -1
- package/dist/backend/date-range/InlineDateRangeSelect.js.map +1 -1
- package/dist/backend/detail/AccessDeniedMessage.js +1 -1
- package/dist/backend/detail/AccessDeniedMessage.js.map +1 -1
- package/dist/backend/detail/ActivitiesSection.js +5 -5
- package/dist/backend/detail/ActivitiesSection.js.map +1 -1
- package/dist/backend/detail/AddressEditor.js +3 -3
- package/dist/backend/detail/AddressEditor.js.map +2 -2
- package/dist/backend/detail/AddressTiles.js +3 -3
- package/dist/backend/detail/AddressTiles.js.map +2 -2
- package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
- package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
- package/dist/backend/detail/CustomDataSection.js +1 -1
- package/dist/backend/detail/CustomDataSection.js.map +1 -1
- package/dist/backend/detail/InlineEditors.js +5 -5
- package/dist/backend/detail/InlineEditors.js.map +1 -1
- package/dist/backend/detail/NotesSection.js +6 -6
- package/dist/backend/detail/NotesSection.js.map +1 -1
- package/dist/backend/detail/TagsSection.js +1 -1
- package/dist/backend/detail/TagsSection.js.map +1 -1
- package/dist/backend/devtools/UmesDevToolsPanel.js +6 -6
- package/dist/backend/devtools/UmesDevToolsPanel.js.map +2 -2
- package/dist/backend/devtools/components/ConflictWarnings.js +3 -3
- package/dist/backend/devtools/components/ConflictWarnings.js.map +2 -2
- package/dist/backend/devtools/components/EnricherTiming.js +2 -2
- package/dist/backend/devtools/components/EnricherTiming.js.map +2 -2
- package/dist/backend/devtools/components/EventFlow.js +5 -5
- package/dist/backend/devtools/components/EventFlow.js.map +2 -2
- package/dist/backend/devtools/components/ExtensionPointList.js +3 -3
- package/dist/backend/devtools/components/ExtensionPointList.js.map +2 -2
- package/dist/backend/devtools/components/InterceptorActivity.js +6 -6
- package/dist/backend/devtools/components/InterceptorActivity.js.map +2 -2
- package/dist/backend/forms/ActionsDropdown.js +1 -1
- package/dist/backend/forms/ActionsDropdown.js.map +1 -1
- package/dist/backend/forms/FormActionButtons.js +2 -3
- package/dist/backend/forms/FormActionButtons.js.map +2 -2
- package/dist/backend/indexes/PartialIndexBanner.js +8 -8
- package/dist/backend/indexes/PartialIndexBanner.js.map +2 -2
- package/dist/backend/inputs/ComboboxInput.js +1 -1
- package/dist/backend/inputs/ComboboxInput.js.map +2 -2
- package/dist/backend/inputs/DatePicker.js +3 -3
- package/dist/backend/inputs/DatePicker.js.map +1 -1
- package/dist/backend/inputs/DateTimePicker.js +3 -3
- package/dist/backend/inputs/DateTimePicker.js.map +1 -1
- package/dist/backend/inputs/EventSelect.js +1 -1
- package/dist/backend/inputs/EventSelect.js.map +2 -2
- package/dist/backend/inputs/LookupSelect.js +1 -1
- package/dist/backend/inputs/LookupSelect.js.map +1 -1
- package/dist/backend/inputs/SwitchableMarkdownInput.js +1 -1
- package/dist/backend/inputs/SwitchableMarkdownInput.js.map +1 -1
- package/dist/backend/inputs/TagsInput.js +2 -2
- package/dist/backend/inputs/TagsInput.js.map +2 -2
- package/dist/backend/inputs/TimeInput.js +1 -1
- package/dist/backend/inputs/TimeInput.js.map +1 -1
- package/dist/backend/inputs/TimePicker.js +3 -3
- package/dist/backend/inputs/TimePicker.js.map +1 -1
- package/dist/backend/messages/MessageObjectDetail.js +1 -1
- package/dist/backend/messages/MessageObjectDetail.js.map +1 -1
- package/dist/backend/messages/MessageObjectPreview.js +1 -1
- package/dist/backend/messages/MessageObjectPreview.js.map +1 -1
- package/dist/backend/messages/message-compose-form-groups.js +3 -3
- package/dist/backend/messages/message-compose-form-groups.js.map +1 -1
- package/dist/backend/notifications/NotificationCountBadge.js +1 -1
- package/dist/backend/notifications/NotificationCountBadge.js.map +2 -2
- package/dist/backend/notifications/NotificationPanel.js +3 -3
- package/dist/backend/notifications/NotificationPanel.js.map +1 -1
- package/dist/backend/progress/ProgressTopBar.js +4 -4
- package/dist/backend/progress/ProgressTopBar.js.map +2 -2
- package/dist/backend/schedule/ScheduleAgenda.js +1 -1
- package/dist/backend/schedule/ScheduleAgenda.js.map +2 -2
- package/dist/backend/schedule/ScheduleCalendar.js +1 -1
- package/dist/backend/schedule/ScheduleCalendar.js.map +1 -1
- package/dist/backend/schedule/ScheduleGrid.js +1 -1
- package/dist/backend/schedule/ScheduleGrid.js.map +2 -2
- package/dist/backend/version-history/VersionHistoryPanel.js +4 -4
- package/dist/backend/version-history/VersionHistoryPanel.js.map +2 -2
- package/dist/frontend/AuthFooter.js +1 -1
- package/dist/frontend/AuthFooter.js.map +1 -1
- package/dist/frontend/LanguageSwitcher.js +1 -1
- package/dist/frontend/LanguageSwitcher.js.map +1 -1
- package/dist/frontend/Layout.js +2 -2
- package/dist/frontend/Layout.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +2 -2
- package/dist/portal/PortalShell.js +15 -15
- package/dist/portal/PortalShell.js.map +2 -2
- package/dist/portal/components/PortalCard.js +2 -2
- package/dist/portal/components/PortalCard.js.map +2 -2
- package/dist/portal/components/PortalNotificationPanel.js +18 -18
- package/dist/portal/components/PortalNotificationPanel.js.map +2 -2
- package/dist/portal/components/PortalPageHeader.js +1 -1
- package/dist/portal/components/PortalPageHeader.js.map +2 -2
- package/dist/primitives/avatar.js +11 -1
- package/dist/primitives/avatar.js.map +2 -2
- package/dist/primitives/badge.js +1 -1
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.js +9 -5
- package/dist/primitives/button.js.map +2 -2
- package/dist/primitives/calendar.js +1 -1
- package/dist/primitives/calendar.js.map +1 -1
- package/dist/primitives/checkbox-field.js +63 -0
- package/dist/primitives/checkbox-field.js.map +7 -0
- package/dist/primitives/checkbox.js +31 -17
- package/dist/primitives/checkbox.js.map +2 -2
- package/dist/primitives/dialog.js +4 -4
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/fancy-button.js +72 -0
- package/dist/primitives/fancy-button.js.map +7 -0
- package/dist/primitives/icon-button.js +20 -4
- package/dist/primitives/icon-button.js.map +2 -2
- package/dist/primitives/kbd.js +27 -0
- package/dist/primitives/kbd.js.map +7 -0
- package/dist/primitives/link-button.js +56 -0
- package/dist/primitives/link-button.js.map +7 -0
- package/dist/primitives/popover.js +1 -1
- package/dist/primitives/popover.js.map +1 -1
- package/dist/primitives/social-button.js +61 -0
- package/dist/primitives/social-button.js.map +7 -0
- package/dist/primitives/tabs.js +1 -1
- package/dist/primitives/tabs.js.map +1 -1
- package/dist/primitives/tag.js +45 -0
- package/dist/primitives/tag.js.map +7 -0
- package/dist/primitives/tooltip.js +1 -1
- package/dist/primitives/tooltip.js.map +1 -1
- package/package.json +3 -3
- package/src/backend/AppShell.tsx +25 -28
- package/src/backend/ContextHelp.tsx +1 -1
- package/src/backend/CrudForm.tsx +12 -15
- package/src/backend/DataTable.tsx +9 -10
- package/src/backend/FilterBar.tsx +6 -5
- package/src/backend/FilterOverlay.tsx +10 -10
- package/src/backend/FlashMessages.tsx +1 -1
- package/src/backend/JsonBuilder.tsx +6 -6
- package/src/backend/NextStepCallout.tsx +1 -1
- package/src/backend/PerspectiveSidebar.tsx +2 -2
- package/src/backend/ProfileDropdown.tsx +1 -1
- package/src/backend/RowActions.tsx +1 -1
- package/src/backend/UserMenu.tsx +2 -2
- package/src/backend/WebhookSetupGuide.tsx +11 -11
- package/src/backend/charts/KpiCard.tsx +3 -3
- package/src/backend/columns/ColumnChooserPanel.tsx +1 -1
- package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +3 -3
- package/src/backend/dashboard/DashboardScreen.tsx +1 -1
- package/src/backend/date-range/DateRangeSelect.tsx +1 -1
- package/src/backend/date-range/InlineDateRangeSelect.tsx +1 -1
- package/src/backend/detail/AccessDeniedMessage.tsx +1 -1
- package/src/backend/detail/ActivitiesSection.tsx +5 -5
- package/src/backend/detail/AddressEditor.tsx +3 -3
- package/src/backend/detail/AddressTiles.tsx +3 -3
- package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
- package/src/backend/detail/CustomDataSection.tsx +1 -1
- package/src/backend/detail/InlineEditors.tsx +5 -5
- package/src/backend/detail/NotesSection.tsx +6 -6
- package/src/backend/detail/TagsSection.tsx +1 -1
- package/src/backend/devtools/UmesDevToolsPanel.tsx +6 -6
- package/src/backend/devtools/components/ConflictWarnings.tsx +4 -4
- package/src/backend/devtools/components/EnricherTiming.tsx +2 -2
- package/src/backend/devtools/components/EventFlow.tsx +5 -5
- package/src/backend/devtools/components/ExtensionPointList.tsx +3 -3
- package/src/backend/devtools/components/InterceptorActivity.tsx +6 -6
- package/src/backend/forms/ActionsDropdown.tsx +1 -1
- package/src/backend/forms/FormActionButtons.tsx +4 -5
- package/src/backend/indexes/PartialIndexBanner.tsx +8 -8
- package/src/backend/inputs/ComboboxInput.tsx +1 -1
- package/src/backend/inputs/DatePicker.tsx +3 -3
- package/src/backend/inputs/DateTimePicker.tsx +3 -3
- package/src/backend/inputs/EventSelect.tsx +1 -1
- package/src/backend/inputs/LookupSelect.tsx +1 -1
- package/src/backend/inputs/SwitchableMarkdownInput.tsx +1 -1
- package/src/backend/inputs/TagsInput.tsx +2 -2
- package/src/backend/inputs/TimeInput.tsx +1 -1
- package/src/backend/inputs/TimePicker.tsx +3 -3
- package/src/backend/messages/MessageObjectDetail.tsx +1 -1
- package/src/backend/messages/MessageObjectPreview.tsx +1 -1
- package/src/backend/messages/message-compose-form-groups.tsx +3 -3
- package/src/backend/notifications/NotificationCountBadge.tsx +1 -1
- package/src/backend/notifications/NotificationPanel.tsx +3 -3
- package/src/backend/progress/ProgressTopBar.tsx +4 -4
- package/src/backend/schedule/ScheduleAgenda.tsx +1 -1
- package/src/backend/schedule/ScheduleCalendar.tsx +1 -1
- package/src/backend/schedule/ScheduleGrid.tsx +1 -1
- package/src/backend/version-history/VersionHistoryPanel.tsx +4 -4
- package/src/frontend/AuthFooter.tsx +1 -1
- package/src/frontend/LanguageSwitcher.tsx +1 -1
- package/src/frontend/Layout.tsx +2 -2
- package/src/index.ts +6 -1
- package/src/portal/PortalShell.tsx +15 -15
- package/src/portal/components/PortalCard.tsx +2 -2
- package/src/portal/components/PortalNotificationPanel.tsx +18 -18
- package/src/portal/components/PortalPageHeader.tsx +1 -1
- package/src/primitives/avatar.tsx +22 -0
- package/src/primitives/badge.tsx +1 -1
- package/src/primitives/button.tsx +12 -5
- package/src/primitives/calendar.tsx +1 -1
- package/src/primitives/checkbox-field.tsx +85 -0
- package/src/primitives/checkbox.tsx +44 -18
- package/src/primitives/dialog.tsx +4 -4
- package/src/primitives/fancy-button.tsx +89 -0
- package/src/primitives/icon-button.tsx +19 -2
- package/src/primitives/kbd.tsx +38 -0
- package/src/primitives/link-button.tsx +55 -0
- package/src/primitives/popover.tsx +1 -1
- package/src/primitives/social-button.tsx +80 -0
- package/src/primitives/tabs.tsx +1 -1
- package/src/primitives/tag.tsx +66 -0
- package/src/primitives/tooltip.tsx +1 -1
|
@@ -17,7 +17,7 @@ function EnricherTiming({ entries }) {
|
|
|
17
17
|
const maxMs = Math.max(...recent.map((e) => e.durationMs), 1);
|
|
18
18
|
return /* @__PURE__ */ jsx("div", { children: recent.map((entry, idx) => {
|
|
19
19
|
const classes = getTimingClasses(entry.durationMs);
|
|
20
|
-
return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/70 py-1 text-xs", children: [
|
|
21
21
|
/* @__PURE__ */ jsxs("div", { className: "mb-0.5 flex justify-between", children: [
|
|
22
22
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.enricherId }),
|
|
23
23
|
/* @__PURE__ */ jsxs("span", { className: `font-mono font-semibold ${classes.text}`, children: [
|
|
@@ -32,7 +32,7 @@ function EnricherTiming({ entries }) {
|
|
|
32
32
|
style: { width: getTimingBarWidth(entry.durationMs, maxMs) }
|
|
33
33
|
}
|
|
34
34
|
) }),
|
|
35
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-px text-
|
|
35
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-px text-overline text-muted-foreground", children: [
|
|
36
36
|
entry.targetEntity,
|
|
37
37
|
" | ",
|
|
38
38
|
entry.moduleId
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/backend/devtools/components/EnricherTiming.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport type { EnricherTimingEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nfunction getTimingClasses(ms: number): { text: string; bar: string } {\n if (ms >= 500) return { text: 'text-red-500', bar: 'bg-red-500' }\n if (ms >= 100) return { text: 'text-amber-500', bar: 'bg-amber-500' }\n return { text: 'text-emerald-500', bar: 'bg-emerald-500' }\n}\n\nfunction getTimingBarWidth(ms: number, maxMs: number): string {\n if (maxMs === 0) return '0%'\n return `${Math.min(100, (ms / maxMs) * 100)}%`\n}\n\nexport function EnricherTiming({ entries }: { entries: EnricherTimingEntry[] }) {\n if (entries.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No timing data</p>\n }\n\n const recent = entries.slice(-20).reverse()\n const maxMs = Math.max(...recent.map((e) => e.durationMs), 1)\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = getTimingClasses(entry.durationMs)\n return (\n <div key={idx} className=\"border-b border-border/
|
|
5
|
-
"mappings": ";AAiBW,cAcG,YAdH;AAbX,SAAS,iBAAiB,IAA2C;AACnE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,gBAAgB,KAAK,aAAa;AAChE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,kBAAkB,KAAK,eAAe;AACpE,SAAO,EAAE,MAAM,oBAAoB,KAAK,iBAAiB;AAC3D;AAEA,SAAS,kBAAkB,IAAY,OAAuB;AAC5D,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,GAAG,KAAK,IAAI,KAAM,KAAK,QAAS,GAAG,CAAC;AAC7C;AAEO,SAAS,eAAe,EAAE,QAAQ,GAAuC;AAC9E,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,oBAAC,OAAE,WAAU,wCAAuC,4BAAc;AAAA,EAC3E;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC;AAE5D,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,iBAAiB,MAAM,UAAU;AACjD,WACE,qBAAC,SAAc,WAAU,0CACvB;AAAA,2BAAC,SAAI,WAAU,+BACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,YAAW;AAAA,QAChD,qBAAC,UAAK,WAAW,2BAA2B,QAAQ,IAAI,IACrD;AAAA,gBAAM;AAAA,UAAW;AAAA,WACpB;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,wCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,kDAAkD,QAAQ,GAAG;AAAA,UACxE,OAAO,EAAE,OAAO,kBAAkB,MAAM,YAAY,KAAK,EAAE;AAAA;AAAA,MAC7D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport type { EnricherTimingEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nfunction getTimingClasses(ms: number): { text: string; bar: string } {\n if (ms >= 500) return { text: 'text-red-500', bar: 'bg-red-500' }\n if (ms >= 100) return { text: 'text-amber-500', bar: 'bg-amber-500' }\n return { text: 'text-emerald-500', bar: 'bg-emerald-500' }\n}\n\nfunction getTimingBarWidth(ms: number, maxMs: number): string {\n if (maxMs === 0) return '0%'\n return `${Math.min(100, (ms / maxMs) * 100)}%`\n}\n\nexport function EnricherTiming({ entries }: { entries: EnricherTimingEntry[] }) {\n if (entries.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No timing data</p>\n }\n\n const recent = entries.slice(-20).reverse()\n const maxMs = Math.max(...recent.map((e) => e.durationMs), 1)\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = getTimingClasses(entry.durationMs)\n return (\n <div key={idx} className=\"border-b border-border/70 py-1 text-xs\">\n <div className=\"mb-0.5 flex justify-between\">\n <span className=\"font-medium\">{entry.enricherId}</span>\n <span className={`font-mono font-semibold ${classes.text}`}>\n {entry.durationMs}ms\n </span>\n </div>\n <div className=\"h-1 overflow-hidden rounded bg-muted\">\n <div\n className={`h-full rounded transition-[width] duration-300 ${classes.bar}`}\n style={{ width: getTimingBarWidth(entry.durationMs, maxMs) }}\n />\n </div>\n <div className=\"mt-px text-overline text-muted-foreground\">\n {entry.targetEntity} | {entry.moduleId}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAiBW,cAcG,YAdH;AAbX,SAAS,iBAAiB,IAA2C;AACnE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,gBAAgB,KAAK,aAAa;AAChE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,kBAAkB,KAAK,eAAe;AACpE,SAAO,EAAE,MAAM,oBAAoB,KAAK,iBAAiB;AAC3D;AAEA,SAAS,kBAAkB,IAAY,OAAuB;AAC5D,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,GAAG,KAAK,IAAI,KAAM,KAAK,QAAS,GAAG,CAAC;AAC7C;AAEO,SAAS,eAAe,EAAE,QAAQ,GAAuC;AAC9E,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,oBAAC,OAAE,WAAU,wCAAuC,4BAAc;AAAA,EAC3E;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC;AAE5D,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,iBAAiB,MAAM,UAAU;AACjD,WACE,qBAAC,SAAc,WAAU,0CACvB;AAAA,2BAAC,SAAI,WAAU,+BACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,YAAW;AAAA,QAChD,qBAAC,UAAK,WAAW,2BAA2B,QAAQ,IAAI,IACrD;AAAA,gBAAM;AAAA,UAAW;AAAA,WACpB;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,wCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,kDAAkD,QAAQ,GAAG;AAAA,UACxE,OAAO,EAAE,OAAO,kBAAkB,MAAM,YAAY,KAAK,EAAE;AAAA;AAAA,MAC7D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,6CACZ;AAAA,cAAM;AAAA,QAAa;AAAA,QAAI,MAAM;AAAA,SAChC;AAAA,SAfQ,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
const RESULT_CLASSES = {
|
|
4
|
-
allowed: { text: "text-
|
|
5
|
-
blocked: { text: "text-
|
|
6
|
-
error: { text: "text-
|
|
4
|
+
allowed: { text: "text-status-success-icon", bg: "bg-status-success-bg" },
|
|
5
|
+
blocked: { text: "text-status-error-icon", bg: "bg-status-error-bg" },
|
|
6
|
+
error: { text: "text-status-warning-icon", bg: "bg-status-warning-bg" }
|
|
7
7
|
};
|
|
8
8
|
function EventFlow({ entries }) {
|
|
9
9
|
if (entries.length === 0) {
|
|
@@ -19,9 +19,9 @@ function EventFlow({ entries }) {
|
|
|
19
19
|
children: [
|
|
20
20
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
21
21
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.eventName }),
|
|
22
|
-
/* @__PURE__ */ jsx("span", { className: "ml-1.5 text-
|
|
22
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1.5 text-overline text-muted-foreground", children: entry.widgetId })
|
|
23
23
|
] }),
|
|
24
|
-
/* @__PURE__ */ jsx("span", { className: `text-
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: `text-overline font-semibold ${classes.text}`, children: entry.result })
|
|
25
25
|
]
|
|
26
26
|
},
|
|
27
27
|
idx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/backend/devtools/components/EventFlow.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport type { EventFlowEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-
|
|
5
|
-
"mappings": ";AAaM,cAiBM,YAjBN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport type { EventFlowEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-status-success-icon', bg: 'bg-status-success-bg' },\n blocked: { text: 'text-status-error-icon', bg: 'bg-status-error-bg' },\n error: { text: 'text-status-warning-icon', bg: 'bg-status-warning-bg' },\n}\n\nexport function EventFlow({ entries }: { entries: EventFlowEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No event flow data\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div\n key={idx}\n className={`mb-0.5 flex items-center justify-between rounded p-1 px-2 text-xs ${classes.bg}`}\n >\n <div>\n <span className=\"font-medium\">{entry.eventName}</span>\n <span className=\"ml-1.5 text-overline text-muted-foreground\">\n {entry.widgetId}\n </span>\n </div>\n <span className={`text-overline font-semibold ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n )\n })}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAaM,cAiBM,YAjBN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAAA,EACxE,SAAS,EAAE,MAAM,0BAA0B,IAAI,qBAAqB;AAAA,EACpE,OAAO,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AACxE;AAEO,SAAS,UAAU,EAAE,QAAQ,GAAkC;AACpE,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,gCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,qEAAqE,QAAQ,EAAE;AAAA,QAE1F;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,gBAAM,WAAU;AAAA,YAC/C,oBAAC,UAAK,WAAU,8CACb,gBAAM,UACT;AAAA,aACF;AAAA,UACA,oBAAC,UAAK,WAAW,+BAA+B,QAAQ,IAAI,IACzD,gBAAM,QACT;AAAA;AAAA;AAAA,MAXK;AAAA,IAYP;AAAA,EAEJ,CAAC,GACH;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -29,7 +29,7 @@ function ExtensionPointList({ extensions }) {
|
|
|
29
29
|
/* @__PURE__ */ jsx("div", { className: "pl-3.5", children: items.map((ext, idx) => /* @__PURE__ */ jsxs(
|
|
30
30
|
"div",
|
|
31
31
|
{
|
|
32
|
-
className: "flex items-center justify-between border-b border-border/
|
|
32
|
+
className: "flex items-center justify-between border-b border-border/70 py-1 text-xs",
|
|
33
33
|
children: [
|
|
34
34
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
35
35
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: ext.id }),
|
|
@@ -40,8 +40,8 @@ function ExtensionPointList({ extensions }) {
|
|
|
40
40
|
] })
|
|
41
41
|
] }),
|
|
42
42
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
43
|
-
/* @__PURE__ */ jsx("span", { className: "text-
|
|
44
|
-
ext.priority !== 0 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-px text-
|
|
43
|
+
/* @__PURE__ */ jsx("span", { className: "text-overline text-muted-foreground", children: ext.target }),
|
|
44
|
+
ext.priority !== 0 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-px text-overline font-semibold", children: [
|
|
45
45
|
"P",
|
|
46
46
|
ext.priority
|
|
47
47
|
] })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/backend/devtools/components/ExtensionPointList.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport type { UmesExtensionInfo } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst TYPE_COLORS: Record<string, string> = {\n enricher: 'bg-blue-500',\n interceptor: 'bg-amber-500',\n 'component-override': 'bg-violet-500',\n 'injection-widget': 'bg-emerald-500',\n 'injection-data-widget': 'bg-cyan-500',\n}\n\nexport function ExtensionPointList({ extensions }: { extensions: UmesExtensionInfo[] }) {\n if (extensions.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No extensions registered</p>\n }\n\n const grouped = new Map<string, UmesExtensionInfo[]>()\n for (const ext of extensions) {\n const key = ext.type\n const group = grouped.get(key) ?? []\n group.push(ext)\n grouped.set(key, group)\n }\n\n return (\n <div>\n {Array.from(grouped.entries()).map(([type, items]) => (\n <div key={type} className=\"mb-3\">\n <div className=\"mb-1 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide\">\n <span className={`inline-block size-2 rounded-full ${TYPE_COLORS[type] ?? 'bg-muted-foreground'}`} />\n {type} ({items.length})\n </div>\n <div className=\"pl-3.5\">\n {items.map((ext, idx) => (\n <div\n key={`${ext.id}-${idx}`}\n className=\"flex items-center justify-between border-b border-border/
|
|
5
|
-
"mappings": ";AAcW,cAeD,YAfC;AAVX,MAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,yBAAyB;AAC3B;AAEO,SAAS,mBAAmB,EAAE,WAAW,GAAwC;AACtF,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,oBAAC,OAAE,WAAU,wCAAuC,sCAAwB;AAAA,EACrF;AAEA,QAAM,UAAU,oBAAI,IAAiC;AACrD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,IAAI;AAChB,UAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,CAAC;AACnC,UAAM,KAAK,GAAG;AACd,YAAQ,IAAI,KAAK,KAAK;AAAA,EACxB;AAEA,SACE,oBAAC,SACE,gBAAM,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAC9C,qBAAC,SAAe,WAAU,QACxB;AAAA,yBAAC,SAAI,WAAU,gFACb;AAAA,0BAAC,UAAK,WAAW,oCAAoC,YAAY,IAAI,KAAK,qBAAqB,IAAI;AAAA,MAClG;AAAA,MAAK;AAAA,MAAG,MAAM;AAAA,MAAO;AAAA,OACxB;AAAA,IACA,oBAAC,SAAI,WAAU,UACZ,gBAAM,IAAI,CAAC,KAAK,QACf;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,cAAI,IAAG;AAAA,YACtC,qBAAC,UAAK,WAAU,gCAA+B;AAAA;AAAA,cAAE,IAAI;AAAA,cAAS;AAAA,eAAC;AAAA,aACjE;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport type { UmesExtensionInfo } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst TYPE_COLORS: Record<string, string> = {\n enricher: 'bg-blue-500',\n interceptor: 'bg-amber-500',\n 'component-override': 'bg-violet-500',\n 'injection-widget': 'bg-emerald-500',\n 'injection-data-widget': 'bg-cyan-500',\n}\n\nexport function ExtensionPointList({ extensions }: { extensions: UmesExtensionInfo[] }) {\n if (extensions.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No extensions registered</p>\n }\n\n const grouped = new Map<string, UmesExtensionInfo[]>()\n for (const ext of extensions) {\n const key = ext.type\n const group = grouped.get(key) ?? []\n group.push(ext)\n grouped.set(key, group)\n }\n\n return (\n <div>\n {Array.from(grouped.entries()).map(([type, items]) => (\n <div key={type} className=\"mb-3\">\n <div className=\"mb-1 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide\">\n <span className={`inline-block size-2 rounded-full ${TYPE_COLORS[type] ?? 'bg-muted-foreground'}`} />\n {type} ({items.length})\n </div>\n <div className=\"pl-3.5\">\n {items.map((ext, idx) => (\n <div\n key={`${ext.id}-${idx}`}\n className=\"flex items-center justify-between border-b border-border/70 py-1 text-xs\"\n >\n <div>\n <span className=\"font-medium\">{ext.id}</span>\n <span className=\"ml-1.5 text-muted-foreground\">[{ext.moduleId}]</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-overline text-muted-foreground\">{ext.target}</span>\n {ext.priority !== 0 && (\n <span className=\"rounded bg-muted px-1.5 py-px text-overline font-semibold\">\n P{ext.priority}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAcW,cAeD,YAfC;AAVX,MAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,yBAAyB;AAC3B;AAEO,SAAS,mBAAmB,EAAE,WAAW,GAAwC;AACtF,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,oBAAC,OAAE,WAAU,wCAAuC,sCAAwB;AAAA,EACrF;AAEA,QAAM,UAAU,oBAAI,IAAiC;AACrD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,IAAI;AAChB,UAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,CAAC;AACnC,UAAM,KAAK,GAAG;AACd,YAAQ,IAAI,KAAK,KAAK;AAAA,EACxB;AAEA,SACE,oBAAC,SACE,gBAAM,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAC9C,qBAAC,SAAe,WAAU,QACxB;AAAA,yBAAC,SAAI,WAAU,gFACb;AAAA,0BAAC,UAAK,WAAW,oCAAoC,YAAY,IAAI,KAAK,qBAAqB,IAAI;AAAA,MAClG;AAAA,MAAK;AAAA,MAAG,MAAM;AAAA,MAAO;AAAA,OACxB;AAAA,IACA,oBAAC,SAAI,WAAU,UACZ,gBAAM,IAAI,CAAC,KAAK,QACf;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,cAAI,IAAG;AAAA,YACtC,qBAAC,UAAK,WAAU,gCAA+B;AAAA;AAAA,cAAE,IAAI;AAAA,cAAS;AAAA,eAAC;AAAA,aACjE;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,uCAAuC,cAAI,QAAO;AAAA,YACjE,IAAI,aAAa,KAChB,qBAAC,UAAK,WAAU,6DAA4D;AAAA;AAAA,cACxE,IAAI;AAAA,eACR;AAAA,aAEJ;AAAA;AAAA;AAAA,MAdK,GAAG,IAAI,EAAE,IAAI,GAAG;AAAA,IAevB,CACD,GACH;AAAA,OAzBQ,IA0BV,CACD,GACH;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
const RESULT_CLASSES = {
|
|
4
|
-
allowed: { text: "text-
|
|
5
|
-
blocked: { text: "text-
|
|
6
|
-
modified: { text: "text-
|
|
4
|
+
allowed: { text: "text-status-success-icon", bg: "bg-status-success-bg" },
|
|
5
|
+
blocked: { text: "text-status-error-icon", bg: "bg-status-error-bg" },
|
|
6
|
+
modified: { text: "text-status-warning-icon", bg: "bg-status-warning-bg" }
|
|
7
7
|
};
|
|
8
8
|
function InterceptorActivity({ entries }) {
|
|
9
9
|
if (entries.length === 0) {
|
|
@@ -15,9 +15,9 @@ function InterceptorActivity({ entries }) {
|
|
|
15
15
|
return /* @__PURE__ */ jsxs("div", { className: `mb-1 rounded p-1.5 px-2 text-xs ${classes.bg}`, children: [
|
|
16
16
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
17
17
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.interceptorId }),
|
|
18
|
-
/* @__PURE__ */ jsx("span", { className: `text-
|
|
18
|
+
/* @__PURE__ */ jsx("span", { className: `text-overline font-semibold uppercase ${classes.text}`, children: entry.result })
|
|
19
19
|
] }),
|
|
20
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-
|
|
20
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-overline text-muted-foreground", children: [
|
|
21
21
|
entry.method,
|
|
22
22
|
" ",
|
|
23
23
|
entry.route,
|
|
@@ -26,7 +26,7 @@ function InterceptorActivity({ entries }) {
|
|
|
26
26
|
"ms",
|
|
27
27
|
entry.statusCode ? ` | ${entry.statusCode}` : ""
|
|
28
28
|
] }),
|
|
29
|
-
entry.message && /* @__PURE__ */ jsx("div", { className: "mt-px text-
|
|
29
|
+
entry.message && /* @__PURE__ */ jsx("div", { className: "mt-px text-overline text-muted-foreground/70", children: entry.message })
|
|
30
30
|
] }, idx);
|
|
31
31
|
}) });
|
|
32
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/backend/devtools/components/InterceptorActivity.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport type { InterceptorActivityEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-
|
|
5
|
-
"mappings": ";AAaM,cAcM,YAdN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport type { InterceptorActivityEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-status-success-icon', bg: 'bg-status-success-bg' },\n blocked: { text: 'text-status-error-icon', bg: 'bg-status-error-bg' },\n modified: { text: 'text-status-warning-icon', bg: 'bg-status-warning-bg' },\n}\n\nexport function InterceptorActivity({ entries }: { entries: InterceptorActivityEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No interceptor activity\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div key={idx} className={`mb-1 rounded p-1.5 px-2 text-xs ${classes.bg}`}>\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">{entry.interceptorId}</span>\n <span className={`text-overline font-semibold uppercase ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n <div className=\"mt-0.5 text-overline text-muted-foreground\">\n {entry.method} {entry.route} | {entry.durationMs}ms\n {entry.statusCode ? ` | ${entry.statusCode}` : ''}\n </div>\n {entry.message && (\n <div className=\"mt-px text-overline text-muted-foreground/70\">\n {entry.message}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAaM,cAcM,YAdN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAAA,EACxE,SAAS,EAAE,MAAM,0BAA0B,IAAI,qBAAqB;AAAA,EACpE,UAAU,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAC3E;AAEO,SAAS,oBAAoB,EAAE,QAAQ,GAA4C;AACxF,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,qCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE,qBAAC,SAAc,WAAW,mCAAmC,QAAQ,EAAE,IACrE;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,eAAc;AAAA,QACnD,oBAAC,UAAK,WAAW,yCAAyC,QAAQ,IAAI,IACnE,gBAAM,QACT;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,8CACZ;AAAA,cAAM;AAAA,QAAO;AAAA,QAAE,MAAM;AAAA,QAAM;AAAA,QAAI,MAAM;AAAA,QAAW;AAAA,QAChD,MAAM,aAAa,MAAM,MAAM,UAAU,KAAK;AAAA,SACjD;AAAA,MACC,MAAM,WACL,oBAAC,SAAI,WAAU,gDACZ,gBAAM,SACT;AAAA,SAdM,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -115,7 +115,7 @@ function ActionsDropdown({
|
|
|
115
115
|
{
|
|
116
116
|
ref: menuRef,
|
|
117
117
|
role: "menu",
|
|
118
|
-
className: "fixed w-52 rounded-md border bg-background p-1 shadow-md focus:outline-none z-
|
|
118
|
+
className: "fixed w-52 rounded-md border bg-background p-1 shadow-md focus-visible:outline-none z-dropdown",
|
|
119
119
|
onMouseEnter: handleMouseEnter,
|
|
120
120
|
onMouseLeave: handleMouseLeave,
|
|
121
121
|
style: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/forms/ActionsDropdown.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Zap, ChevronDown, Loader2, MoreHorizontal } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type ActionItem = {\n /** Unique key */\n id: string\n /** Display label */\n label: string\n /** Lucide icon component (optional) */\n icon?: React.ComponentType<{ className?: string }>\n /** Click handler */\n onSelect: () => void\n /** Disable the item */\n disabled?: boolean\n /** Show a loading spinner instead of the icon */\n loading?: boolean\n}\n\nexport type ActionsDropdownProps = {\n /** Items to render inside the dropdown */\n items: ActionItem[]\n /** Button label (default: translated 'Actions') */\n label?: string\n /** Trigger style */\n triggerMode?: 'label' | 'icon'\n /** Accessible label for icon trigger */\n ariaLabel?: string\n /** Button size (default: 'sm') */\n size?: 'sm' | 'default'\n}\n\nexport function ActionsDropdown({\n items,\n label,\n triggerMode = 'label',\n ariaLabel,\n size = 'sm',\n}: ActionsDropdownProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const btnRef = React.useRef<HTMLButtonElement>(null)\n const menuRef = React.useRef<HTMLDivElement>(null)\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null)\n const hoverTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)\n const [direction, setDirection] = React.useState<'down' | 'up'>('down')\n\n const resolvedLabel = label ?? t('ui.actions.actions', 'Actions')\n const resolvedAriaLabel = ariaLabel ?? resolvedLabel\n\n const updatePosition = React.useCallback(() => {\n if (!btnRef.current) return\n const rect = btnRef.current.getBoundingClientRect()\n setAnchorRect(rect)\n const spaceBelow = window.innerHeight - rect.bottom\n const spaceAbove = rect.top\n setDirection(spaceBelow < 200 && spaceAbove > spaceBelow ? 'up' : 'down')\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n updatePosition()\n function onDocClick(event: MouseEvent) {\n const target = event.target as Node\n if (\n menuRef.current && !menuRef.current.contains(target) &&\n btnRef.current && !btnRef.current.contains(target)\n ) {\n setOpen(false)\n }\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n setOpen(false)\n btnRef.current?.focus()\n }\n }\n function onScrollOrResize() {\n updatePosition()\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n window.addEventListener('scroll', onScrollOrResize, true)\n window.addEventListener('resize', onScrollOrResize)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, true)\n window.removeEventListener('resize', onScrollOrResize)\n }\n }, [open, updatePosition])\n\n React.useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n }\n }, [])\n\n const handleMouseEnter = () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n setOpen(true)\n }\n\n const handleMouseLeave = () => {\n hoverTimeoutRef.current = setTimeout(() => {\n setOpen(false)\n }, 150)\n }\n\n if (!items.length) return null\n\n return (\n <div\n className=\"relative inline-block\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <Button\n ref={btnRef}\n type=\"button\"\n variant=\"outline\"\n size={size}\n className={triggerMode === 'icon' ? 'px-2' : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label={resolvedAriaLabel}\n onClick={() => {\n setOpen((prev) => !prev)\n requestAnimationFrame(updatePosition)\n }}\n >\n {triggerMode === 'icon' ? (\n <>\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">{resolvedAriaLabel}</span>\n </>\n ) : (\n <>\n {resolvedLabel}\n <Zap className=\"size-4 ml-1\" />\n <ChevronDown className={`size-3.5 transition-transform duration-150 ${open ? 'rotate-180' : ''}`} />\n </>\n )}\n </Button>\n {open && anchorRect && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"fixed w-52 rounded-md border bg-background p-1 shadow-md focus:outline-none z-
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Zap, ChevronDown, Loader2, MoreHorizontal } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type ActionItem = {\n /** Unique key */\n id: string\n /** Display label */\n label: string\n /** Lucide icon component (optional) */\n icon?: React.ComponentType<{ className?: string }>\n /** Click handler */\n onSelect: () => void\n /** Disable the item */\n disabled?: boolean\n /** Show a loading spinner instead of the icon */\n loading?: boolean\n}\n\nexport type ActionsDropdownProps = {\n /** Items to render inside the dropdown */\n items: ActionItem[]\n /** Button label (default: translated 'Actions') */\n label?: string\n /** Trigger style */\n triggerMode?: 'label' | 'icon'\n /** Accessible label for icon trigger */\n ariaLabel?: string\n /** Button size (default: 'sm') */\n size?: 'sm' | 'default'\n}\n\nexport function ActionsDropdown({\n items,\n label,\n triggerMode = 'label',\n ariaLabel,\n size = 'sm',\n}: ActionsDropdownProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const btnRef = React.useRef<HTMLButtonElement>(null)\n const menuRef = React.useRef<HTMLDivElement>(null)\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null)\n const hoverTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)\n const [direction, setDirection] = React.useState<'down' | 'up'>('down')\n\n const resolvedLabel = label ?? t('ui.actions.actions', 'Actions')\n const resolvedAriaLabel = ariaLabel ?? resolvedLabel\n\n const updatePosition = React.useCallback(() => {\n if (!btnRef.current) return\n const rect = btnRef.current.getBoundingClientRect()\n setAnchorRect(rect)\n const spaceBelow = window.innerHeight - rect.bottom\n const spaceAbove = rect.top\n setDirection(spaceBelow < 200 && spaceAbove > spaceBelow ? 'up' : 'down')\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n updatePosition()\n function onDocClick(event: MouseEvent) {\n const target = event.target as Node\n if (\n menuRef.current && !menuRef.current.contains(target) &&\n btnRef.current && !btnRef.current.contains(target)\n ) {\n setOpen(false)\n }\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n setOpen(false)\n btnRef.current?.focus()\n }\n }\n function onScrollOrResize() {\n updatePosition()\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n window.addEventListener('scroll', onScrollOrResize, true)\n window.addEventListener('resize', onScrollOrResize)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, true)\n window.removeEventListener('resize', onScrollOrResize)\n }\n }, [open, updatePosition])\n\n React.useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n }\n }, [])\n\n const handleMouseEnter = () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n setOpen(true)\n }\n\n const handleMouseLeave = () => {\n hoverTimeoutRef.current = setTimeout(() => {\n setOpen(false)\n }, 150)\n }\n\n if (!items.length) return null\n\n return (\n <div\n className=\"relative inline-block\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <Button\n ref={btnRef}\n type=\"button\"\n variant=\"outline\"\n size={size}\n className={triggerMode === 'icon' ? 'px-2' : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label={resolvedAriaLabel}\n onClick={() => {\n setOpen((prev) => !prev)\n requestAnimationFrame(updatePosition)\n }}\n >\n {triggerMode === 'icon' ? (\n <>\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">{resolvedAriaLabel}</span>\n </>\n ) : (\n <>\n {resolvedLabel}\n <Zap className=\"size-4 ml-1\" />\n <ChevronDown className={`size-3.5 transition-transform duration-150 ${open ? 'rotate-180' : ''}`} />\n </>\n )}\n </Button>\n {open && anchorRect && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"fixed w-52 rounded-md border bg-background p-1 shadow-md focus-visible:outline-none z-dropdown\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n style={{\n top: direction === 'down' ? anchorRect.bottom + 4 : anchorRect.top - 4,\n left: anchorRect.right,\n transform: `translate(-100%, ${direction === 'down' ? '0' : '-100%'})`,\n }}\n >\n {items.map((item) => {\n const Icon = item.icon\n return (\n <Button\n key={item.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start\"\n role=\"menuitem\"\n disabled={item.disabled}\n onClick={() => {\n setOpen(false)\n item.onSelect()\n }}\n >\n {item.loading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : Icon ? (\n <Icon className=\"size-4\" />\n ) : (\n <span className=\"size-4\" />\n )}\n {item.label}\n </Button>\n )\n })}\n </div>,\n document.body,\n )}\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -28,17 +28,16 @@ function FormActionButtons({
|
|
|
28
28
|
Button,
|
|
29
29
|
{
|
|
30
30
|
type: "button",
|
|
31
|
-
variant: "outline",
|
|
31
|
+
variant: "destructive-outline",
|
|
32
32
|
onClick: onDelete,
|
|
33
33
|
disabled: isDeleting,
|
|
34
|
-
className: "text-red-600 border-red-200 hover:bg-red-50 rounded",
|
|
35
34
|
children: [
|
|
36
35
|
isDeleting ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 mr-2 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "size-4 mr-2" }),
|
|
37
36
|
resolvedDeleteLabel
|
|
38
37
|
]
|
|
39
38
|
}
|
|
40
39
|
) : null,
|
|
41
|
-
cancelHref ? /* @__PURE__ */ jsx(
|
|
40
|
+
cancelHref ? /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", children: /* @__PURE__ */ jsx(Link, { href: cancelHref, children: resolvedCancelLabel }) }) : null,
|
|
42
41
|
submit ? /* @__PURE__ */ jsxs(
|
|
43
42
|
Button,
|
|
44
43
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/forms/FormActionButtons.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Trash2, Save, Loader2 } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FormActionButtonsProps = {\n /** Extra action buttons rendered before the standard buttons */\n extraActions?: React.ReactNode\n /** Show the delete button */\n showDelete?: boolean\n /** Callback when delete is clicked */\n onDelete?: () => void\n /** Label for the delete button */\n deleteLabel?: string\n /** Whether the delete button shows a loading spinner */\n isDeleting?: boolean\n /** URL for the cancel link */\n cancelHref?: string\n /** Label for the cancel link */\n cancelLabel?: string\n /** Submit button configuration */\n submit?: {\n /** Form ID for the submit button (needed in header to trigger form submit) */\n formId?: string\n /** Whether the form is currently submitting */\n pending?: boolean\n /** Label while idle */\n label?: string\n /** Label while saving */\n pendingLabel?: string\n /** Optional icon for idle submit state */\n icon?: React.ComponentType<{ className?: string }>\n }\n /** When true, hides all buttons */\n hidden?: boolean\n}\n\nexport function FormActionButtons({\n extraActions,\n showDelete,\n onDelete,\n deleteLabel,\n isDeleting,\n cancelHref,\n cancelLabel,\n submit,\n hidden,\n}: FormActionButtonsProps) {\n const t = useT()\n\n if (hidden) return null\n\n const resolvedDeleteLabel = deleteLabel ?? t('ui.forms.actions.delete')\n const resolvedCancelLabel = cancelLabel ?? t('ui.forms.actions.cancel')\n const resolvedSubmitLabel = submit?.label ?? t('ui.forms.actions.save')\n const resolvedPendingLabel = submit?.pendingLabel ?? t('ui.forms.status.saving')\n const SubmitIcon = submit?.icon ?? Save\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {extraActions}\n {showDelete ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onDelete}\n disabled={isDeleting}\n
|
|
5
|
-
"mappings": ";AAiEQ,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Trash2, Save, Loader2 } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FormActionButtonsProps = {\n /** Extra action buttons rendered before the standard buttons */\n extraActions?: React.ReactNode\n /** Show the delete button */\n showDelete?: boolean\n /** Callback when delete is clicked */\n onDelete?: () => void\n /** Label for the delete button */\n deleteLabel?: string\n /** Whether the delete button shows a loading spinner */\n isDeleting?: boolean\n /** URL for the cancel link */\n cancelHref?: string\n /** Label for the cancel link */\n cancelLabel?: string\n /** Submit button configuration */\n submit?: {\n /** Form ID for the submit button (needed in header to trigger form submit) */\n formId?: string\n /** Whether the form is currently submitting */\n pending?: boolean\n /** Label while idle */\n label?: string\n /** Label while saving */\n pendingLabel?: string\n /** Optional icon for idle submit state */\n icon?: React.ComponentType<{ className?: string }>\n }\n /** When true, hides all buttons */\n hidden?: boolean\n}\n\nexport function FormActionButtons({\n extraActions,\n showDelete,\n onDelete,\n deleteLabel,\n isDeleting,\n cancelHref,\n cancelLabel,\n submit,\n hidden,\n}: FormActionButtonsProps) {\n const t = useT()\n\n if (hidden) return null\n\n const resolvedDeleteLabel = deleteLabel ?? t('ui.forms.actions.delete')\n const resolvedCancelLabel = cancelLabel ?? t('ui.forms.actions.cancel')\n const resolvedSubmitLabel = submit?.label ?? t('ui.forms.actions.save')\n const resolvedPendingLabel = submit?.pendingLabel ?? t('ui.forms.status.saving')\n const SubmitIcon = submit?.icon ?? Save\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {extraActions}\n {showDelete ? (\n <Button\n type=\"button\"\n variant=\"destructive-outline\"\n onClick={onDelete}\n disabled={isDeleting}\n >\n {isDeleting ? (\n <Loader2 className=\"size-4 mr-2 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4 mr-2\" />\n )}\n {resolvedDeleteLabel}\n </Button>\n ) : null}\n {cancelHref ? (\n <Button asChild variant=\"outline\">\n <Link href={cancelHref}>{resolvedCancelLabel}</Link>\n </Button>\n ) : null}\n {submit ? (\n <Button\n type=\"submit\"\n form={submit.formId}\n disabled={submit.pending}\n >\n {submit.pending ? <Loader2 className=\"size-4 mr-2 animate-spin\" /> : <SubmitIcon className=\"size-4 mr-2\" />}\n {submit.pending ? resolvedPendingLabel : resolvedSubmitLabel}\n </Button>\n ) : null}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAiEQ,SAOI,KAPJ;AA9DR,OAAO,UAAU;AACjB,SAAS,QAAQ,MAAM,eAAe;AACtC,SAAS,cAAc;AACvB,SAAS,YAAY;AAkCd,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,IAAI,KAAK;AAEf,MAAI,OAAQ,QAAO;AAEnB,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,QAAQ,SAAS,EAAE,uBAAuB;AACtE,QAAM,uBAAuB,QAAQ,gBAAgB,EAAE,wBAAwB;AAC/E,QAAM,aAAa,QAAQ,QAAQ;AAEnC,SACE,qBAAC,SAAI,WAAU,qCACZ;AAAA;AAAA,IACA,aACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QAET;AAAA,uBACC,oBAAC,WAAQ,WAAU,4BAA2B,IAE9C,oBAAC,UAAO,WAAU,eAAc;AAAA,UAEjC;AAAA;AAAA;AAAA,IACH,IACE;AAAA,IACH,aACC,oBAAC,UAAO,SAAO,MAAC,SAAQ,WACtB,8BAAC,QAAK,MAAM,YAAa,+BAAoB,GAC/C,IACE;AAAA,IACH,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAM,OAAO;AAAA,QACb,UAAU,OAAO;AAAA,QAEhB;AAAA,iBAAO,UAAU,oBAAC,WAAQ,WAAU,4BAA2B,IAAK,oBAAC,cAAW,WAAU,eAAc;AAAA,UACxG,OAAO,UAAU,uBAAuB;AAAA;AAAA;AAAA,IAC3C,IACE;AAAA,KACN;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -28,16 +28,16 @@ function PartialIndexBanner() {
|
|
|
28
28
|
const indexed = warning.indexedCount;
|
|
29
29
|
const hasCounts = typeof base === "number" && typeof indexed === "number";
|
|
30
30
|
const hasExcessIndexedRows = hasCounts && indexed > base;
|
|
31
|
-
return /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-col gap-3 rounded-md border border-
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-col gap-3 rounded-md border border-status-warning-border bg-status-warning-bg px-3 py-3 text-sm text-status-warning-text md:flex-row md:items-center md:justify-between", children: [
|
|
32
32
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 text-sm", children: [
|
|
33
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-
|
|
33
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-status-warning-text", children: [
|
|
34
34
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "size-4", "aria-hidden": "true" }),
|
|
35
35
|
/* @__PURE__ */ jsx("span", { children: t("query_index.banner.partial_title") })
|
|
36
36
|
] }),
|
|
37
|
-
/* @__PURE__ */ jsx("p", { className: "text-
|
|
38
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-
|
|
39
|
-
hasCounts && /* @__PURE__ */ jsx("p", { className: "text-xs text-
|
|
40
|
-
warning.scope === "global" && /* @__PURE__ */ jsx("p", { className: "text-xs text-
|
|
37
|
+
/* @__PURE__ */ jsx("p", { className: "text-status-warning-text", children: t("query_index.banner.partial_description") }),
|
|
38
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: t("query_index.banner.partial_entity", { entity: entityLabel }) }),
|
|
39
|
+
hasCounts && /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: hasExcessIndexedRows ? t("query_index.banner.partial_counts_excess", { indexed, total: base }) : t("query_index.banner.partial_counts", { indexed, total: base }) }),
|
|
40
|
+
warning.scope === "global" && /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: t("query_index.banner.partial_global_note") })
|
|
41
41
|
] }),
|
|
42
42
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
43
43
|
/* @__PURE__ */ jsx(
|
|
@@ -46,7 +46,7 @@ function PartialIndexBanner() {
|
|
|
46
46
|
asChild: true,
|
|
47
47
|
variant: "outline",
|
|
48
48
|
size: "sm",
|
|
49
|
-
className: "border-
|
|
49
|
+
className: "border-status-warning-border text-status-warning-text hover:bg-status-warning-bg",
|
|
50
50
|
children: /* @__PURE__ */ jsx(Link, { href: manageIndexesHref, children: t("query_index.banner.manage_indexes") })
|
|
51
51
|
}
|
|
52
52
|
),
|
|
@@ -57,7 +57,7 @@ function PartialIndexBanner() {
|
|
|
57
57
|
size: "sm",
|
|
58
58
|
type: "button",
|
|
59
59
|
onClick: () => dismissPartialIndexWarning(),
|
|
60
|
-
className: "text-
|
|
60
|
+
className: "text-status-warning-text hover:bg-status-warning-bg",
|
|
61
61
|
"aria-label": t("query_index.banner.dismiss"),
|
|
62
62
|
children: [
|
|
63
63
|
/* @__PURE__ */ jsx(X, { className: "mr-1 size-4", "aria-hidden": "true" }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/indexes/PartialIndexBanner.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { AlertTriangle, X } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { buildHrefWithReturnTo } from '@open-mercato/shared/lib/navigation/returnTo'\nimport { dismissPartialIndexWarning, usePartialIndexWarning } from './store'\n\nexport function PartialIndexBanner() {\n const t = useT()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const warning = usePartialIndexWarning()\n\n const returnTo = React.useMemo(() => {\n const query = searchParams?.toString() ?? ''\n if (!pathname) return null\n return query.length ? `${pathname}?${query}` : pathname\n }, [pathname, searchParams])\n const manageIndexesHref = React.useMemo(\n () => buildHrefWithReturnTo('/backend/query-indexes', returnTo),\n [returnTo],\n )\n\n if (!warning) return null\n\n const entityLabel = warning.entityLabel || warning.entity\n const base = warning.baseCount\n const indexed = warning.indexedCount\n const hasCounts = typeof base === 'number' && typeof indexed === 'number'\n const hasExcessIndexedRows = hasCounts && indexed > base\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 rounded-md border border-
|
|
5
|
-
"mappings": ";AAqCQ,SACE,KADF;AApCR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,aAAa,uBAAuB;AAC7C,SAAS,eAAe,SAAS;AACjC,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,4BAA4B,8BAA8B;AAE5D,SAAS,qBAAqB;AACnC,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,UAAU,uBAAuB;AAEvC,QAAM,WAAW,MAAM,QAAQ,MAAM;AACnC,UAAM,QAAQ,cAAc,SAAS,KAAK;AAC1C,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,MAAM,SAAS,GAAG,QAAQ,IAAI,KAAK,KAAK;AAAA,EACjD,GAAG,CAAC,UAAU,YAAY,CAAC;AAC3B,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,sBAAsB,0BAA0B,QAAQ;AAAA,IAC9D,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,QAAM,OAAO,QAAQ;AACrB,QAAM,UAAU,QAAQ;AACxB,QAAM,YAAY,OAAO,SAAS,YAAY,OAAO,YAAY;AACjE,QAAM,uBAAuB,aAAa,UAAU;AAEpD,SACE,qBAAC,SAAI,WAAU,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { AlertTriangle, X } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { buildHrefWithReturnTo } from '@open-mercato/shared/lib/navigation/returnTo'\nimport { dismissPartialIndexWarning, usePartialIndexWarning } from './store'\n\nexport function PartialIndexBanner() {\n const t = useT()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const warning = usePartialIndexWarning()\n\n const returnTo = React.useMemo(() => {\n const query = searchParams?.toString() ?? ''\n if (!pathname) return null\n return query.length ? `${pathname}?${query}` : pathname\n }, [pathname, searchParams])\n const manageIndexesHref = React.useMemo(\n () => buildHrefWithReturnTo('/backend/query-indexes', returnTo),\n [returnTo],\n )\n\n if (!warning) return null\n\n const entityLabel = warning.entityLabel || warning.entity\n const base = warning.baseCount\n const indexed = warning.indexedCount\n const hasCounts = typeof base === 'number' && typeof indexed === 'number'\n const hasExcessIndexedRows = hasCounts && indexed > base\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 rounded-md border border-status-warning-border bg-status-warning-bg px-3 py-3 text-sm text-status-warning-text md:flex-row md:items-center md:justify-between\">\n <div className=\"flex flex-col gap-2 text-sm\">\n <div className=\"flex items-center gap-2 font-medium text-status-warning-text\">\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n <span>{t('query_index.banner.partial_title')}</span>\n </div>\n <p className=\"text-status-warning-text\">\n {t('query_index.banner.partial_description')}\n </p>\n <p className=\"text-xs text-status-warning-text\">\n {t('query_index.banner.partial_entity', { entity: entityLabel })}\n </p>\n {hasCounts && (\n <p className=\"text-xs text-status-warning-text\">\n {hasExcessIndexedRows\n ? t('query_index.banner.partial_counts_excess', { indexed, total: base })\n : t('query_index.banner.partial_counts', { indexed, total: base })}\n </p>\n )}\n {warning.scope === 'global' && (\n <p className=\"text-xs text-status-warning-text\">\n {t('query_index.banner.partial_global_note')}\n </p>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n asChild\n variant=\"outline\"\n size=\"sm\"\n className=\"border-status-warning-border text-status-warning-text hover:bg-status-warning-bg\"\n >\n <Link href={manageIndexesHref}>\n {t('query_index.banner.manage_indexes')}\n </Link>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n type=\"button\"\n onClick={() => dismissPartialIndexWarning()}\n className=\"text-status-warning-text hover:bg-status-warning-bg\"\n aria-label={t('query_index.banner.dismiss')}\n >\n <X className=\"mr-1 size-4\" aria-hidden=\"true\" />\n {t('query_index.banner.dismiss')}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAqCQ,SACE,KADF;AApCR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,aAAa,uBAAuB;AAC7C,SAAS,eAAe,SAAS;AACjC,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,4BAA4B,8BAA8B;AAE5D,SAAS,qBAAqB;AACnC,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,UAAU,uBAAuB;AAEvC,QAAM,WAAW,MAAM,QAAQ,MAAM;AACnC,UAAM,QAAQ,cAAc,SAAS,KAAK;AAC1C,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,MAAM,SAAS,GAAG,QAAQ,IAAI,KAAK,KAAK;AAAA,EACjD,GAAG,CAAC,UAAU,YAAY,CAAC;AAC3B,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,sBAAsB,0BAA0B,QAAQ;AAAA,IAC9D,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,QAAM,OAAO,QAAQ;AACrB,QAAM,UAAU,QAAQ;AACxB,QAAM,YAAY,OAAO,SAAS,YAAY,OAAO,YAAY;AACjE,QAAM,uBAAuB,aAAa,UAAU;AAEpD,SACE,qBAAC,SAAI,WAAU,0LACb;AAAA,yBAAC,SAAI,WAAU,+BACb;AAAA,2BAAC,SAAI,WAAU,gEACb;AAAA,4BAAC,iBAAc,WAAU,UAAS,eAAY,QAAO;AAAA,QACrD,oBAAC,UAAM,YAAE,kCAAkC,GAAE;AAAA,SAC/C;AAAA,MACA,oBAAC,OAAE,WAAU,4BACV,YAAE,wCAAwC,GAC7C;AAAA,MACA,oBAAC,OAAE,WAAU,oCACV,YAAE,qCAAqC,EAAE,QAAQ,YAAY,CAAC,GACjE;AAAA,MACC,aACC,oBAAC,OAAE,WAAU,oCACV,iCACG,EAAE,4CAA4C,EAAE,SAAS,OAAO,KAAK,CAAC,IACtE,EAAE,qCAAqC,EAAE,SAAS,OAAO,KAAK,CAAC,GACrE;AAAA,MAED,QAAQ,UAAU,YACjB,oBAAC,OAAE,WAAU,oCACV,YAAE,wCAAwC,GAC7C;AAAA,OAEJ;AAAA,IACA,qBAAC,SAAI,WAAU,qCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,WAAU;AAAA,UAEV,8BAAC,QAAK,MAAM,mBACT,YAAE,mCAAmC,GACxC;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,MAAM,2BAA2B;AAAA,UAC1C,WAAU;AAAA,UACV,cAAY,EAAE,4BAA4B;AAAA,UAE1C;AAAA,gCAAC,KAAE,WAAU,eAAc,eAAY,QAAO;AAAA,YAC7C,EAAE,4BAA4B;AAAA;AAAA;AAAA,MACjC;AAAA,OACF;AAAA,KACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -200,7 +200,7 @@ function ComboboxInput({
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
),
|
|
203
|
-
showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-
|
|
203
|
+
showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-dropdown w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto", children: loading && touched ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: "Loading suggestions\u2026" }) : filteredSuggestions.map((option, index) => /* @__PURE__ */ jsxs(
|
|
204
204
|
Button,
|
|
205
205
|
{
|
|
206
206
|
type: "button",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/inputs/ComboboxInput.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n resolveLabel?: (value: string) => string\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n if (!map.has(option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n map.set(value, {\n value,\n label: resolveLabel?.(value) ?? value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Sync input with value when value changes externally and input is not focused\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to current value if custom values not allowed\n const currentOption = optionMap.get(value)\n setInput(currentOption?.label ?? value ?? '')\n setShowSuggestions(false)\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n resolveLabel?: (value: string) => string\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n if (!map.has(option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n map.set(value, {\n value,\n label: resolveLabel?.(value) ?? value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Sync input with value when value changes externally and input is not focused\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to current value if custom values not allowed\n const currentOption = optionMap.get(value)\n setInput(currentOption?.label ?? value ?? '')\n setShowSuggestions(false)\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-dropdown w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto\">\n {loading && touched ? (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">Loading suggestions\u2026</div>\n ) : (\n filteredSuggestions.map((option, index) => (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={[\n 'w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2',\n index === selectedIndex ? 'bg-accent' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectValue(option.value)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n <span className=\"font-medium\">{option.label}</span>\n {option.description ? (\n <span className=\"text-xs text-muted-foreground\">{option.description}</span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -94,7 +94,7 @@ function DatePicker({
|
|
|
94
94
|
className: cn(
|
|
95
95
|
"w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
|
|
96
96
|
"bg-background transition-colors",
|
|
97
|
-
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1",
|
|
97
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
98
98
|
"disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
|
|
99
99
|
readOnly && "cursor-default opacity-70",
|
|
100
100
|
!formattedValue && "text-muted-foreground",
|
|
@@ -125,7 +125,7 @@ function DatePicker({
|
|
|
125
125
|
{
|
|
126
126
|
type: "button",
|
|
127
127
|
onClick: handleToday,
|
|
128
|
-
className: "text-sm text-primary hover:underline focus:outline-none",
|
|
128
|
+
className: "text-sm text-primary hover:underline focus-visible:outline-none",
|
|
129
129
|
children: todayText
|
|
130
130
|
}
|
|
131
131
|
),
|
|
@@ -134,7 +134,7 @@ function DatePicker({
|
|
|
134
134
|
{
|
|
135
135
|
type: "button",
|
|
136
136
|
onClick: handleClear,
|
|
137
|
-
className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto",
|
|
137
|
+
className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
|
|
138
138
|
children: clearText
|
|
139
139
|
}
|
|
140
140
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/inputs/DatePicker.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n showTodayButton?: boolean\n showClearButton?: boolean\n closeOnSelect?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n showTodayButton = true,\n showClearButton = true,\n closeOnSelect = true,\n minDate,\n maxDate,\n}: DatePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.datePicker.placeholder', 'Pick a date')\n const todayText = t('ui.datePicker.todayButton', 'Today')\n const clearText = t('ui.datePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const next = new Date(day)\n next.setHours(0, 0, 0, 0)\n onChange(next)\n if (closeOnSelect) setOpen(false)\n },\n [onChange, closeOnSelect]\n )\n\n const handleToday = React.useCallback(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n onChange(today)\n setOpen(false)\n }, [onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n showTodayButton?: boolean\n showClearButton?: boolean\n closeOnSelect?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n showTodayButton = true,\n showClearButton = true,\n closeOnSelect = true,\n minDate,\n maxDate,\n}: DatePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.datePicker.placeholder', 'Pick a date')\n const todayText = t('ui.datePicker.todayButton', 'Today')\n const clearText = t('ui.datePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const next = new Date(day)\n next.setHours(0, 0, 0, 0)\n onChange(next)\n if (closeOnSelect) setOpen(false)\n },\n [onChange, closeOnSelect]\n )\n\n const handleToday = React.useCallback(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n onChange(today)\n setOpen(false)\n }, [onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus-visible:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -118,7 +118,7 @@ function DateTimePicker({
|
|
|
118
118
|
className: cn(
|
|
119
119
|
"w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
|
|
120
120
|
"bg-background transition-colors",
|
|
121
|
-
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1",
|
|
121
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
122
122
|
"disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
|
|
123
123
|
readOnly && "cursor-default opacity-70",
|
|
124
124
|
!formattedValue && "text-muted-foreground",
|
|
@@ -164,7 +164,7 @@ function DateTimePicker({
|
|
|
164
164
|
{
|
|
165
165
|
type: "button",
|
|
166
166
|
onClick: handleToday,
|
|
167
|
-
className: "text-sm text-primary hover:underline focus:outline-none",
|
|
167
|
+
className: "text-sm text-primary hover:underline focus-visible:outline-none",
|
|
168
168
|
children: todayText
|
|
169
169
|
}
|
|
170
170
|
),
|
|
@@ -173,7 +173,7 @@ function DateTimePicker({
|
|
|
173
173
|
{
|
|
174
174
|
type: "button",
|
|
175
175
|
onClick: handleClear,
|
|
176
|
-
className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto",
|
|
176
|
+
className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
|
|
177
177
|
children: clearText
|
|
178
178
|
}
|
|
179
179
|
)
|