@mastra/playground-ui 68.0.0-alpha.1 → 68.0.0-alpha.2
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/dist/{DataCodeSection-CcPmJPTp.cjs → DataCodeSection-CFxXsQWH.cjs} +3 -3
- package/dist/DataCodeSection-CFxXsQWH.cjs.map +1 -0
- package/dist/{DataCodeSection-KJRyRD1Q.js → DataCodeSection-PY9XEg2C.js} +3 -3
- package/dist/DataCodeSection-PY9XEg2C.js.map +1 -0
- package/dist/{DataPanel-BwB1Oifd.cjs → DataPanel-Coc9h35I.cjs} +2 -2
- package/dist/{DataPanel-BwB1Oifd.cjs.map → DataPanel-Coc9h35I.cjs.map} +1 -1
- package/dist/{DataPanel-Bv4M17xO.js → DataPanel-IgB9D5PO.js} +2 -2
- package/dist/{DataPanel-Bv4M17xO.js.map → DataPanel-IgB9D5PO.js.map} +1 -1
- package/dist/{FilterBar-BO-vvvyq.js → FilterBar-BgW2dqRQ.js} +7 -7
- package/dist/FilterBar-BgW2dqRQ.js.map +1 -0
- package/dist/{FilterBar-Buw0tv51.cjs → FilterBar-CQl04O6t.cjs} +7 -7
- package/dist/FilterBar-CQl04O6t.cjs.map +1 -0
- package/dist/{MetricsTable-D-aZf3dk.cjs → MetricsTable-BSl81oNe.cjs} +44 -9
- package/dist/MetricsTable-BSl81oNe.cjs.map +1 -0
- package/dist/{MetricsTable-CRPeLHe1.js → MetricsTable-DID6LRoP.js} +44 -9
- package/dist/MetricsTable-DID6LRoP.js.map +1 -0
- package/dist/{ask-user-DdYz56qH.cjs → ask-user-C1p2PEYe.cjs} +2 -2
- package/dist/ask-user-C1p2PEYe.cjs.map +1 -0
- package/dist/{ask-user-B225wzWc.js → ask-user-DPznrqGO.js} +2 -2
- package/dist/ask-user-DPznrqGO.js.map +1 -0
- package/dist/chart-plot.css +5 -4
- package/dist/{combobox-CtCK0mNx.js → combobox-D21no8t5.js} +4 -4
- package/dist/{combobox-CtCK0mNx.js.map → combobox-D21no8t5.js.map} +1 -1
- package/dist/{combobox-CMx2ayFN.cjs → combobox-DIT_6xiG.cjs} +4 -4
- package/dist/combobox-DIT_6xiG.cjs.map +1 -0
- package/dist/{combobox-parts-ScKcYjMR.cjs → combobox-parts-C4phOq4t.cjs} +2 -2
- package/dist/combobox-parts-C4phOq4t.cjs.map +1 -0
- package/dist/{combobox-parts-C1CugUAU.js → combobox-parts-D90ir0Py.js} +3 -3
- package/dist/combobox-parts-D90ir0Py.js.map +1 -0
- package/dist/components/Combobox.cjs.js +2 -2
- package/dist/components/Combobox.es.js +2 -2
- package/dist/components/Command.cjs.js +1 -1
- package/dist/components/Command.cjs.js.map +1 -1
- package/dist/components/Command.es.js +1 -1
- package/dist/components/Command.es.js.map +1 -1
- package/dist/components/DataCodeSection.cjs.js +1 -1
- package/dist/components/DataCodeSection.es.js +1 -1
- package/dist/components/DataList.cjs.js +1 -1
- package/dist/components/DataList.es.js +1 -1
- package/dist/components/DataPanel.cjs.js +1 -1
- package/dist/components/DataPanel.es.js +1 -1
- package/dist/components/DateTimePicker.cjs.js +1 -1
- package/dist/components/DateTimePicker.cjs.js.map +1 -1
- package/dist/components/DateTimePicker.es.js +1 -1
- package/dist/components/DateTimePicker.es.js.map +1 -1
- package/dist/components/FilterBar.cjs.js +3 -3
- package/dist/components/FilterBar.es.js +3 -3
- package/dist/components/FormFieldBlocks.cjs.js +1 -1
- package/dist/components/FormFieldBlocks.cjs.js.map +1 -1
- package/dist/components/FormFieldBlocks.es.js +1 -1
- package/dist/components/FormFieldBlocks.es.js.map +1 -1
- package/dist/components/MetricsTable.cjs.js +1 -1
- package/dist/components/MetricsTable.es.js +1 -1
- package/dist/components/PropertyFilter.cjs.js +3 -3
- package/dist/components/PropertyFilter.cjs.js.map +1 -1
- package/dist/components/PropertyFilter.es.js +3 -3
- package/dist/components/PropertyFilter.es.js.map +1 -1
- package/dist/components/SavedViews.cjs.js +1 -1
- package/dist/components/SavedViews.es.js +1 -1
- package/dist/components/Sidebar.cjs.js +8 -8
- package/dist/components/Sidebar.cjs.js.map +1 -1
- package/dist/components/Sidebar.es.js +9 -9
- package/dist/components/Sidebar.es.js.map +1 -1
- package/dist/components/ai/ask-user.cjs.js +1 -1
- package/dist/components/ai/ask-user.es.js +1 -1
- package/dist/domains/chat/tools/badges/ask-user-badge.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/ask-user-badge.es.js +1 -1
- package/dist/domains/dashboards/kinds/table/table-view.cjs.js +1 -1
- package/dist/domains/dashboards/kinds/table/table-view.es.js +1 -1
- package/dist/domains/dashboards/metrics-dashboard.cjs.js +1 -1
- package/dist/domains/dashboards/metrics-dashboard.cjs.js.map +1 -1
- package/dist/domains/dashboards/metrics-dashboard.es.js +1 -1
- package/dist/domains/dashboards/metrics-dashboard.es.js.map +1 -1
- package/dist/domains/datasets/components/save-as-dataset-item-dialog.cjs.js +1 -1
- package/dist/domains/datasets/components/save-as-dataset-item-dialog.es.js +1 -1
- package/dist/domains/logs/components/log-data-panel.cjs.js +1 -1
- package/dist/domains/logs/components/log-data-panel.es.js +1 -1
- package/dist/domains/logs/components/logs-saved-views.cjs.js +1 -1
- package/dist/domains/logs/components/logs-saved-views.es.js +1 -1
- package/dist/domains/logs/components/logs-toolbar.cjs.js +1 -1
- package/dist/domains/logs/components/logs-toolbar.es.js +1 -1
- package/dist/domains/metrics/components/breakdown/breakdown-table.cjs.js +2 -2
- package/dist/domains/metrics/components/breakdown/breakdown-table.cjs.js.map +1 -1
- package/dist/domains/metrics/components/breakdown/breakdown-table.es.js +2 -2
- package/dist/domains/metrics/components/breakdown/breakdown-table.es.js.map +1 -1
- package/dist/domains/metrics/components/metrics-time-range-chip.cjs.js +1 -1
- package/dist/domains/metrics/components/metrics-time-range-chip.es.js +1 -1
- package/dist/domains/observability/saved-views/observability-saved-views.cjs.js +1 -1
- package/dist/domains/observability/saved-views/observability-saved-views.es.js +1 -1
- package/dist/domains/observability/saved-views.cjs.js +1 -1
- package/dist/domains/observability/saved-views.es.js +1 -1
- package/dist/domains/observability.cjs.js +1 -1
- package/dist/domains/observability.es.js +1 -1
- package/dist/domains/scores/components/score-data-panel.cjs.js +1 -1
- package/dist/domains/scores/components/score-data-panel.es.js +1 -1
- package/dist/domains/scores/components/span-scoring.cjs.js +3 -3
- package/dist/domains/scores/components/span-scoring.cjs.js.map +1 -1
- package/dist/domains/scores/components/span-scoring.es.js +3 -3
- package/dist/domains/scores/components/span-scoring.es.js.map +1 -1
- package/dist/domains/skills/skill-simple-form.cjs.js +1 -1
- package/dist/domains/skills/skill-simple-form.cjs.js.map +1 -1
- package/dist/domains/skills/skill-simple-form.es.js +1 -1
- package/dist/domains/skills/skill-simple-form.es.js.map +1 -1
- package/dist/domains/spans/components/spans-explorer-body.cjs.js +1 -1
- package/dist/domains/spans/components/spans-explorer-body.es.js +1 -1
- package/dist/domains/spans/components/spans-filter-bar.cjs.js +3 -3
- package/dist/domains/spans/components/spans-filter-bar.cjs.js.map +1 -1
- package/dist/domains/spans/components/spans-filter-bar.es.js +3 -3
- package/dist/domains/spans/components/spans-filter-bar.es.js.map +1 -1
- package/dist/domains/spans/hooks/use-spans-filter-bar.cjs.js +1 -1
- package/dist/domains/spans/hooks/use-spans-filter-bar.es.js +1 -1
- package/dist/domains/threads/components/threads-explorer-body.cjs.js +1 -1
- package/dist/domains/threads/components/threads-explorer-body.es.js +1 -1
- package/dist/domains/threads/components/threads-filter-bar.cjs.js +3 -3
- package/dist/domains/threads/components/threads-filter-bar.cjs.js.map +1 -1
- package/dist/domains/threads/components/threads-filter-bar.es.js +3 -3
- package/dist/domains/threads/components/threads-filter-bar.es.js.map +1 -1
- package/dist/domains/threads/hooks/use-threads-filter-bar.cjs.js +1 -1
- package/dist/domains/threads/hooks/use-threads-filter-bar.es.js +1 -1
- package/dist/domains/traces/components/feedback-thread.cjs.js +1 -1
- package/dist/domains/traces/components/feedback-thread.cjs.js.map +1 -1
- package/dist/domains/traces/components/feedback-thread.es.js +1 -1
- package/dist/domains/traces/components/feedback-thread.es.js.map +1 -1
- package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
- package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
- package/dist/domains/traces/components/span-summary-description.cjs.js +1 -1
- package/dist/domains/traces/components/span-summary-description.es.js +1 -1
- package/dist/domains/traces/components/thread-trace/thread-trace-details.cjs.js +1 -1
- package/dist/domains/traces/components/thread-trace/thread-trace-details.es.js +1 -1
- package/dist/domains/traces/components/trace-columns-menu.cjs.js +3 -3
- package/dist/domains/traces/components/trace-columns-menu.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-columns-menu.es.js +3 -3
- package/dist/domains/traces/components/trace-columns-menu.es.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +2 -2
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +2 -2
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-id-button.cjs.js +1 -1
- package/dist/domains/traces/components/trace-id-button.es.js +1 -1
- package/dist/domains/traces/components/trace-summary-description.cjs.js +1 -1
- package/dist/domains/traces/components/trace-summary-description.es.js +1 -1
- package/dist/domains/traces/components/trace-thread-panel.cjs.js +1 -1
- package/dist/domains/traces/components/trace-thread-panel.es.js +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.cjs.js +3 -3
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.cjs.js.map +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.es.js +3 -3
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.es.js.map +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.cjs.js +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.es.js +1 -1
- package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.cjs.js +1 -1
- package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.es.js +1 -1
- package/dist/domains/workflows/components/workflow-combobox.cjs.js +2 -2
- package/dist/domains/workflows/components/workflow-combobox.cjs.js.map +1 -1
- package/dist/domains/workflows/components/workflow-combobox.es.js +2 -2
- package/dist/domains/workflows/components/workflow-combobox.es.js.map +1 -1
- package/dist/domains/workflows/workflow/input/workflow-processor-input.cjs.js +1 -1
- package/dist/domains/workflows/workflow/input/workflow-processor-input.cjs.js.map +1 -1
- package/dist/domains/workflows/workflow/input/workflow-processor-input.es.js +1 -1
- package/dist/domains/workflows/workflow/input/workflow-processor-input.es.js.map +1 -1
- package/dist/domains/workspace/components/workspace-add-skill-dialog.cjs.js +1 -1
- package/dist/domains/workspace/components/workspace-add-skill-dialog.cjs.js.map +1 -1
- package/dist/domains/workspace/components/workspace-add-skill-dialog.es.js +1 -1
- package/dist/domains/workspace/components/workspace-add-skill-dialog.es.js.map +1 -1
- package/dist/{filter-bar-chip-B4sV4gDm.js → filter-bar-chip-CABeKrtf.js} +4 -4
- package/dist/{filter-bar-chip-B4sV4gDm.js.map → filter-bar-chip-CABeKrtf.js.map} +1 -1
- package/dist/{filter-bar-chip-CIEsWcEw.cjs → filter-bar-chip-Cg-UbIwP.cjs} +4 -4
- package/dist/{filter-bar-chip-CIEsWcEw.cjs.map → filter-bar-chip-Cg-UbIwP.cjs.map} +1 -1
- package/dist/{filter-bar-time-range-DvuaFnkI.cjs → filter-bar-time-range-BA-pXMlo.cjs} +2 -2
- package/dist/{filter-bar-time-range-DvuaFnkI.cjs.map → filter-bar-time-range-BA-pXMlo.cjs.map} +1 -1
- package/dist/{filter-bar-time-range-CXQMBgpz.js → filter-bar-time-range-mg9JeYue.js} +2 -2
- package/dist/{filter-bar-time-range-CXQMBgpz.js.map → filter-bar-time-range-mg9JeYue.js.map} +1 -1
- package/dist/layout/tabbed-container.cjs.js +1 -1
- package/dist/layout/tabbed-container.es.js +1 -1
- package/dist/{observability-saved-views-BBam8Fr5.js → observability-saved-views-CjKTEp1V.js} +3 -3
- package/dist/observability-saved-views-CjKTEp1V.js.map +1 -0
- package/dist/{observability-saved-views-BAzxxoAr.cjs → observability-saved-views-Daizz4tU.cjs} +3 -3
- package/dist/observability-saved-views-Daizz4tU.cjs.map +1 -0
- package/dist/primitives/chart-plot.cjs.js +8 -6
- package/dist/primitives/chart-plot.cjs.js.map +1 -1
- package/dist/primitives/chart-plot.es.js +8 -6
- package/dist/primitives/chart-plot.es.js.map +1 -1
- package/dist/primitives/control-icon.cjs.js.map +1 -1
- package/dist/primitives/control-icon.es.js.map +1 -1
- package/dist/{property-filter-applied-p3dTTDdb.js → property-filter-applied--U5EZdaA.js} +2 -2
- package/dist/property-filter-applied--U5EZdaA.js.map +1 -0
- package/dist/{property-filter-applied-BCeRLcXb.cjs → property-filter-applied-BkkIObRq.cjs} +2 -2
- package/dist/property-filter-applied-BkkIObRq.cjs.map +1 -0
- package/dist/src/ds/components/MetricsTable/metrics-table-rows.d.ts +10 -3
- package/dist/src/ds/components/MetricsTable/metrics-table.d.ts +1 -1
- package/dist/style.css +14 -1
- package/dist/{tabbed-container-DQU7pVio.cjs → tabbed-container-B4lCBgRP.cjs} +2 -2
- package/dist/{tabbed-container-DQU7pVio.cjs.map → tabbed-container-B4lCBgRP.cjs.map} +1 -1
- package/dist/{tabbed-container-5j6dhoRX.js → tabbed-container-DI1GI1Qv.js} +2 -2
- package/dist/{tabbed-container-5j6dhoRX.js.map → tabbed-container-DI1GI1Qv.js.map} +1 -1
- package/oxlint/index.js +90 -0
- package/package.json +8 -8
- package/theme.css +4 -3
- package/dist/DataCodeSection-CcPmJPTp.cjs.map +0 -1
- package/dist/DataCodeSection-KJRyRD1Q.js.map +0 -1
- package/dist/FilterBar-BO-vvvyq.js.map +0 -1
- package/dist/FilterBar-Buw0tv51.cjs.map +0 -1
- package/dist/MetricsTable-CRPeLHe1.js.map +0 -1
- package/dist/MetricsTable-D-aZf3dk.cjs.map +0 -1
- package/dist/ask-user-B225wzWc.js.map +0 -1
- package/dist/ask-user-DdYz56qH.cjs.map +0 -1
- package/dist/combobox-CMx2ayFN.cjs.map +0 -1
- package/dist/combobox-parts-C1CugUAU.js.map +0 -1
- package/dist/combobox-parts-ScKcYjMR.cjs.map +0 -1
- package/dist/observability-saved-views-BAzxxoAr.cjs.map +0 -1
- package/dist/observability-saved-views-BBam8Fr5.js.map +0 -1
- package/dist/property-filter-applied-BCeRLcXb.cjs.map +0 -1
- package/dist/property-filter-applied-p3dTTDdb.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as DateTimeRangePicker } from "./date-time-range-picker-DKh1K9Iy.js";
|
|
2
|
-
import { p as useFilterBarItemKeys, y as useFilterBarContext } from "./filter-bar-chip-
|
|
2
|
+
import { p as useFilterBarItemKeys, y as useFilterBarContext } from "./filter-bar-chip-CABeKrtf.js";
|
|
3
3
|
import { useRef } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { CalendarIcon } from "lucide-react";
|
|
@@ -57,4 +57,4 @@ function FilterBarTimeRange(props) {
|
|
|
57
57
|
}
|
|
58
58
|
export { FilterBarTimeRange as i, FILTER_BAR_TIME_RANGE_FIELD_ID as n, FILTER_BAR_TIME_RANGE_ITEM as r, FILTER_BAR_TIME_RANGE_FIELD as t };
|
|
59
59
|
|
|
60
|
-
//# sourceMappingURL=filter-bar-time-range-
|
|
60
|
+
//# sourceMappingURL=filter-bar-time-range-mg9JeYue.js.map
|
package/dist/{filter-bar-time-range-CXQMBgpz.js.map → filter-bar-time-range-mg9JeYue.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-bar-time-range-
|
|
1
|
+
{"version":3,"file":"filter-bar-time-range-mg9JeYue.js","names":[],"sources":["../src/ds/components/FilterBar/filter-bar-time-range.tsx"],"sourcesContent":["/* eslint-disable react-refresh/only-export-components */\nimport { CalendarIcon } from 'lucide-react';\nimport { useRef } from 'react';\nimport { FILTER_BAR_CONTROL_SIZE } from './filter-bar-chip';\nimport { useFilterBarContext } from './filter-bar-context';\nimport type { FilterBarField, FilterBarItem } from './types';\nimport { useFilterBarItemKeys } from './use-filter-bar-item-keys';\nimport { DateTimeRangePicker } from '@/ds/components/DateTimeRangePicker/date-time-range-picker';\nimport type { DateTimeRangePickerProps } from '@/ds/components/DateTimeRangePicker/date-time-range-picker';\n\nexport const FILTER_BAR_TIME_RANGE_FIELD_ID = 'timeRange';\n\n/**\n * Synthetic field backing the time range control. Hidden from the input's field step (the\n * range cannot be added twice) but registered so the bar resolves its label and takes it into\n * keyboard navigation. Add it to the bar's `fields` and `FILTER_BAR_TIME_RANGE_ITEM` to its\n * `items`, then render `FilterBar.TimeRange` for that item from `FilterBar.Chips`.\n */\nexport const FILTER_BAR_TIME_RANGE_FIELD: FilterBarField = {\n id: FILTER_BAR_TIME_RANGE_FIELD_ID,\n label: 'Time',\n icon: CalendarIcon,\n type: 'text',\n operators: ['is'],\n hidden: true,\n};\n\nexport const FILTER_BAR_TIME_RANGE_ITEM: FilterBarItem = {\n id: FILTER_BAR_TIME_RANGE_FIELD_ID,\n fieldId: FILTER_BAR_TIME_RANGE_FIELD_ID,\n operatorId: 'is',\n value: '',\n};\n\nexport type FilterBarTimeRangeProps = Omit<DateTimeRangePickerProps, 'size' | 'ref'>;\n\n/**\n * A filter bar's time range: the `DateTimeRangePicker` itself at the bar's rung, so it looks and\n * behaves exactly as it does anywhere else, reset × included. It scopes the bar rather than\n * filtering it, so it is not a removable chip; the wrapper only joins it to the bar's arrow-key\n * order.\n */\nexport function FilterBarTimeRange(props: FilterBarTimeRangeProps) {\n const ctx = useFilterBarContext();\n const rootRef = useRef<HTMLDivElement>(null);\n const { onKeyDown } = useFilterBarItemKeys({\n item: FILTER_BAR_TIME_RANGE_ITEM,\n rootRef,\n pinned: true,\n removable: false,\n segmentSelector: 'button',\n });\n\n return (\n <div\n ref={rootRef}\n role=\"group\"\n aria-label=\"Time range\"\n data-slot=\"filter-bar-time-range\"\n className=\"flex\"\n onKeyDown={onKeyDown}\n >\n <DateTimeRangePicker\n {...props}\n size={FILTER_BAR_CONTROL_SIZE}\n ref={el => ctx.registerSegment(FILTER_BAR_TIME_RANGE_ITEM.id, 'value', el)}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;AAUA,IAAa,iCAAiC;;;;;;;AAQ9C,IAAa,8BAA8C;CACzD,IAAI;CACJ,OAAO;CACP,MAAM;CACN,MAAM;CACN,WAAW,CAAC,IAAI;CAChB,QAAQ;AACV;AAEA,IAAa,6BAA4C;CACvD,IAAI;CACJ,SAAS;CACT,YAAY;CACZ,OAAO;AACT;;;;;;;AAUA,SAAgB,mBAAmB,OAAgC;CACjE,MAAM,MAAM,oBAAoB;CAChC,MAAM,UAAU,OAAuB,IAAI;CAC3C,MAAM,EAAE,cAAc,qBAAqB;EACzC,MAAM;EACN;EACA,QAAQ;EACR,WAAW;EACX,iBAAiB;CACnB,CAAC;CAED,OACE,oBAAC,OAAD;EACE,KAAK;EACL,MAAK;EACL,cAAW;EACX,aAAU;EACV,WAAU;EACC;EAEX,UAAA,oBAAC,qBAAD;GACE,GAAI;GACJ,MAAA;GACA,MAAK,OAAM,IAAI,gBAAgB,2BAA2B,IAAI,SAAS,EAAE;EAC1E,CAAA;CACE,CAAA;AAET"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_tabbed_container = require("../tabbed-container-
|
|
2
|
+
const require_tabbed_container = require("../tabbed-container-B4lCBgRP.cjs");
|
|
3
3
|
exports.TabbedContainer = require_tabbed_container.TabbedContainer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as TabbedContainer } from "../tabbed-container-
|
|
1
|
+
export { t as TabbedContainer } from "../tabbed-container-DI1GI1Qv.js";
|
package/dist/{observability-saved-views-BBam8Fr5.js → observability-saved-views-CjKTEp1V.js}
RENAMED
|
@@ -5,7 +5,7 @@ import { t as Input } from "./input-0l1uzOBZ.js";
|
|
|
5
5
|
import { t as DropdownMenu } from "./dropdown-menu-B4jY3J9e.js";
|
|
6
6
|
import { Field, FieldError } from "./components/Field.es.js";
|
|
7
7
|
import { i as PopoverTrigger, n as Popover, r as PopoverContent } from "./popover-CzHvTPk2.js";
|
|
8
|
-
import { _ as ComboboxRoot, b as ComboboxTrigger, g as ComboboxList, o as ComboboxContent, p as ComboboxItemEnd, s as ComboboxEmpty, u as ComboboxItem, v as ComboboxSearch } from "./combobox-parts-
|
|
8
|
+
import { _ as ComboboxRoot, b as ComboboxTrigger, g as ComboboxList, o as ComboboxContent, p as ComboboxItemEnd, s as ComboboxEmpty, u as ComboboxItem, v as ComboboxSearch } from "./combobox-parts-D90ir0Py.js";
|
|
9
9
|
import { useSavedViewsSource } from "./domains/observability/saved-views/saved-views-source.es.js";
|
|
10
10
|
import { useHostedSavedViews } from "./domains/observability/saved-views/use-hosted-saved-views.es.js";
|
|
11
11
|
import { useObservabilityHeaderSlot } from "./domains/observability/components/observability-header-slot.es.js";
|
|
@@ -87,7 +87,7 @@ function SavedViewPicker({ views, defaultLabel, newViewSettings, describeView, c
|
|
|
87
87
|
}), /* @__PURE__ */ jsxs(ComboboxContent, {
|
|
88
88
|
align: "end",
|
|
89
89
|
children: [
|
|
90
|
-
/* @__PURE__ */ jsx(ComboboxSearch, { placeholder: "Search views
|
|
90
|
+
/* @__PURE__ */ jsx(ComboboxSearch, { placeholder: "Search views" }),
|
|
91
91
|
/* @__PURE__ */ jsx(ComboboxEmpty, { children: "No views found." }),
|
|
92
92
|
/* @__PURE__ */ jsx(ComboboxList, { children: (item) => {
|
|
93
93
|
const view = item.viewId ? viewsById.get(item.viewId) : void 0;
|
|
@@ -296,4 +296,4 @@ function HostedSavedViewsBar({ page, searchParams, setSearchParams, columns, def
|
|
|
296
296
|
}
|
|
297
297
|
export { ObservabilitySavedViews as t };
|
|
298
298
|
|
|
299
|
-
//# sourceMappingURL=observability-saved-views-
|
|
299
|
+
//# sourceMappingURL=observability-saved-views-CjKTEp1V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability-saved-views-CjKTEp1V.js","names":["_Fragment"],"sources":["../src/ds/components/SavedViews/saved-view-picker.tsx","../src/domains/observability/saved-views/observability-saved-views.tsx"],"sourcesContent":["import { CopyIcon, EllipsisIcon, LayersIcon, LayersPlusIcon, TextCursorInputIcon, Trash2Icon } from 'lucide-react';\nimport { useRef, useState } from 'react';\nimport type { FormEvent, ReactNode, RefObject } from 'react';\nimport { MAX_SAVED_VIEW_NAME_CHARS } from './saved-view-schema';\nimport type { SavedView } from './saved-view-schema';\nimport type { SavedViewsController } from './use-saved-views';\nimport { Button } from '@/ds/components/Button/Button';\nimport {\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxItemEnd,\n ComboboxList,\n ComboboxRoot,\n ComboboxSearch,\n ComboboxTrigger,\n} from '@/ds/components/Combobox/combobox-parts';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu';\nimport { Field, FieldError } from '@/ds/components/Field';\nimport { Input } from '@/ds/components/Input/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ds/components/Popover';\nimport { Txt } from '@/ds/components/Txt';\nimport { cn } from '@/lib/utils';\n\nexport type SavedViewPickerProps<TSettings> = {\n views: SavedViewsController<TSettings>;\n /** Names the page's unfiltered state, e.g. \"All traces\". */\n defaultLabel: string;\n newViewSettings: NoInfer<TSettings>;\n /** Muted text after a view in the list, e.g. \"Shared\". */\n describeView?: (view: SavedView<TSettings>) => ReactNode;\n /** Whether a view can be renamed, deleted or overwritten. Others can still be applied and duplicated. */\n canEdit?: (view: SavedView<TSettings>) => boolean;\n /** Whether new views can be saved here (save as new view, duplicate). Defaults to true. */\n canCreate?: boolean;\n 'aria-label'?: string;\n className?: string;\n};\n\ntype PickerItem = { value: string; label: string; viewId: string | undefined };\n\nconst DEFAULT_ITEM_VALUE = '';\n\n/**\n * A compact saved-views control for a page header: a searchable view picker, the active view's\n * actions, and save / reset once the page differs from the view. Driven by the same controller\n * as `SavedViewTabs`.\n */\nexport function SavedViewPicker<TSettings>({\n views,\n defaultLabel,\n newViewSettings,\n describeView,\n canEdit = () => true,\n canCreate = true,\n 'aria-label': ariaLabel = 'Views',\n className,\n}: SavedViewPickerProps<TSettings>) {\n const anchorRef = useRef<HTMLDivElement>(null);\n const [renaming, setRenaming] = useState(false);\n const { draft, activeView } = views;\n const creating = draft !== undefined && draft.viewId === undefined;\n const activeUnsaved = !creating && draft?.viewId !== undefined && views.unsaved;\n const editable = activeView !== undefined && canEdit(activeView);\n\n const items: PickerItem[] = [\n { value: DEFAULT_ITEM_VALUE, label: defaultLabel, viewId: undefined },\n ...views.views.map(view => ({ value: view.id, label: view.name, viewId: view.id })),\n ];\n const selected = items.find(item => item.viewId === activeView?.id) ?? items[0];\n const viewsById = new Map(views.views.map(view => [view.id, view]));\n\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className={cn('flex min-w-0 flex-wrap items-center justify-end gap-1.5', className)}\n >\n {views.error && !creating && !renaming && (\n <Txt role=\"alert\" variant=\"caption\" className=\"min-w-0 truncate text-destructive-foreground\">\n {views.error}\n </Txt>\n )}\n {activeUnsaved && (\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" disabled={views.pending} onClick={views.discard}>\n Reset\n </Button>\n {editable && (\n <Button type=\"button\" variant=\"default\" size=\"sm\" disabled={views.pending} onClick={views.save}>\n Save changes\n </Button>\n )}\n </div>\n )}\n <div ref={anchorRef} className=\"flex min-w-0 items-center gap-0.5\">\n <ComboboxRoot\n items={items}\n value={selected}\n onValueChange={(item: PickerItem | null) => {\n if (item) views.select(item.viewId);\n }}\n isItemEqualToValue={(item: PickerItem, value: PickerItem) => item.value === value.value}\n autoHighlight\n >\n <ComboboxTrigger\n size=\"sm\"\n icon={<LayersIcon />}\n aria-label={`View: ${selected?.label}${activeUnsaved ? ', unsaved changes' : ''}`}\n className=\"max-w-60\"\n >\n {selected?.label}\n {activeUnsaved && (\n <span className=\"ml-1.5 inline-block size-1.5 rounded-full bg-warning-indicator align-middle\" />\n )}\n </ComboboxTrigger>\n <ComboboxContent align=\"end\">\n <ComboboxSearch placeholder=\"Search views\" />\n <ComboboxEmpty>No views found.</ComboboxEmpty>\n <ComboboxList>\n {(item: PickerItem) => {\n const view = item.viewId ? viewsById.get(item.viewId) : undefined;\n return (\n <ComboboxItem key={item.value} value={item}>\n <span className=\"truncate\">{item.label}</span>\n {view && describeView && <ComboboxItemEnd>{describeView(view)}</ComboboxItemEnd>}\n </ComboboxItem>\n );\n }}\n </ComboboxList>\n </ComboboxContent>\n </ComboboxRoot>\n {activeView && !creating && (editable || canCreate) && (\n <DropdownMenu>\n <DropdownMenu.Trigger variant=\"ghost\" size=\"icon-sm\" tooltip=\"View actions\" className=\"shrink-0\">\n <EllipsisIcon />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {editable && (\n <DropdownMenu.Item onClick={() => setRenaming(true)}>\n <TextCursorInputIcon aria-hidden />\n Rename\n </DropdownMenu.Item>\n )}\n {canCreate && (\n <DropdownMenu.Item onClick={() => views.duplicate(activeView.id)}>\n <CopyIcon aria-hidden />\n Duplicate\n </DropdownMenu.Item>\n )}\n {editable && (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item variant=\"destructive\" onClick={() => views.remove(activeView.id)}>\n <Trash2Icon aria-hidden />\n Delete view\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n )}\n </div>\n {canCreate && (\n <Popover\n open={creating}\n onOpenChange={open => {\n if (open) views.create(newViewSettings);\n else views.discard();\n }}\n >\n <PopoverTrigger variant=\"ghost\" size=\"icon-sm\" tooltip=\"Save as new view\" className=\"shrink-0\">\n <LayersPlusIcon />\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-72\">\n {creating && (\n <ViewNameForm\n title=\"Save as new view\"\n initialName={draft.name}\n submitLabel=\"Save view\"\n error={views.error}\n pending={views.pending}\n onNameChange={name => views.change({ name })}\n onSubmit={() => views.save()}\n onCancel={views.discard}\n />\n )}\n </PopoverContent>\n </Popover>\n )}\n {activeView && (\n <RenamePopover\n open={renaming}\n anchorRef={anchorRef}\n name={activeView.name}\n error={views.error}\n pending={views.pending}\n onClose={() => setRenaming(false)}\n onRename={name => views.rename(activeView.id, name)}\n />\n )}\n </div>\n );\n}\n\nfunction RenamePopover({\n open,\n anchorRef,\n name,\n error,\n pending,\n onClose,\n onRename,\n}: {\n open: boolean;\n anchorRef: RefObject<HTMLDivElement | null>;\n name: string;\n error: string | undefined;\n pending: boolean | undefined;\n onClose: () => void;\n onRename: (name: string) => boolean | Promise<boolean>;\n}) {\n // The name that last failed to save: its error shows until the user types something else.\n const [failedName, setFailedName] = useState<string>();\n const [typedName, setTypedName] = useState(name);\n const close = () => {\n setFailedName(undefined);\n setTypedName(name);\n onClose();\n };\n return (\n <Popover open={open} onOpenChange={next => !next && close()}>\n <PopoverContent anchor={anchorRef} align=\"end\" className=\"w-72\">\n {open && (\n <ViewNameForm\n title=\"Rename view\"\n initialName={name}\n submitLabel=\"Rename\"\n error={failedName !== undefined && failedName === typedName ? error : undefined}\n pending={pending}\n onNameChange={setTypedName}\n onSubmit={async next => {\n if (await onRename(next)) close();\n else setFailedName(next);\n }}\n onCancel={close}\n />\n )}\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction ViewNameForm({\n title,\n initialName,\n submitLabel,\n error,\n pending,\n onNameChange,\n onSubmit,\n onCancel,\n}: {\n title: string;\n initialName: string;\n submitLabel: string;\n error?: string;\n pending?: boolean;\n onNameChange?: (name: string) => void;\n onSubmit: (name: string) => void | Promise<void>;\n onCancel: () => void;\n}) {\n const [name, setName] = useState(initialName);\n const submit = (event: FormEvent) => {\n event.preventDefault();\n if (name.trim()) void onSubmit(name);\n };\n return (\n <form className=\"flex flex-col gap-3\" onSubmit={submit}>\n <Txt as=\"h2\" variant=\"label\">\n {title}\n </Txt>\n <Field invalid={error !== undefined}>\n <Input\n aria-label=\"View name\"\n size=\"sm\"\n autoFocus\n onFocus={event => event.currentTarget.select()}\n maxLength={MAX_SAVED_VIEW_NAME_CHARS}\n value={name}\n onChange={event => {\n setName(event.target.value);\n onNameChange?.(event.target.value);\n }}\n />\n <FieldError>{error}</FieldError>\n </Field>\n <div className=\"flex justify-end gap-1.5\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" variant=\"default\" size=\"sm\" disabled={pending || !name.trim()}>\n {submitLabel}\n </Button>\n </div>\n </form>\n );\n}\n","import type { SavedViewPage } from '@mastra/core/storage';\nimport { createPortal } from 'react-dom';\nimport { useSavedViewsSource } from './saved-views-source';\nimport type { SavedViewsContextValue } from './saved-views-source';\nimport { useHostedSavedViews } from './use-hosted-saved-views';\nimport type { SavedViewColumnsControl } from './use-hosted-saved-views';\nimport { useObservabilityHeaderSlot } from '@/domains/observability/components/observability-header-slot';\nimport { SavedViewPicker } from '@/ds/components/SavedViews/saved-view-picker';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_LABELS: Record<SavedViewPage, string> = {\n traces: 'All traces',\n spans: 'All spans',\n threads: 'All threads',\n logs: 'All logs',\n};\n\nexport type ObservabilitySavedViewsProps = {\n page: SavedViewPage;\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n /** The page's column picker (traces, spans, threads), so views save and restore columns. */\n columns?: SavedViewColumnsControl;\n /**\n * The range the page shows when the URL names none, when the host's differs from the page's own\n * (the same value passed to `useObservabilityListFilters`).\n */\n defaultDatePreset?: string;\n className?: string;\n};\n\n/**\n * The saved views of an observability page: a searchable view picker with save and reset actions.\n * Inside the shared traces / spans / threads header it moves into that header's row. Renders nothing\n * unless a `SavedViewsProvider` above it supplies where views are stored.\n */\nexport function ObservabilitySavedViews(props: ObservabilitySavedViewsProps) {\n const context = useSavedViewsSource();\n if (!context) return null;\n return <HostedSavedViewsBar {...props} {...context} />;\n}\n\nfunction HostedSavedViewsBar({\n page,\n searchParams,\n setSearchParams,\n columns,\n defaultDatePreset,\n className,\n source,\n queryKeyScope,\n canEdit,\n canCreate = true,\n}: ObservabilitySavedViewsProps & SavedViewsContextValue) {\n const headerSlot = useObservabilityHeaderSlot();\n const views = useHostedSavedViews({\n page,\n source,\n queryKeyScope,\n canEdit,\n canCreate,\n searchParams,\n setSearchParams,\n columns,\n defaultDatePreset,\n });\n\n const picker = (\n <SavedViewPicker\n views={views}\n defaultLabel={DEFAULT_LABELS[page]}\n aria-label=\"Saved views\"\n newViewSettings={{ state: { schemaVersion: 1, page, filters: [] } }}\n describeView={view => (view.settings.record?.scope === 'org' ? 'Shared' : undefined)}\n canEdit={view => !canEdit || !view.settings.record || canEdit(view.settings.record)}\n canCreate={canCreate}\n className={className}\n />\n );\n return headerSlot ? createPortal(picker, headerSlot) : picker;\n}\n"],"mappings":"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"}
|
package/dist/{observability-saved-views-BAzxxoAr.cjs → observability-saved-views-Daizz4tU.cjs}
RENAMED
|
@@ -5,7 +5,7 @@ const require_input = require("./input-2hRXcZIu.cjs");
|
|
|
5
5
|
const require_dropdown_menu = require("./dropdown-menu-BETTTPBB.cjs");
|
|
6
6
|
const require_components_Field = require("./components/Field.cjs.js");
|
|
7
7
|
const require_popover = require("./popover-BJqa6Hz6.cjs");
|
|
8
|
-
const require_combobox_parts = require("./combobox-parts-
|
|
8
|
+
const require_combobox_parts = require("./combobox-parts-C4phOq4t.cjs");
|
|
9
9
|
const require_domains_observability_saved_views_saved_views_source = require("./domains/observability/saved-views/saved-views-source.cjs.js");
|
|
10
10
|
const require_domains_observability_saved_views_use_hosted_saved_views = require("./domains/observability/saved-views/use-hosted-saved-views.cjs.js");
|
|
11
11
|
const require_domains_observability_components_observability_header_slot = require("./domains/observability/components/observability-header-slot.cjs.js");
|
|
@@ -87,7 +87,7 @@ function SavedViewPicker({ views, defaultLabel, newViewSettings, describeView, c
|
|
|
87
87
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_combobox_parts.ComboboxContent, {
|
|
88
88
|
align: "end",
|
|
89
89
|
children: [
|
|
90
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_combobox_parts.ComboboxSearch, { placeholder: "Search views
|
|
90
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_combobox_parts.ComboboxSearch, { placeholder: "Search views" }),
|
|
91
91
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_combobox_parts.ComboboxEmpty, { children: "No views found." }),
|
|
92
92
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_combobox_parts.ComboboxList, { children: (item) => {
|
|
93
93
|
const view = item.viewId ? viewsById.get(item.viewId) : void 0;
|
|
@@ -301,4 +301,4 @@ Object.defineProperty(exports, "ObservabilitySavedViews", {
|
|
|
301
301
|
}
|
|
302
302
|
});
|
|
303
303
|
|
|
304
|
-
//# sourceMappingURL=observability-saved-views-
|
|
304
|
+
//# sourceMappingURL=observability-saved-views-Daizz4tU.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability-saved-views-Daizz4tU.cjs","names":["useRef","useState","cn","Txt","Button","ComboboxRoot","ComboboxTrigger","LayersIcon","ComboboxContent","ComboboxSearch","ComboboxEmpty","ComboboxList","ComboboxItem","ComboboxItemEnd","DropdownMenu","EllipsisIcon","TextCursorInputIcon","CopyIcon","_Fragment","Trash2Icon","Popover","PopoverTrigger","LayersPlusIcon","PopoverContent","Field","Input","FieldError","useSavedViewsSource","useObservabilityHeaderSlot","useHostedSavedViews","createPortal"],"sources":["../src/ds/components/SavedViews/saved-view-picker.tsx","../src/domains/observability/saved-views/observability-saved-views.tsx"],"sourcesContent":["import { CopyIcon, EllipsisIcon, LayersIcon, LayersPlusIcon, TextCursorInputIcon, Trash2Icon } from 'lucide-react';\nimport { useRef, useState } from 'react';\nimport type { FormEvent, ReactNode, RefObject } from 'react';\nimport { MAX_SAVED_VIEW_NAME_CHARS } from './saved-view-schema';\nimport type { SavedView } from './saved-view-schema';\nimport type { SavedViewsController } from './use-saved-views';\nimport { Button } from '@/ds/components/Button/Button';\nimport {\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxItemEnd,\n ComboboxList,\n ComboboxRoot,\n ComboboxSearch,\n ComboboxTrigger,\n} from '@/ds/components/Combobox/combobox-parts';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu';\nimport { Field, FieldError } from '@/ds/components/Field';\nimport { Input } from '@/ds/components/Input/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ds/components/Popover';\nimport { Txt } from '@/ds/components/Txt';\nimport { cn } from '@/lib/utils';\n\nexport type SavedViewPickerProps<TSettings> = {\n views: SavedViewsController<TSettings>;\n /** Names the page's unfiltered state, e.g. \"All traces\". */\n defaultLabel: string;\n newViewSettings: NoInfer<TSettings>;\n /** Muted text after a view in the list, e.g. \"Shared\". */\n describeView?: (view: SavedView<TSettings>) => ReactNode;\n /** Whether a view can be renamed, deleted or overwritten. Others can still be applied and duplicated. */\n canEdit?: (view: SavedView<TSettings>) => boolean;\n /** Whether new views can be saved here (save as new view, duplicate). Defaults to true. */\n canCreate?: boolean;\n 'aria-label'?: string;\n className?: string;\n};\n\ntype PickerItem = { value: string; label: string; viewId: string | undefined };\n\nconst DEFAULT_ITEM_VALUE = '';\n\n/**\n * A compact saved-views control for a page header: a searchable view picker, the active view's\n * actions, and save / reset once the page differs from the view. Driven by the same controller\n * as `SavedViewTabs`.\n */\nexport function SavedViewPicker<TSettings>({\n views,\n defaultLabel,\n newViewSettings,\n describeView,\n canEdit = () => true,\n canCreate = true,\n 'aria-label': ariaLabel = 'Views',\n className,\n}: SavedViewPickerProps<TSettings>) {\n const anchorRef = useRef<HTMLDivElement>(null);\n const [renaming, setRenaming] = useState(false);\n const { draft, activeView } = views;\n const creating = draft !== undefined && draft.viewId === undefined;\n const activeUnsaved = !creating && draft?.viewId !== undefined && views.unsaved;\n const editable = activeView !== undefined && canEdit(activeView);\n\n const items: PickerItem[] = [\n { value: DEFAULT_ITEM_VALUE, label: defaultLabel, viewId: undefined },\n ...views.views.map(view => ({ value: view.id, label: view.name, viewId: view.id })),\n ];\n const selected = items.find(item => item.viewId === activeView?.id) ?? items[0];\n const viewsById = new Map(views.views.map(view => [view.id, view]));\n\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className={cn('flex min-w-0 flex-wrap items-center justify-end gap-1.5', className)}\n >\n {views.error && !creating && !renaming && (\n <Txt role=\"alert\" variant=\"caption\" className=\"min-w-0 truncate text-destructive-foreground\">\n {views.error}\n </Txt>\n )}\n {activeUnsaved && (\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" disabled={views.pending} onClick={views.discard}>\n Reset\n </Button>\n {editable && (\n <Button type=\"button\" variant=\"default\" size=\"sm\" disabled={views.pending} onClick={views.save}>\n Save changes\n </Button>\n )}\n </div>\n )}\n <div ref={anchorRef} className=\"flex min-w-0 items-center gap-0.5\">\n <ComboboxRoot\n items={items}\n value={selected}\n onValueChange={(item: PickerItem | null) => {\n if (item) views.select(item.viewId);\n }}\n isItemEqualToValue={(item: PickerItem, value: PickerItem) => item.value === value.value}\n autoHighlight\n >\n <ComboboxTrigger\n size=\"sm\"\n icon={<LayersIcon />}\n aria-label={`View: ${selected?.label}${activeUnsaved ? ', unsaved changes' : ''}`}\n className=\"max-w-60\"\n >\n {selected?.label}\n {activeUnsaved && (\n <span className=\"ml-1.5 inline-block size-1.5 rounded-full bg-warning-indicator align-middle\" />\n )}\n </ComboboxTrigger>\n <ComboboxContent align=\"end\">\n <ComboboxSearch placeholder=\"Search views\" />\n <ComboboxEmpty>No views found.</ComboboxEmpty>\n <ComboboxList>\n {(item: PickerItem) => {\n const view = item.viewId ? viewsById.get(item.viewId) : undefined;\n return (\n <ComboboxItem key={item.value} value={item}>\n <span className=\"truncate\">{item.label}</span>\n {view && describeView && <ComboboxItemEnd>{describeView(view)}</ComboboxItemEnd>}\n </ComboboxItem>\n );\n }}\n </ComboboxList>\n </ComboboxContent>\n </ComboboxRoot>\n {activeView && !creating && (editable || canCreate) && (\n <DropdownMenu>\n <DropdownMenu.Trigger variant=\"ghost\" size=\"icon-sm\" tooltip=\"View actions\" className=\"shrink-0\">\n <EllipsisIcon />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {editable && (\n <DropdownMenu.Item onClick={() => setRenaming(true)}>\n <TextCursorInputIcon aria-hidden />\n Rename\n </DropdownMenu.Item>\n )}\n {canCreate && (\n <DropdownMenu.Item onClick={() => views.duplicate(activeView.id)}>\n <CopyIcon aria-hidden />\n Duplicate\n </DropdownMenu.Item>\n )}\n {editable && (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item variant=\"destructive\" onClick={() => views.remove(activeView.id)}>\n <Trash2Icon aria-hidden />\n Delete view\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n )}\n </div>\n {canCreate && (\n <Popover\n open={creating}\n onOpenChange={open => {\n if (open) views.create(newViewSettings);\n else views.discard();\n }}\n >\n <PopoverTrigger variant=\"ghost\" size=\"icon-sm\" tooltip=\"Save as new view\" className=\"shrink-0\">\n <LayersPlusIcon />\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-72\">\n {creating && (\n <ViewNameForm\n title=\"Save as new view\"\n initialName={draft.name}\n submitLabel=\"Save view\"\n error={views.error}\n pending={views.pending}\n onNameChange={name => views.change({ name })}\n onSubmit={() => views.save()}\n onCancel={views.discard}\n />\n )}\n </PopoverContent>\n </Popover>\n )}\n {activeView && (\n <RenamePopover\n open={renaming}\n anchorRef={anchorRef}\n name={activeView.name}\n error={views.error}\n pending={views.pending}\n onClose={() => setRenaming(false)}\n onRename={name => views.rename(activeView.id, name)}\n />\n )}\n </div>\n );\n}\n\nfunction RenamePopover({\n open,\n anchorRef,\n name,\n error,\n pending,\n onClose,\n onRename,\n}: {\n open: boolean;\n anchorRef: RefObject<HTMLDivElement | null>;\n name: string;\n error: string | undefined;\n pending: boolean | undefined;\n onClose: () => void;\n onRename: (name: string) => boolean | Promise<boolean>;\n}) {\n // The name that last failed to save: its error shows until the user types something else.\n const [failedName, setFailedName] = useState<string>();\n const [typedName, setTypedName] = useState(name);\n const close = () => {\n setFailedName(undefined);\n setTypedName(name);\n onClose();\n };\n return (\n <Popover open={open} onOpenChange={next => !next && close()}>\n <PopoverContent anchor={anchorRef} align=\"end\" className=\"w-72\">\n {open && (\n <ViewNameForm\n title=\"Rename view\"\n initialName={name}\n submitLabel=\"Rename\"\n error={failedName !== undefined && failedName === typedName ? error : undefined}\n pending={pending}\n onNameChange={setTypedName}\n onSubmit={async next => {\n if (await onRename(next)) close();\n else setFailedName(next);\n }}\n onCancel={close}\n />\n )}\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction ViewNameForm({\n title,\n initialName,\n submitLabel,\n error,\n pending,\n onNameChange,\n onSubmit,\n onCancel,\n}: {\n title: string;\n initialName: string;\n submitLabel: string;\n error?: string;\n pending?: boolean;\n onNameChange?: (name: string) => void;\n onSubmit: (name: string) => void | Promise<void>;\n onCancel: () => void;\n}) {\n const [name, setName] = useState(initialName);\n const submit = (event: FormEvent) => {\n event.preventDefault();\n if (name.trim()) void onSubmit(name);\n };\n return (\n <form className=\"flex flex-col gap-3\" onSubmit={submit}>\n <Txt as=\"h2\" variant=\"label\">\n {title}\n </Txt>\n <Field invalid={error !== undefined}>\n <Input\n aria-label=\"View name\"\n size=\"sm\"\n autoFocus\n onFocus={event => event.currentTarget.select()}\n maxLength={MAX_SAVED_VIEW_NAME_CHARS}\n value={name}\n onChange={event => {\n setName(event.target.value);\n onNameChange?.(event.target.value);\n }}\n />\n <FieldError>{error}</FieldError>\n </Field>\n <div className=\"flex justify-end gap-1.5\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" variant=\"default\" size=\"sm\" disabled={pending || !name.trim()}>\n {submitLabel}\n </Button>\n </div>\n </form>\n );\n}\n","import type { SavedViewPage } from '@mastra/core/storage';\nimport { createPortal } from 'react-dom';\nimport { useSavedViewsSource } from './saved-views-source';\nimport type { SavedViewsContextValue } from './saved-views-source';\nimport { useHostedSavedViews } from './use-hosted-saved-views';\nimport type { SavedViewColumnsControl } from './use-hosted-saved-views';\nimport { useObservabilityHeaderSlot } from '@/domains/observability/components/observability-header-slot';\nimport { SavedViewPicker } from '@/ds/components/SavedViews/saved-view-picker';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_LABELS: Record<SavedViewPage, string> = {\n traces: 'All traces',\n spans: 'All spans',\n threads: 'All threads',\n logs: 'All logs',\n};\n\nexport type ObservabilitySavedViewsProps = {\n page: SavedViewPage;\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n /** The page's column picker (traces, spans, threads), so views save and restore columns. */\n columns?: SavedViewColumnsControl;\n /**\n * The range the page shows when the URL names none, when the host's differs from the page's own\n * (the same value passed to `useObservabilityListFilters`).\n */\n defaultDatePreset?: string;\n className?: string;\n};\n\n/**\n * The saved views of an observability page: a searchable view picker with save and reset actions.\n * Inside the shared traces / spans / threads header it moves into that header's row. Renders nothing\n * unless a `SavedViewsProvider` above it supplies where views are stored.\n */\nexport function ObservabilitySavedViews(props: ObservabilitySavedViewsProps) {\n const context = useSavedViewsSource();\n if (!context) return null;\n return <HostedSavedViewsBar {...props} {...context} />;\n}\n\nfunction HostedSavedViewsBar({\n page,\n searchParams,\n setSearchParams,\n columns,\n defaultDatePreset,\n className,\n source,\n queryKeyScope,\n canEdit,\n canCreate = true,\n}: ObservabilitySavedViewsProps & SavedViewsContextValue) {\n const headerSlot = useObservabilityHeaderSlot();\n const views = useHostedSavedViews({\n page,\n source,\n queryKeyScope,\n canEdit,\n canCreate,\n searchParams,\n setSearchParams,\n columns,\n defaultDatePreset,\n });\n\n const picker = (\n <SavedViewPicker\n views={views}\n defaultLabel={DEFAULT_LABELS[page]}\n aria-label=\"Saved views\"\n newViewSettings={{ state: { schemaVersion: 1, page, filters: [] } }}\n describeView={view => (view.settings.record?.scope === 'org' ? 'Shared' : undefined)}\n canEdit={view => !canEdit || !view.settings.record || canEdit(view.settings.record)}\n canCreate={canCreate}\n className={className}\n />\n );\n return headerSlot ? createPortal(picker, headerSlot) : picker;\n}\n"],"mappings":"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"}
|
|
@@ -33,9 +33,9 @@ function ChartPlot({ height, plotRef, onResize, clickable, className, children }
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Draws the chart at the box's size, and again only once the box has stopped resizing: a page of
|
|
36
|
-
* charts can't redraw on every frame of a resize. React only sets the drawn size;
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* charts can't redraw on every frame of a resize. React only sets the drawn size; the observer
|
|
37
|
+
* writes the box's live size, and `chart-plot.css` scales the drawn chart to it meanwhile, so it
|
|
38
|
+
* moves with its card and its labels keep their shape.
|
|
39
39
|
*/
|
|
40
40
|
function StretchedPlot({ onResize, children }) {
|
|
41
41
|
const ref = (0, react.useRef)(null);
|
|
@@ -55,6 +55,8 @@ function StretchedPlot({ onResize, children }) {
|
|
|
55
55
|
const observer = new ResizeObserver(([entry]) => {
|
|
56
56
|
if (!entry) return;
|
|
57
57
|
const { width, height } = entry.contentRect;
|
|
58
|
+
el.style.setProperty("--chart-box-w", String(width));
|
|
59
|
+
el.style.setProperty("--chart-box-h", String(height));
|
|
58
60
|
clearTimeout(timer);
|
|
59
61
|
if (width === drawn?.width && height === drawn?.height) return;
|
|
60
62
|
const commit = () => {
|
|
@@ -90,11 +92,11 @@ function StretchedPlot({ onResize, children }) {
|
|
|
90
92
|
})
|
|
91
93
|
});
|
|
92
94
|
}
|
|
93
|
-
/** The drawn size as the CSS variables `chart-plot.css` scales from. */
|
|
95
|
+
/** The drawn size as the CSS variables `chart-plot.css` scales from, in plain CSS pixels. */
|
|
94
96
|
function drawnSizeVars({ width, height }) {
|
|
95
97
|
return {
|
|
96
|
-
"--chart-drawn-w":
|
|
97
|
-
"--chart-drawn-h":
|
|
98
|
+
"--chart-drawn-w": String(width),
|
|
99
|
+
"--chart-drawn-h": String(height)
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
function isDrawable({ width, height }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-plot.cjs.js","names":["cn","useRef","useState","useEffectEvent","startTransition","ResponsiveContainer"],"sources":["../../src/ds/primitives/chart-plot.tsx"],"sourcesContent":["import { startTransition, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { ResponsiveContainer } from 'recharts';\nimport type { ChartHeight } from './chart-frame';\nimport { cn } from '@/lib/utils';\nimport './chart-plot.css';\n\n/** How long the box has to hold still before the chart redraws at its new size. */\nconst SETTLE_MS = 150;\n\n/**\n * Sizes the plot. `fill` takes the parent's free height, out of flow: a ResponsiveContainer at\n * 100% height can round a pixel past its box, which would make the card scroll by a hair.\n */\nexport function ChartPlot({\n height,\n plotRef,\n onResize,\n clickable,\n className,\n children,\n}: {\n height: ChartHeight;\n plotRef: React.Ref<HTMLDivElement>;\n onResize: (width: number, height: number) => void;\n clickable?: boolean;\n /** On the element around the SVG, e.g. to style Recharts' parts from a chart option. */\n className?: string;\n children: ReactNode;\n}) {\n // Recharts makes parts of the plot focusable for keyboard use; a mouse click shouldn't leave a\n // focus ring around the chart, keyboard focus still shows one.\n const surface = cn(\n 'w-full [&_.recharts-surface]:overflow-visible [&_.recharts-surface]:outline-none',\n '[&_*:focus:not(:focus-visible)]:outline-none',\n clickable && '[&_.recharts-surface]:cursor-pointer',\n className,\n );\n const plot = <StretchedPlot onResize={onResize}>{children}</StretchedPlot>;\n if (height === 'fill') {\n return (\n <div className=\"relative min-h-45 flex-1\">\n <div ref={plotRef} className={cn('absolute inset-0', surface)}>\n {plot}\n </div>\n </div>\n );\n }\n return (\n <div ref={plotRef} className={surface} style={{ height }}>\n {plot}\n </div>\n );\n}\n\n/**\n * Draws the chart at the box's size, and again only once the box has stopped resizing: a page of\n * charts can't redraw on every frame of a resize. React only sets the drawn size; `chart-plot.css
|
|
1
|
+
{"version":3,"file":"chart-plot.cjs.js","names":["cn","useRef","useState","useEffectEvent","startTransition","ResponsiveContainer"],"sources":["../../src/ds/primitives/chart-plot.tsx"],"sourcesContent":["import { startTransition, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { ResponsiveContainer } from 'recharts';\nimport type { ChartHeight } from './chart-frame';\nimport { cn } from '@/lib/utils';\nimport './chart-plot.css';\n\n/** How long the box has to hold still before the chart redraws at its new size. */\nconst SETTLE_MS = 150;\n\n/**\n * Sizes the plot. `fill` takes the parent's free height, out of flow: a ResponsiveContainer at\n * 100% height can round a pixel past its box, which would make the card scroll by a hair.\n */\nexport function ChartPlot({\n height,\n plotRef,\n onResize,\n clickable,\n className,\n children,\n}: {\n height: ChartHeight;\n plotRef: React.Ref<HTMLDivElement>;\n onResize: (width: number, height: number) => void;\n clickable?: boolean;\n /** On the element around the SVG, e.g. to style Recharts' parts from a chart option. */\n className?: string;\n children: ReactNode;\n}) {\n // Recharts makes parts of the plot focusable for keyboard use; a mouse click shouldn't leave a\n // focus ring around the chart, keyboard focus still shows one.\n const surface = cn(\n 'w-full [&_.recharts-surface]:overflow-visible [&_.recharts-surface]:outline-none',\n '[&_*:focus:not(:focus-visible)]:outline-none',\n clickable && '[&_.recharts-surface]:cursor-pointer',\n className,\n );\n const plot = <StretchedPlot onResize={onResize}>{children}</StretchedPlot>;\n if (height === 'fill') {\n return (\n <div className=\"relative min-h-45 flex-1\">\n <div ref={plotRef} className={cn('absolute inset-0', surface)}>\n {plot}\n </div>\n </div>\n );\n }\n return (\n <div ref={plotRef} className={surface} style={{ height }}>\n {plot}\n </div>\n );\n}\n\n/**\n * Draws the chart at the box's size, and again only once the box has stopped resizing: a page of\n * charts can't redraw on every frame of a resize. React only sets the drawn size; the observer\n * writes the box's live size, and `chart-plot.css` scales the drawn chart to it meanwhile, so it\n * moves with its card and its labels keep their shape.\n */\nfunction StretchedPlot({\n onResize,\n children,\n}: {\n onResize: (width: number, height: number) => void;\n children: ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ width: number; height: number }>();\n const draw = useEffectEvent((width: number, height: number) => {\n setSize({ width, height });\n onResize(width, height);\n });\n\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n let drawn: { width: number; height: number } | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const observer = new ResizeObserver(([entry]) => {\n if (!entry) return;\n const { width, height } = entry.contentRect;\n el.style.setProperty('--chart-box-w', String(width));\n el.style.setProperty('--chart-box-h', String(height));\n clearTimeout(timer);\n if (width === drawn?.width && height === drawn?.height) return;\n const commit = () => {\n drawn = { width, height };\n draw(width, height);\n };\n // Nothing is drawn at a zero size (a hidden tab), so there's nothing to stretch: draw now.\n if (!drawn || !isDrawable(drawn)) {\n commit();\n return;\n }\n // Redraw once the resize stops, in a transition so React draws the charts in slices between\n // frames instead of in one long task.\n timer = setTimeout(() => startTransition(commit), SETTLE_MS);\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n clearTimeout(timer);\n };\n }, []);\n\n return (\n <div ref={ref} className=\"chart-plot-box size-full\">\n {size && isDrawable(size) && (\n <div className=\"chart-plot-stretch\" style={drawnSizeVars(size)}>\n <ResponsiveContainer width={size.width} height={size.height}>\n {children}\n </ResponsiveContainer>\n </div>\n )}\n </div>\n );\n}\n\n/** The drawn size as the CSS variables `chart-plot.css` scales from, in plain CSS pixels. */\nfunction drawnSizeVars({ width, height }: { width: number; height: number }): Record<string, string> {\n return { '--chart-drawn-w': String(width), '--chart-drawn-h': String(height) };\n}\n\nfunction isDrawable({ width, height }: { width: number; height: number }) {\n return width > 0 && height > 0;\n}\n"],"mappings":";;;;;;;AAQA,IAAM,YAAY;;;;;AAMlB,SAAgB,UAAU,EACxB,QACA,SACA,UACA,WACA,WACA,YASC;CAGD,MAAM,UAAUA,cAAAA,GACd,oFACA,gDACA,aAAa,wCACb,SACF;CACA,MAAM,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;EAAyB;EAAW;CAAwB,CAAA;CACzE,IAAI,WAAW,QACb,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,WAAU;EACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAAK,KAAK;GAAS,WAAWA,cAAAA,GAAG,oBAAoB,OAAO;GACzD,UAAA;EACE,CAAA;CACF,CAAA;CAGT,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,KAAK;EAAS,WAAW;EAAS,OAAO,EAAE,OAAO;EACpD,UAAA;CACE,CAAA;AAET;;;;;;;AAQA,SAAS,cAAc,EACrB,UACA,YAIC;CACD,MAAM,OAAA,GAAMC,MAAAA,OAAAA,CAAuB,IAAI;CACvC,MAAM,CAAC,MAAM,YAAA,GAAWC,MAAAA,SAAAA,CAA4C;CACpE,MAAM,QAAA,GAAOC,MAAAA,eAAAA,EAAgB,OAAe,WAAmB;EAC7D,QAAQ;GAAE;GAAO;EAAO,CAAC;EACzB,SAAS,OAAO,MAAM;CACxB,CAAC;CAED,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,MAAM,OAAO,mBAAmB,aAAa;EAClD,IAAI;EACJ,IAAI;EACJ,MAAM,WAAW,IAAI,gBAAgB,CAAC,WAAW;GAC/C,IAAI,CAAC,OAAO;GACZ,MAAM,EAAE,OAAO,WAAW,MAAM;GAChC,GAAG,MAAM,YAAY,iBAAiB,OAAO,KAAK,CAAC;GACnD,GAAG,MAAM,YAAY,iBAAiB,OAAO,MAAM,CAAC;GACpD,aAAa,KAAK;GAClB,IAAI,UAAU,OAAO,SAAS,WAAW,OAAO,QAAQ;GACxD,MAAM,eAAe;IACnB,QAAQ;KAAE;KAAO;IAAO;IACxB,KAAK,OAAO,MAAM;GACpB;GAEA,IAAI,CAAC,SAAS,CAAC,WAAW,KAAK,GAAG;IAChC,OAAO;IACP;GACF;GAGA,QAAQ,kBAAA,GAAiBC,MAAAA,gBAAAA,CAAgB,MAAM,GAAG,SAAS;EAC7D,CAAC;EACD,SAAS,QAAQ,EAAE;EACnB,aAAa;GACX,SAAS,WAAW;GACpB,aAAa,KAAK;EACpB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAU;EAAK,WAAU;EACtB,UAAA,QAAQ,WAAW,IAAI,KACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAAK,WAAU;GAAqB,OAAO,cAAc,IAAI;GAC3D,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,SAAAA,qBAAD;IAAqB,OAAO,KAAK;IAAO,QAAQ,KAAK;IAClD;GACkB,CAAA;EAClB,CAAA;CAEJ,CAAA;AAET;;AAGA,SAAS,cAAc,EAAE,OAAO,UAAqE;CACnG,OAAO;EAAE,mBAAmB,OAAO,KAAK;EAAG,mBAAmB,OAAO,MAAM;CAAE;AAC/E;AAEA,SAAS,WAAW,EAAE,OAAO,UAA6C;CACxE,OAAO,QAAQ,KAAK,SAAS;AAC/B"}
|
|
@@ -32,9 +32,9 @@ function ChartPlot({ height, plotRef, onResize, clickable, className, children }
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Draws the chart at the box's size, and again only once the box has stopped resizing: a page of
|
|
35
|
-
* charts can't redraw on every frame of a resize. React only sets the drawn size;
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* charts can't redraw on every frame of a resize. React only sets the drawn size; the observer
|
|
36
|
+
* writes the box's live size, and `chart-plot.css` scales the drawn chart to it meanwhile, so it
|
|
37
|
+
* moves with its card and its labels keep their shape.
|
|
38
38
|
*/
|
|
39
39
|
function StretchedPlot({ onResize, children }) {
|
|
40
40
|
const ref = useRef(null);
|
|
@@ -54,6 +54,8 @@ function StretchedPlot({ onResize, children }) {
|
|
|
54
54
|
const observer = new ResizeObserver(([entry]) => {
|
|
55
55
|
if (!entry) return;
|
|
56
56
|
const { width, height } = entry.contentRect;
|
|
57
|
+
el.style.setProperty("--chart-box-w", String(width));
|
|
58
|
+
el.style.setProperty("--chart-box-h", String(height));
|
|
57
59
|
clearTimeout(timer);
|
|
58
60
|
if (width === drawn?.width && height === drawn?.height) return;
|
|
59
61
|
const commit = () => {
|
|
@@ -89,11 +91,11 @@ function StretchedPlot({ onResize, children }) {
|
|
|
89
91
|
})
|
|
90
92
|
});
|
|
91
93
|
}
|
|
92
|
-
/** The drawn size as the CSS variables `chart-plot.css` scales from. */
|
|
94
|
+
/** The drawn size as the CSS variables `chart-plot.css` scales from, in plain CSS pixels. */
|
|
93
95
|
function drawnSizeVars({ width, height }) {
|
|
94
96
|
return {
|
|
95
|
-
"--chart-drawn-w":
|
|
96
|
-
"--chart-drawn-h":
|
|
97
|
+
"--chart-drawn-w": String(width),
|
|
98
|
+
"--chart-drawn-h": String(height)
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
function isDrawable({ width, height }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-plot.es.js","names":[],"sources":["../../src/ds/primitives/chart-plot.tsx"],"sourcesContent":["import { startTransition, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { ResponsiveContainer } from 'recharts';\nimport type { ChartHeight } from './chart-frame';\nimport { cn } from '@/lib/utils';\nimport './chart-plot.css';\n\n/** How long the box has to hold still before the chart redraws at its new size. */\nconst SETTLE_MS = 150;\n\n/**\n * Sizes the plot. `fill` takes the parent's free height, out of flow: a ResponsiveContainer at\n * 100% height can round a pixel past its box, which would make the card scroll by a hair.\n */\nexport function ChartPlot({\n height,\n plotRef,\n onResize,\n clickable,\n className,\n children,\n}: {\n height: ChartHeight;\n plotRef: React.Ref<HTMLDivElement>;\n onResize: (width: number, height: number) => void;\n clickable?: boolean;\n /** On the element around the SVG, e.g. to style Recharts' parts from a chart option. */\n className?: string;\n children: ReactNode;\n}) {\n // Recharts makes parts of the plot focusable for keyboard use; a mouse click shouldn't leave a\n // focus ring around the chart, keyboard focus still shows one.\n const surface = cn(\n 'w-full [&_.recharts-surface]:overflow-visible [&_.recharts-surface]:outline-none',\n '[&_*:focus:not(:focus-visible)]:outline-none',\n clickable && '[&_.recharts-surface]:cursor-pointer',\n className,\n );\n const plot = <StretchedPlot onResize={onResize}>{children}</StretchedPlot>;\n if (height === 'fill') {\n return (\n <div className=\"relative min-h-45 flex-1\">\n <div ref={plotRef} className={cn('absolute inset-0', surface)}>\n {plot}\n </div>\n </div>\n );\n }\n return (\n <div ref={plotRef} className={surface} style={{ height }}>\n {plot}\n </div>\n );\n}\n\n/**\n * Draws the chart at the box's size, and again only once the box has stopped resizing: a page of\n * charts can't redraw on every frame of a resize. React only sets the drawn size; `chart-plot.css
|
|
1
|
+
{"version":3,"file":"chart-plot.es.js","names":[],"sources":["../../src/ds/primitives/chart-plot.tsx"],"sourcesContent":["import { startTransition, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { ResponsiveContainer } from 'recharts';\nimport type { ChartHeight } from './chart-frame';\nimport { cn } from '@/lib/utils';\nimport './chart-plot.css';\n\n/** How long the box has to hold still before the chart redraws at its new size. */\nconst SETTLE_MS = 150;\n\n/**\n * Sizes the plot. `fill` takes the parent's free height, out of flow: a ResponsiveContainer at\n * 100% height can round a pixel past its box, which would make the card scroll by a hair.\n */\nexport function ChartPlot({\n height,\n plotRef,\n onResize,\n clickable,\n className,\n children,\n}: {\n height: ChartHeight;\n plotRef: React.Ref<HTMLDivElement>;\n onResize: (width: number, height: number) => void;\n clickable?: boolean;\n /** On the element around the SVG, e.g. to style Recharts' parts from a chart option. */\n className?: string;\n children: ReactNode;\n}) {\n // Recharts makes parts of the plot focusable for keyboard use; a mouse click shouldn't leave a\n // focus ring around the chart, keyboard focus still shows one.\n const surface = cn(\n 'w-full [&_.recharts-surface]:overflow-visible [&_.recharts-surface]:outline-none',\n '[&_*:focus:not(:focus-visible)]:outline-none',\n clickable && '[&_.recharts-surface]:cursor-pointer',\n className,\n );\n const plot = <StretchedPlot onResize={onResize}>{children}</StretchedPlot>;\n if (height === 'fill') {\n return (\n <div className=\"relative min-h-45 flex-1\">\n <div ref={plotRef} className={cn('absolute inset-0', surface)}>\n {plot}\n </div>\n </div>\n );\n }\n return (\n <div ref={plotRef} className={surface} style={{ height }}>\n {plot}\n </div>\n );\n}\n\n/**\n * Draws the chart at the box's size, and again only once the box has stopped resizing: a page of\n * charts can't redraw on every frame of a resize. React only sets the drawn size; the observer\n * writes the box's live size, and `chart-plot.css` scales the drawn chart to it meanwhile, so it\n * moves with its card and its labels keep their shape.\n */\nfunction StretchedPlot({\n onResize,\n children,\n}: {\n onResize: (width: number, height: number) => void;\n children: ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ width: number; height: number }>();\n const draw = useEffectEvent((width: number, height: number) => {\n setSize({ width, height });\n onResize(width, height);\n });\n\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n let drawn: { width: number; height: number } | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const observer = new ResizeObserver(([entry]) => {\n if (!entry) return;\n const { width, height } = entry.contentRect;\n el.style.setProperty('--chart-box-w', String(width));\n el.style.setProperty('--chart-box-h', String(height));\n clearTimeout(timer);\n if (width === drawn?.width && height === drawn?.height) return;\n const commit = () => {\n drawn = { width, height };\n draw(width, height);\n };\n // Nothing is drawn at a zero size (a hidden tab), so there's nothing to stretch: draw now.\n if (!drawn || !isDrawable(drawn)) {\n commit();\n return;\n }\n // Redraw once the resize stops, in a transition so React draws the charts in slices between\n // frames instead of in one long task.\n timer = setTimeout(() => startTransition(commit), SETTLE_MS);\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n clearTimeout(timer);\n };\n }, []);\n\n return (\n <div ref={ref} className=\"chart-plot-box size-full\">\n {size && isDrawable(size) && (\n <div className=\"chart-plot-stretch\" style={drawnSizeVars(size)}>\n <ResponsiveContainer width={size.width} height={size.height}>\n {children}\n </ResponsiveContainer>\n </div>\n )}\n </div>\n );\n}\n\n/** The drawn size as the CSS variables `chart-plot.css` scales from, in plain CSS pixels. */\nfunction drawnSizeVars({ width, height }: { width: number; height: number }): Record<string, string> {\n return { '--chart-drawn-w': String(width), '--chart-drawn-h': String(height) };\n}\n\nfunction isDrawable({ width, height }: { width: number; height: number }) {\n return width > 0 && height > 0;\n}\n"],"mappings":";;;;;;AAQA,IAAM,YAAY;;;;;AAMlB,SAAgB,UAAU,EACxB,QACA,SACA,UACA,WACA,WACA,YASC;CAGD,MAAM,UAAU,GACd,oFACA,gDACA,aAAa,wCACb,SACF;CACA,MAAM,OAAO,oBAAC,eAAD;EAAyB;EAAW;CAAwB,CAAA;CACzE,IAAI,WAAW,QACb,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,oBAAC,OAAD;GAAK,KAAK;GAAS,WAAW,GAAG,oBAAoB,OAAO;GACzD,UAAA;EACE,CAAA;CACF,CAAA;CAGT,OACE,oBAAC,OAAD;EAAK,KAAK;EAAS,WAAW;EAAS,OAAO,EAAE,OAAO;EACpD,UAAA;CACE,CAAA;AAET;;;;;;;AAQA,SAAS,cAAc,EACrB,UACA,YAIC;CACD,MAAM,MAAM,OAAuB,IAAI;CACvC,MAAM,CAAC,MAAM,WAAW,SAA4C;CACpE,MAAM,OAAO,gBAAgB,OAAe,WAAmB;EAC7D,QAAQ;GAAE;GAAO;EAAO,CAAC;EACzB,SAAS,OAAO,MAAM;CACxB,CAAC;CAED,gBAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,MAAM,OAAO,mBAAmB,aAAa;EAClD,IAAI;EACJ,IAAI;EACJ,MAAM,WAAW,IAAI,gBAAgB,CAAC,WAAW;GAC/C,IAAI,CAAC,OAAO;GACZ,MAAM,EAAE,OAAO,WAAW,MAAM;GAChC,GAAG,MAAM,YAAY,iBAAiB,OAAO,KAAK,CAAC;GACnD,GAAG,MAAM,YAAY,iBAAiB,OAAO,MAAM,CAAC;GACpD,aAAa,KAAK;GAClB,IAAI,UAAU,OAAO,SAAS,WAAW,OAAO,QAAQ;GACxD,MAAM,eAAe;IACnB,QAAQ;KAAE;KAAO;IAAO;IACxB,KAAK,OAAO,MAAM;GACpB;GAEA,IAAI,CAAC,SAAS,CAAC,WAAW,KAAK,GAAG;IAChC,OAAO;IACP;GACF;GAGA,QAAQ,iBAAiB,gBAAgB,MAAM,GAAG,SAAS;EAC7D,CAAC;EACD,SAAS,QAAQ,EAAE;EACnB,aAAa;GACX,SAAS,WAAW;GACpB,aAAa,KAAK;EACpB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,OAAD;EAAU;EAAK,WAAU;EACtB,UAAA,QAAQ,WAAW,IAAI,KACtB,oBAAC,OAAD;GAAK,WAAU;GAAqB,OAAO,cAAc,IAAI;GAC3D,UAAA,oBAAC,qBAAD;IAAqB,OAAO,KAAK;IAAO,QAAQ,KAAK;IAClD;GACkB,CAAA;EAClB,CAAA;CAEJ,CAAA;AAET;;AAGA,SAAS,cAAc,EAAE,OAAO,UAAqE;CACnG,OAAO;EAAE,mBAAmB,OAAO,KAAK;EAAG,mBAAmB,OAAO,MAAM;CAAE;AAC/E;AAEA,SAAS,WAAW,EAAE,OAAO,UAA6C;CACxE,OAAO,QAAQ,KAAK,SAAS;AAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-icon.cjs.js","names":["cn"],"sources":["../../src/ds/primitives/control-icon.ts"],"sourcesContent":["import { cn } from '@/lib/utils';\n\n// The one rule for the icons inside an interactive control (a Button, a field, a chip segment,\n// a menu row): `--control-icon-rest` at rest, `--control-icon-hover` while hovered, back to rest\n// when disabled. A control only ever chooses the two colours (theme.css sets the defaults),\n// never its own hover rule, so every control answers hover the same way by construction.\n// An icon on a neutral surface steps back with a colour token rather than opacity: opacity dims\n// against whatever sits behind the control, so the same glyph would clear contrast on one\n// surface and fail on another.\nexport const controlIconState = cn(\n '[--control-icon:var(--control-icon-rest)] [&_svg]:text-(color:--control-icon)',\n 'not-disabled:hover:[--control-icon:var(--control-icon-hover)] aria-disabled:[--control-icon:var(--control-icon-rest)]',\n // An icon-only Button's glyph is its label, so it brightens like a label does.\n 'data-[shape=icon]:[--control-icon-hover:var(--foreground)]',\n);\n\n/** The same for a bare-glyph control that is not a Button (a chip's ×). */\nexport const controlIconOnly = '[--control-icon-hover:var(--foreground)]';\n"],"mappings":";;AASA,IAAa,mB,+BAAmBA,CAAAA,CAAAA,GAC9B,iFACA,yHAEA,4DACF;;AAGA,IAAa,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"control-icon.cjs.js","names":["cn"],"sources":["../../src/ds/primitives/control-icon.ts"],"sourcesContent":["import { cn } from '@/lib/utils';\n\n// The one rule for the icons inside an interactive control (a Button, a field, a chip segment,\n// a menu row): `--control-icon-rest` at rest, `--control-icon-hover` while hovered, back to rest\n// when disabled. By default the two match, so a labelled control's icons stay muted on hover. A control only ever chooses the two colours (theme.css sets the defaults),\n// never its own hover rule, so every control answers hover the same way by construction.\n// An icon on a neutral surface steps back with a colour token rather than opacity: opacity dims\n// against whatever sits behind the control, so the same glyph would clear contrast on one\n// surface and fail on another.\nexport const controlIconState = cn(\n '[--control-icon:var(--control-icon-rest)] [&_svg]:text-(color:--control-icon)',\n 'not-disabled:hover:[--control-icon:var(--control-icon-hover)] aria-disabled:[--control-icon:var(--control-icon-rest)]',\n // An icon-only Button's glyph is its label, so it brightens like a label does.\n 'data-[shape=icon]:[--control-icon-hover:var(--foreground)]',\n);\n\n/** The same for a bare-glyph control that is not a Button (a chip's ×). */\nexport const controlIconOnly = '[--control-icon-hover:var(--foreground)]';\n"],"mappings":";;AASA,IAAa,mB,+BAAmBA,CAAAA,CAAAA,GAC9B,iFACA,yHAEA,4DACF;;AAGA,IAAa,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-icon.es.js","names":[],"sources":["../../src/ds/primitives/control-icon.ts"],"sourcesContent":["import { cn } from '@/lib/utils';\n\n// The one rule for the icons inside an interactive control (a Button, a field, a chip segment,\n// a menu row): `--control-icon-rest` at rest, `--control-icon-hover` while hovered, back to rest\n// when disabled. A control only ever chooses the two colours (theme.css sets the defaults),\n// never its own hover rule, so every control answers hover the same way by construction.\n// An icon on a neutral surface steps back with a colour token rather than opacity: opacity dims\n// against whatever sits behind the control, so the same glyph would clear contrast on one\n// surface and fail on another.\nexport const controlIconState = cn(\n '[--control-icon:var(--control-icon-rest)] [&_svg]:text-(color:--control-icon)',\n 'not-disabled:hover:[--control-icon:var(--control-icon-hover)] aria-disabled:[--control-icon:var(--control-icon-rest)]',\n // An icon-only Button's glyph is its label, so it brightens like a label does.\n 'data-[shape=icon]:[--control-icon-hover:var(--foreground)]',\n);\n\n/** The same for a bare-glyph control that is not a Button (a chip's ×). */\nexport const controlIconOnly = '[--control-icon-hover:var(--foreground)]';\n"],"mappings":";;AASA,IAAa,mBAAmB,GAC9B,iFACA,yHAEA,4DACF;;AAGA,IAAa,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"control-icon.es.js","names":[],"sources":["../../src/ds/primitives/control-icon.ts"],"sourcesContent":["import { cn } from '@/lib/utils';\n\n// The one rule for the icons inside an interactive control (a Button, a field, a chip segment,\n// a menu row): `--control-icon-rest` at rest, `--control-icon-hover` while hovered, back to rest\n// when disabled. By default the two match, so a labelled control's icons stay muted on hover. A control only ever chooses the two colours (theme.css sets the defaults),\n// never its own hover rule, so every control answers hover the same way by construction.\n// An icon on a neutral surface steps back with a colour token rather than opacity: opacity dims\n// against whatever sits behind the control, so the same glyph would clear contrast on one\n// surface and fail on another.\nexport const controlIconState = cn(\n '[--control-icon:var(--control-icon-rest)] [&_svg]:text-(color:--control-icon)',\n 'not-disabled:hover:[--control-icon:var(--control-icon-hover)] aria-disabled:[--control-icon:var(--control-icon-rest)]',\n // An icon-only Button's glyph is its label, so it brightens like a label does.\n 'data-[shape=icon]:[--control-icon-hover:var(--foreground)]',\n);\n\n/** The same for a bare-glyph control that is not a Button (a chip's ×). */\nexport const controlIconOnly = '[--control-icon-hover:var(--foreground)]';\n"],"mappings":";;AASA,IAAa,mBAAmB,GAC9B,iFACA,yHAEA,4DACF;;AAGA,IAAa,kBAAkB"}
|
|
@@ -104,7 +104,7 @@ function PickMultiPanel({ field, tokens, onChange }) {
|
|
|
104
104
|
type: "text",
|
|
105
105
|
value: query,
|
|
106
106
|
onChange: (e) => setQuery(e.target.value),
|
|
107
|
-
placeholder: `Search ${field.label.toLowerCase()}
|
|
107
|
+
placeholder: `Search ${field.label.toLowerCase()}`,
|
|
108
108
|
className: menuSearchClasses.input,
|
|
109
109
|
...passwordManagerOptOutProps,
|
|
110
110
|
onKeyDown: (e) => {
|
|
@@ -341,4 +341,4 @@ function PropertyFilterApplied({ fields, tokens, onTokensChange, disabled, autoF
|
|
|
341
341
|
}
|
|
342
342
|
export { PickMultiPanel as n, PropertyFilterActions as r, PropertyFilterApplied as t };
|
|
343
343
|
|
|
344
|
-
//# sourceMappingURL=property-filter-applied
|
|
344
|
+
//# sourceMappingURL=property-filter-applied--U5EZdaA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-filter-applied--U5EZdaA.js","names":["_Fragment"],"sources":["../src/ds/components/PropertyFilter/property-filter-actions.tsx","../src/ds/components/PropertyFilter/pick-multi-panel.tsx","../src/ds/components/PropertyFilter/property-filter-applied.tsx"],"sourcesContent":["import { EllipsisVerticalIcon, SaveIcon, Trash2Icon, XIcon } from 'lucide-react';\nimport { Button } from '@/ds/components/Button/Button';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu/dropdown-menu';\n\nexport type PropertyFilterActionsProps = {\n disabled?: boolean;\n /** Neutralize each pill's value (keep pills, clear values). Shown as a button, not a menu item. */\n onClear?: () => void;\n /** Fully remove all active filters. Rendered as \"Remove all filters\" inside the overflow menu. */\n onRemoveAll?: () => void;\n /** Persist the current filter set (typically to localStorage) for later restoration. */\n onSave?: () => void;\n /** Drop a previously-saved filter set. Wire only when a saved set actually exists. */\n onRemoveSaved?: () => void;\n};\n\n/**\n * Shared action bar for filter-driven pages (traces, logs, …). Renders a\n * Clear button and an overflow menu with Remove all / Save / Remove saved actions.\n */\nexport function PropertyFilterActions({\n disabled,\n onClear,\n onRemoveAll,\n onSave,\n onRemoveSaved,\n}: PropertyFilterActionsProps) {\n const hasMenuItems = !!(onRemoveAll || onSave || onRemoveSaved);\n if (!onClear && !hasMenuItems) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n {onClear && (\n <Button disabled={disabled} size=\"md\" onClick={onClear} icon={<XIcon />}>\n Clear\n </Button>\n )}\n\n {hasMenuItems && (\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button disabled={disabled} size=\"icon-md\" aria-label=\"More filter actions\">\n <EllipsisVerticalIcon />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {onRemoveAll && (\n <DropdownMenu.Item onSelect={() => onRemoveAll()}>\n <XIcon />\n Remove all filters\n </DropdownMenu.Item>\n )}\n {onRemoveAll && (onSave || onRemoveSaved) && <DropdownMenu.Separator />}\n {onSave && (\n <DropdownMenu.Item onSelect={() => onSave()}>\n <SaveIcon />\n Save filters for next time\n </DropdownMenu.Item>\n )}\n {onRemoveSaved && (\n <DropdownMenu.Item onSelect={() => onRemoveSaved()}>\n <Trash2Icon />\n Remove saved filters\n </DropdownMenu.Item>\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n )}\n </div>\n );\n}\n","import { CheckIcon, SearchIcon } from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport type { PropertyFilterField, PropertyFilterToken } from './types';\nimport { Spinner } from '@/ds/components/Spinner/spinner';\nimport { menuEmptyClass, menuItemButtonClass, menuItemCheckClass, menuSearchClasses } from '@/ds/primitives/menu-item';\nimport { passwordManagerOptOutProps } from '@/ds/primitives/password-manager-autofill';\nimport { cn } from '@/lib/utils';\n\n// Same rendering as Combobox items: no visible control, a trailing check when selected.\n// Focus is on the item itself (roving via [data-pick-multi-item]).\nconst pickMultiItemClass = cn(menuItemButtonClass, 'min-w-0');\n\nfunction PickMultiItem({\n role,\n checked,\n label,\n onClick,\n}: {\n role: 'checkbox' | 'radio';\n checked: boolean;\n label: string;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role={role}\n aria-checked={checked}\n data-selected={checked || undefined}\n data-pick-multi-item=\"\"\n title={label}\n className={pickMultiItemClass}\n onClick={onClick}\n >\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {checked && (\n <span className={menuItemCheckClass}>\n <CheckIcon />\n </span>\n )}\n </button>\n );\n}\n\ntype PickMultiField = Extract<PropertyFilterField, { kind: 'pick-multi' }>;\n\nexport type PickMultiPanelProps = {\n field: PickMultiField;\n tokens: PropertyFilterToken[];\n /** Always carries a value: an empty list is how the panel says \"nothing selected\". */\n onChange: (fieldId: string, value: string | string[]) => void;\n};\n\n/**\n * Reusable body for a pick-multi side popover: optional search input plus a\n * radio group (single-select) or checkbox list (when `field.multi` is true).\n * Shared between the Filter Creator's property-picker side popover and the\n * PropertyFilterApplied pill's inline editor so both surfaces use the exact same UI.\n */\nexport function PickMultiPanel({ field, tokens, onChange }: PickMultiPanelProps) {\n const [query, setQuery] = useState('');\n const listClassName = 'max-h-[80dvh] overflow-auto p-1';\n\n const filteredOptions = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return field.options;\n return field.options.filter(o => o.label.toLowerCase().includes(q));\n }, [field.options, query]);\n\n const token = useMemo(() => tokens.find(t => t.fieldId === field.id), [tokens, field.id]);\n // Fall back to `defaultValue` when no token exists — lets view-toggle fields (e.g. List mode)\n // show their default option pre-selected before the user explicitly picks one.\n const selectedValue = typeof token?.value === 'string' ? token.value : !field.multi ? field.defaultValue : undefined;\n const selectedValues = useMemo<string[]>(() => {\n const value = token?.value;\n if (Array.isArray(value)) return value;\n if (typeof value === 'string') return [value];\n return [];\n }, [token]);\n\n return (\n <>\n {field.searchable !== false && (\n <div className={menuSearchClasses.container}>\n <SearchIcon className={menuSearchClasses.icon} />\n <input\n type=\"text\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n placeholder={`Search ${field.label.toLowerCase()}`}\n className={menuSearchClasses.input}\n {...passwordManagerOptOutProps}\n onKeyDown={e => {\n if (e.key !== 'ArrowDown') return;\n const panel = e.currentTarget.closest<HTMLElement>('[data-pick-multi-panel]');\n const first = panel?.querySelector<HTMLElement>('[data-pick-multi-item]:not([disabled])');\n if (!first) return;\n e.preventDefault();\n e.stopPropagation();\n first.focus();\n }}\n />\n </div>\n )}\n\n {field.isLoading ? (\n <div className={cn(menuEmptyClass, 'm-1')}>\n <Spinner size=\"sm\" className=\"size-3 text-muted-foreground\" />\n Loading options…\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={cn(menuEmptyClass, 'm-1')}>{field.emptyText ?? 'No option found.'}</div>\n ) : field.multi ? (\n <div className={listClassName}>\n <>\n {filteredOptions.map(option => {\n const checked = selectedValues.includes(option.value);\n return (\n <PickMultiItem\n key={option.value}\n role=\"checkbox\"\n checked={checked}\n label={option.label}\n onClick={() =>\n onChange(\n field.id,\n checked ? selectedValues.filter(v => v !== option.value) : [...selectedValues, option.value],\n )\n }\n />\n );\n })}\n </>\n </div>\n ) : (\n <div role=\"radiogroup\" className={listClassName}>\n <>\n {filteredOptions.map(option => (\n <PickMultiItem\n key={option.value}\n role=\"radio\"\n checked={selectedValue === option.value}\n label={option.label}\n onClick={() => onChange(field.id, option.value)}\n />\n ))}\n {!field.omitAnyOption && (\n <PickMultiItem\n role=\"radio\"\n checked={selectedValue === 'Any'}\n label=\"Any\"\n onClick={() => onChange(field.id, 'Any')}\n />\n )}\n </>\n </div>\n )}\n </>\n );\n}\n","import { LockIcon, XIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { Button } from '../Button';\nimport { ButtonsGroup, ButtonsGroupText } from '../ButtonsGroup';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../Tooltip';\nimport { PickMultiPanel } from './pick-multi-panel';\nimport type { PropertyFilterField, PropertyFilterToken } from './types';\nimport { Input } from '@/ds/components/Input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ds/components/Popover/popover';\nimport { MENU_SIDE_OFFSET } from '@/ds/primitives/menu-item';\n\nexport type PropertyFilterAppliedProps = {\n fields: PropertyFilterField[];\n tokens: PropertyFilterToken[];\n onTokensChange: (tokens: PropertyFilterToken[]) => void;\n disabled?: boolean;\n /**\n * Field id that was just added via the Creator — rendered pill auto-focuses\n * its input so the user can start typing immediately.\n */\n autoFocusFieldId?: string;\n /**\n * Field ids whose pills must remain visible and read-only — value stays\n * displayed but cannot be edited or removed. Use when an upstream context\n * (e.g. agent-scoped traces tab) pre-applies a filter that the user must\n * not be able to clear.\n */\n lockedFieldIds?: readonly string[];\n /** Tooltip content shown on hover/focus of any locked pill. */\n lockedTooltipContent?: ReactNode;\n};\n\nfunction stringifyTokenValue(value: string | string[]) {\n if (Array.isArray(value)) return value.length === 0 ? 'Any' : value.join(', ');\n return value;\n}\n\nconst DEFAULT_LOCKED_TOOLTIP = 'This filter is set by the current context and cannot be removed here.';\n\nfunction lookupOptionLabel(field: PropertyFilterField, value: string | string[]): string {\n if (field.kind === 'pick-multi' && field.options) {\n if (Array.isArray(value)) {\n if (value.length === 0) return 'Any';\n return value.map(v => field.options.find(o => o.value === v)?.label ?? v).join(', ');\n }\n return field.options.find(o => o.value === value)?.label ?? value;\n }\n return stringifyTokenValue(value);\n}\n\ntype LockedTokenPillProps = {\n field: PropertyFilterField;\n value: string | string[];\n tooltipContent: ReactNode;\n};\n\nfunction LockedTokenPill({ field, value, tooltipContent }: LockedTokenPillProps) {\n const display = lookupOptionLabel(field, value);\n const lockA11yLabel = `${field.label} filter is locked by context`;\n\n return (\n <TooltipProvider delayDuration={150}>\n <Tooltip>\n <TooltipTrigger asChild>\n <ButtonsGroup\n data-locked-field-id={field.id}\n data-property-filter-pill=\"locked\"\n tabIndex={0}\n aria-label={lockA11yLabel}\n >\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <ButtonsGroupText>{display}</ButtonsGroupText>\n <ButtonsGroupText>\n <LockIcon />\n </ButtonsGroupText>\n </ButtonsGroup>\n </TooltipTrigger>\n <TooltipContent>{tooltipContent}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n\ntype TextTokenPillProps = {\n field: Extract<PropertyFilterField, { kind: 'text' }>;\n value: string;\n onChange: (value: string) => void;\n onRemove: () => void;\n disabled?: boolean;\n autoFocus?: boolean;\n};\n\nfunction TextTokenPill({ field, value, onChange, onRemove, disabled, autoFocus }: TextTokenPillProps) {\n // Local draft keeps the caret stable when the URL round-trip trims the\n // stored value (e.g. trailing spaces). We only re-sync from the prop when\n // the external value is genuinely different from our current (trimmed) draft.\n const [draft, setDraft] = useState(value);\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (draft.trim() !== value) setDraft(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n useEffect(() => {\n if (autoFocus) inputRef.current?.focus();\n }, [autoFocus]);\n\n return (\n <ButtonsGroup>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <Input\n ref={inputRef}\n disabled={disabled}\n value={draft}\n placeholder={field.placeholder ?? `Enter ${field.label}`}\n onChange={e => {\n const next = e.target.value;\n setDraft(next);\n // Apply live — URL and traces query update on every keystroke.\n // Empty values persist as empty-value tokens so the pill stays visible.\n if (next.trim() !== value) onChange(next);\n }}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n const trimmed = draft.trim();\n if (trimmed !== value) onChange(trimmed);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setDraft(value);\n e.currentTarget.blur();\n }\n }}\n />\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onMouseDown={e => e.preventDefault()}\n onClick={onRemove}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n}\n\ntype PickMultiTokenPillProps = {\n field: Extract<PropertyFilterField, { kind: 'pick-multi' }>;\n token: PropertyFilterToken;\n tokens: PropertyFilterToken[];\n onChange: (fieldId: string, value: string | string[]) => void;\n onRemove: () => void;\n disabled?: boolean;\n};\n\nfunction PickMultiTokenPill({ field, token, tokens, onChange, onRemove, disabled }: PickMultiTokenPillProps) {\n const [open, setOpen] = useState(false);\n\n return (\n <ButtonsGroup>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button type=\"button\" disabled={disabled}>\n {stringifyTokenValue(token.value)}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" sideOffset={MENU_SIDE_OFFSET} className=\"w-64 p-0\" data-pick-multi-panel>\n <PickMultiPanel field={field} tokens={tokens} onChange={onChange} />\n </PopoverContent>\n </Popover>\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onClick={onRemove}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n}\n\n/**\n * Applied filter pills. Text/id-style tokens render with an always-active\n * input so the user can edit the value inline (and an empty token is valid —\n * it persists in the URL until the user explicitly removes it via ×).\n * Pick-multi tokens render with a clickable value that opens the same side\n * popover as the Filter Creator so the user can update selections in place.\n * Creation lives in a separate component (PropertyFilterCreator).\n */\nexport function PropertyFilterApplied({\n fields,\n tokens,\n onTokensChange,\n disabled,\n autoFocusFieldId,\n lockedFieldIds,\n lockedTooltipContent = DEFAULT_LOCKED_TOOLTIP,\n}: PropertyFilterAppliedProps) {\n if (tokens.length === 0) return null;\n\n const lockedSet = new Set(lockedFieldIds ?? []);\n\n const replaceTokenAt = (index: number, next: PropertyFilterToken) => {\n const copy = [...tokens];\n copy[index] = next;\n onTokensChange(copy);\n };\n\n const removeTokenAt = (index: number) => {\n onTokensChange(tokens.filter((_, i) => i !== index));\n };\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {tokens.map((token, index) => {\n const field = fields.find(f => f.id === token.fieldId);\n if (!field) return null;\n\n if (lockedSet.has(token.fieldId)) {\n return (\n <LockedTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n value={token.value}\n tooltipContent={lockedTooltipContent}\n />\n );\n }\n\n if (field.kind === 'text' && !Array.isArray(token.value)) {\n return (\n <TextTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n value={token.value}\n disabled={disabled}\n autoFocus={autoFocusFieldId === token.fieldId}\n onChange={nextValue => replaceTokenAt(index, { fieldId: token.fieldId, value: nextValue })}\n onRemove={() => removeTokenAt(index)}\n />\n );\n }\n\n if (field.kind === 'pick-multi') {\n return (\n <PickMultiTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n token={token}\n tokens={tokens}\n disabled={disabled}\n // Unselecting everything (empty array) keeps the pill alive in a\n // neutral state — the user explicitly removes it via ×. This lets\n // the page-level Reset neutralize values without dropping the pill.\n onChange={(fieldId, value) => replaceTokenAt(index, { fieldId, value })}\n onRemove={() => removeTokenAt(index)}\n />\n );\n }\n\n return (\n <ButtonsGroup key={`${token.fieldId}-${index}`}>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <ButtonsGroupText>{stringifyTokenValue(token.value)}</ButtonsGroupText>\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onClick={() => removeTokenAt(index)}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -104,7 +104,7 @@ function PickMultiPanel({ field, tokens, onChange }) {
|
|
|
104
104
|
type: "text",
|
|
105
105
|
value: query,
|
|
106
106
|
onChange: (e) => setQuery(e.target.value),
|
|
107
|
-
placeholder: `Search ${field.label.toLowerCase()}
|
|
107
|
+
placeholder: `Search ${field.label.toLowerCase()}`,
|
|
108
108
|
className: require_primitives_menu_item.menuSearchClasses.input,
|
|
109
109
|
...require_primitives_password_manager_autofill.passwordManagerOptOutProps,
|
|
110
110
|
onKeyDown: (e) => {
|
|
@@ -358,4 +358,4 @@ Object.defineProperty(exports, "PropertyFilterApplied", {
|
|
|
358
358
|
}
|
|
359
359
|
});
|
|
360
360
|
|
|
361
|
-
//# sourceMappingURL=property-filter-applied-
|
|
361
|
+
//# sourceMappingURL=property-filter-applied-BkkIObRq.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-filter-applied-BkkIObRq.cjs","names":["Button","XIcon","DropdownMenu","EllipsisVerticalIcon","SaveIcon","Trash2Icon","cn","menuItemButtonClass","menuItemCheckClass","CheckIcon","useState","useMemo","_Fragment","menuSearchClasses","SearchIcon","passwordManagerOptOutProps","menuEmptyClass","Spinner","TooltipProvider","Tooltip","TooltipTrigger","ButtonsGroup","ButtonsGroupText","LockIcon","TooltipContent","useState","useRef","Input","Button","XIcon","Popover","PopoverTrigger","PopoverContent"],"sources":["../src/ds/components/PropertyFilter/property-filter-actions.tsx","../src/ds/components/PropertyFilter/pick-multi-panel.tsx","../src/ds/components/PropertyFilter/property-filter-applied.tsx"],"sourcesContent":["import { EllipsisVerticalIcon, SaveIcon, Trash2Icon, XIcon } from 'lucide-react';\nimport { Button } from '@/ds/components/Button/Button';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu/dropdown-menu';\n\nexport type PropertyFilterActionsProps = {\n disabled?: boolean;\n /** Neutralize each pill's value (keep pills, clear values). Shown as a button, not a menu item. */\n onClear?: () => void;\n /** Fully remove all active filters. Rendered as \"Remove all filters\" inside the overflow menu. */\n onRemoveAll?: () => void;\n /** Persist the current filter set (typically to localStorage) for later restoration. */\n onSave?: () => void;\n /** Drop a previously-saved filter set. Wire only when a saved set actually exists. */\n onRemoveSaved?: () => void;\n};\n\n/**\n * Shared action bar for filter-driven pages (traces, logs, …). Renders a\n * Clear button and an overflow menu with Remove all / Save / Remove saved actions.\n */\nexport function PropertyFilterActions({\n disabled,\n onClear,\n onRemoveAll,\n onSave,\n onRemoveSaved,\n}: PropertyFilterActionsProps) {\n const hasMenuItems = !!(onRemoveAll || onSave || onRemoveSaved);\n if (!onClear && !hasMenuItems) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n {onClear && (\n <Button disabled={disabled} size=\"md\" onClick={onClear} icon={<XIcon />}>\n Clear\n </Button>\n )}\n\n {hasMenuItems && (\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button disabled={disabled} size=\"icon-md\" aria-label=\"More filter actions\">\n <EllipsisVerticalIcon />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {onRemoveAll && (\n <DropdownMenu.Item onSelect={() => onRemoveAll()}>\n <XIcon />\n Remove all filters\n </DropdownMenu.Item>\n )}\n {onRemoveAll && (onSave || onRemoveSaved) && <DropdownMenu.Separator />}\n {onSave && (\n <DropdownMenu.Item onSelect={() => onSave()}>\n <SaveIcon />\n Save filters for next time\n </DropdownMenu.Item>\n )}\n {onRemoveSaved && (\n <DropdownMenu.Item onSelect={() => onRemoveSaved()}>\n <Trash2Icon />\n Remove saved filters\n </DropdownMenu.Item>\n )}\n </DropdownMenu.Content>\n </DropdownMenu>\n )}\n </div>\n );\n}\n","import { CheckIcon, SearchIcon } from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport type { PropertyFilterField, PropertyFilterToken } from './types';\nimport { Spinner } from '@/ds/components/Spinner/spinner';\nimport { menuEmptyClass, menuItemButtonClass, menuItemCheckClass, menuSearchClasses } from '@/ds/primitives/menu-item';\nimport { passwordManagerOptOutProps } from '@/ds/primitives/password-manager-autofill';\nimport { cn } from '@/lib/utils';\n\n// Same rendering as Combobox items: no visible control, a trailing check when selected.\n// Focus is on the item itself (roving via [data-pick-multi-item]).\nconst pickMultiItemClass = cn(menuItemButtonClass, 'min-w-0');\n\nfunction PickMultiItem({\n role,\n checked,\n label,\n onClick,\n}: {\n role: 'checkbox' | 'radio';\n checked: boolean;\n label: string;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role={role}\n aria-checked={checked}\n data-selected={checked || undefined}\n data-pick-multi-item=\"\"\n title={label}\n className={pickMultiItemClass}\n onClick={onClick}\n >\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {checked && (\n <span className={menuItemCheckClass}>\n <CheckIcon />\n </span>\n )}\n </button>\n );\n}\n\ntype PickMultiField = Extract<PropertyFilterField, { kind: 'pick-multi' }>;\n\nexport type PickMultiPanelProps = {\n field: PickMultiField;\n tokens: PropertyFilterToken[];\n /** Always carries a value: an empty list is how the panel says \"nothing selected\". */\n onChange: (fieldId: string, value: string | string[]) => void;\n};\n\n/**\n * Reusable body for a pick-multi side popover: optional search input plus a\n * radio group (single-select) or checkbox list (when `field.multi` is true).\n * Shared between the Filter Creator's property-picker side popover and the\n * PropertyFilterApplied pill's inline editor so both surfaces use the exact same UI.\n */\nexport function PickMultiPanel({ field, tokens, onChange }: PickMultiPanelProps) {\n const [query, setQuery] = useState('');\n const listClassName = 'max-h-[80dvh] overflow-auto p-1';\n\n const filteredOptions = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return field.options;\n return field.options.filter(o => o.label.toLowerCase().includes(q));\n }, [field.options, query]);\n\n const token = useMemo(() => tokens.find(t => t.fieldId === field.id), [tokens, field.id]);\n // Fall back to `defaultValue` when no token exists — lets view-toggle fields (e.g. List mode)\n // show their default option pre-selected before the user explicitly picks one.\n const selectedValue = typeof token?.value === 'string' ? token.value : !field.multi ? field.defaultValue : undefined;\n const selectedValues = useMemo<string[]>(() => {\n const value = token?.value;\n if (Array.isArray(value)) return value;\n if (typeof value === 'string') return [value];\n return [];\n }, [token]);\n\n return (\n <>\n {field.searchable !== false && (\n <div className={menuSearchClasses.container}>\n <SearchIcon className={menuSearchClasses.icon} />\n <input\n type=\"text\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n placeholder={`Search ${field.label.toLowerCase()}`}\n className={menuSearchClasses.input}\n {...passwordManagerOptOutProps}\n onKeyDown={e => {\n if (e.key !== 'ArrowDown') return;\n const panel = e.currentTarget.closest<HTMLElement>('[data-pick-multi-panel]');\n const first = panel?.querySelector<HTMLElement>('[data-pick-multi-item]:not([disabled])');\n if (!first) return;\n e.preventDefault();\n e.stopPropagation();\n first.focus();\n }}\n />\n </div>\n )}\n\n {field.isLoading ? (\n <div className={cn(menuEmptyClass, 'm-1')}>\n <Spinner size=\"sm\" className=\"size-3 text-muted-foreground\" />\n Loading options…\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={cn(menuEmptyClass, 'm-1')}>{field.emptyText ?? 'No option found.'}</div>\n ) : field.multi ? (\n <div className={listClassName}>\n <>\n {filteredOptions.map(option => {\n const checked = selectedValues.includes(option.value);\n return (\n <PickMultiItem\n key={option.value}\n role=\"checkbox\"\n checked={checked}\n label={option.label}\n onClick={() =>\n onChange(\n field.id,\n checked ? selectedValues.filter(v => v !== option.value) : [...selectedValues, option.value],\n )\n }\n />\n );\n })}\n </>\n </div>\n ) : (\n <div role=\"radiogroup\" className={listClassName}>\n <>\n {filteredOptions.map(option => (\n <PickMultiItem\n key={option.value}\n role=\"radio\"\n checked={selectedValue === option.value}\n label={option.label}\n onClick={() => onChange(field.id, option.value)}\n />\n ))}\n {!field.omitAnyOption && (\n <PickMultiItem\n role=\"radio\"\n checked={selectedValue === 'Any'}\n label=\"Any\"\n onClick={() => onChange(field.id, 'Any')}\n />\n )}\n </>\n </div>\n )}\n </>\n );\n}\n","import { LockIcon, XIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { Button } from '../Button';\nimport { ButtonsGroup, ButtonsGroupText } from '../ButtonsGroup';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../Tooltip';\nimport { PickMultiPanel } from './pick-multi-panel';\nimport type { PropertyFilterField, PropertyFilterToken } from './types';\nimport { Input } from '@/ds/components/Input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ds/components/Popover/popover';\nimport { MENU_SIDE_OFFSET } from '@/ds/primitives/menu-item';\n\nexport type PropertyFilterAppliedProps = {\n fields: PropertyFilterField[];\n tokens: PropertyFilterToken[];\n onTokensChange: (tokens: PropertyFilterToken[]) => void;\n disabled?: boolean;\n /**\n * Field id that was just added via the Creator — rendered pill auto-focuses\n * its input so the user can start typing immediately.\n */\n autoFocusFieldId?: string;\n /**\n * Field ids whose pills must remain visible and read-only — value stays\n * displayed but cannot be edited or removed. Use when an upstream context\n * (e.g. agent-scoped traces tab) pre-applies a filter that the user must\n * not be able to clear.\n */\n lockedFieldIds?: readonly string[];\n /** Tooltip content shown on hover/focus of any locked pill. */\n lockedTooltipContent?: ReactNode;\n};\n\nfunction stringifyTokenValue(value: string | string[]) {\n if (Array.isArray(value)) return value.length === 0 ? 'Any' : value.join(', ');\n return value;\n}\n\nconst DEFAULT_LOCKED_TOOLTIP = 'This filter is set by the current context and cannot be removed here.';\n\nfunction lookupOptionLabel(field: PropertyFilterField, value: string | string[]): string {\n if (field.kind === 'pick-multi' && field.options) {\n if (Array.isArray(value)) {\n if (value.length === 0) return 'Any';\n return value.map(v => field.options.find(o => o.value === v)?.label ?? v).join(', ');\n }\n return field.options.find(o => o.value === value)?.label ?? value;\n }\n return stringifyTokenValue(value);\n}\n\ntype LockedTokenPillProps = {\n field: PropertyFilterField;\n value: string | string[];\n tooltipContent: ReactNode;\n};\n\nfunction LockedTokenPill({ field, value, tooltipContent }: LockedTokenPillProps) {\n const display = lookupOptionLabel(field, value);\n const lockA11yLabel = `${field.label} filter is locked by context`;\n\n return (\n <TooltipProvider delayDuration={150}>\n <Tooltip>\n <TooltipTrigger asChild>\n <ButtonsGroup\n data-locked-field-id={field.id}\n data-property-filter-pill=\"locked\"\n tabIndex={0}\n aria-label={lockA11yLabel}\n >\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <ButtonsGroupText>{display}</ButtonsGroupText>\n <ButtonsGroupText>\n <LockIcon />\n </ButtonsGroupText>\n </ButtonsGroup>\n </TooltipTrigger>\n <TooltipContent>{tooltipContent}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n\ntype TextTokenPillProps = {\n field: Extract<PropertyFilterField, { kind: 'text' }>;\n value: string;\n onChange: (value: string) => void;\n onRemove: () => void;\n disabled?: boolean;\n autoFocus?: boolean;\n};\n\nfunction TextTokenPill({ field, value, onChange, onRemove, disabled, autoFocus }: TextTokenPillProps) {\n // Local draft keeps the caret stable when the URL round-trip trims the\n // stored value (e.g. trailing spaces). We only re-sync from the prop when\n // the external value is genuinely different from our current (trimmed) draft.\n const [draft, setDraft] = useState(value);\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (draft.trim() !== value) setDraft(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n useEffect(() => {\n if (autoFocus) inputRef.current?.focus();\n }, [autoFocus]);\n\n return (\n <ButtonsGroup>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <Input\n ref={inputRef}\n disabled={disabled}\n value={draft}\n placeholder={field.placeholder ?? `Enter ${field.label}`}\n onChange={e => {\n const next = e.target.value;\n setDraft(next);\n // Apply live — URL and traces query update on every keystroke.\n // Empty values persist as empty-value tokens so the pill stays visible.\n if (next.trim() !== value) onChange(next);\n }}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n const trimmed = draft.trim();\n if (trimmed !== value) onChange(trimmed);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setDraft(value);\n e.currentTarget.blur();\n }\n }}\n />\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onMouseDown={e => e.preventDefault()}\n onClick={onRemove}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n}\n\ntype PickMultiTokenPillProps = {\n field: Extract<PropertyFilterField, { kind: 'pick-multi' }>;\n token: PropertyFilterToken;\n tokens: PropertyFilterToken[];\n onChange: (fieldId: string, value: string | string[]) => void;\n onRemove: () => void;\n disabled?: boolean;\n};\n\nfunction PickMultiTokenPill({ field, token, tokens, onChange, onRemove, disabled }: PickMultiTokenPillProps) {\n const [open, setOpen] = useState(false);\n\n return (\n <ButtonsGroup>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button type=\"button\" disabled={disabled}>\n {stringifyTokenValue(token.value)}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" sideOffset={MENU_SIDE_OFFSET} className=\"w-64 p-0\" data-pick-multi-panel>\n <PickMultiPanel field={field} tokens={tokens} onChange={onChange} />\n </PopoverContent>\n </Popover>\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onClick={onRemove}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n}\n\n/**\n * Applied filter pills. Text/id-style tokens render with an always-active\n * input so the user can edit the value inline (and an empty token is valid —\n * it persists in the URL until the user explicitly removes it via ×).\n * Pick-multi tokens render with a clickable value that opens the same side\n * popover as the Filter Creator so the user can update selections in place.\n * Creation lives in a separate component (PropertyFilterCreator).\n */\nexport function PropertyFilterApplied({\n fields,\n tokens,\n onTokensChange,\n disabled,\n autoFocusFieldId,\n lockedFieldIds,\n lockedTooltipContent = DEFAULT_LOCKED_TOOLTIP,\n}: PropertyFilterAppliedProps) {\n if (tokens.length === 0) return null;\n\n const lockedSet = new Set(lockedFieldIds ?? []);\n\n const replaceTokenAt = (index: number, next: PropertyFilterToken) => {\n const copy = [...tokens];\n copy[index] = next;\n onTokensChange(copy);\n };\n\n const removeTokenAt = (index: number) => {\n onTokensChange(tokens.filter((_, i) => i !== index));\n };\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {tokens.map((token, index) => {\n const field = fields.find(f => f.id === token.fieldId);\n if (!field) return null;\n\n if (lockedSet.has(token.fieldId)) {\n return (\n <LockedTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n value={token.value}\n tooltipContent={lockedTooltipContent}\n />\n );\n }\n\n if (field.kind === 'text' && !Array.isArray(token.value)) {\n return (\n <TextTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n value={token.value}\n disabled={disabled}\n autoFocus={autoFocusFieldId === token.fieldId}\n onChange={nextValue => replaceTokenAt(index, { fieldId: token.fieldId, value: nextValue })}\n onRemove={() => removeTokenAt(index)}\n />\n );\n }\n\n if (field.kind === 'pick-multi') {\n return (\n <PickMultiTokenPill\n key={`${token.fieldId}-${index}`}\n field={field}\n token={token}\n tokens={tokens}\n disabled={disabled}\n // Unselecting everything (empty array) keeps the pill alive in a\n // neutral state — the user explicitly removes it via ×. This lets\n // the page-level Reset neutralize values without dropping the pill.\n onChange={(fieldId, value) => replaceTokenAt(index, { fieldId, value })}\n onRemove={() => removeTokenAt(index)}\n />\n );\n }\n\n return (\n <ButtonsGroup key={`${token.fieldId}-${index}`}>\n <ButtonsGroupText>{field.label}</ButtonsGroupText>\n <ButtonsGroupText>is</ButtonsGroupText>\n <ButtonsGroupText>{stringifyTokenValue(token.value)}</ButtonsGroupText>\n <Button\n size=\"icon-md\"\n type=\"button\"\n disabled={disabled}\n aria-label={`Remove ${field.label} filter`}\n onClick={() => removeTokenAt(index)}\n >\n <XIcon />\n </Button>\n </ButtonsGroup>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,10 +6,17 @@ export type MetricsTableBodyProps<Row> = RowBehavior<Row> & {
|
|
|
6
6
|
rows: Row[];
|
|
7
7
|
getRowKey: (row: Row) => string;
|
|
8
8
|
empty: MetricsTableProps<Row>['empty'];
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/** A paged table's rows per page: drawn while loading, and kept as the empty table's height. */
|
|
10
|
+
pageSize: number | undefined;
|
|
11
11
|
isLoading: boolean;
|
|
12
12
|
};
|
|
13
13
|
/** Skeleton rows while loading, the empty message without rows, else the page's rows. */
|
|
14
|
-
export declare function MetricsTableBody<Row>({ columns, rows, getRowKey, empty,
|
|
14
|
+
export declare function MetricsTableBody<Row>({ columns, rows, getRowKey, empty, pageSize, isLoading, ...behavior }: MetricsTableBodyProps<Row>): import("react").JSX.Element[] | import("react").JSX.Element | null;
|
|
15
|
+
/**
|
|
16
|
+
* Blank space as tall as `count` rows, so a paged table is a full page tall however many rows it
|
|
17
|
+
* shows. Rows of the same box, not a fixed height, so it follows the row's text size.
|
|
18
|
+
*/
|
|
19
|
+
export declare function MetricsTableFiller({ count }: {
|
|
20
|
+
count: number;
|
|
21
|
+
}): import("react").JSX.Element | null;
|
|
15
22
|
export {};
|
|
@@ -3,6 +3,6 @@ import type { MetricsTableProps } from './metrics-table-types';
|
|
|
3
3
|
* A table for the numbers behind a chart: one row per series or group, columns for its figures,
|
|
4
4
|
* separated by lines that fade at the ends. With `SeriesMark` and `Sparkline` cells and the row
|
|
5
5
|
* hover and click hooks it doubles as the chart's legend; without them it's a plain data table.
|
|
6
|
-
* With `pageSize` it pages long lists. For a share of a total, a compact `ShareBar` fits better.
|
|
6
|
+
* With `pageSize` it pages long lists, and is always a full page tall. For a share of a total, a compact `ShareBar` fits better.
|
|
7
7
|
*/
|
|
8
8
|
export declare function MetricsTable<Row>({ columns, rows, getRowKey, sort, defaultSort, onSortChange, onRowClick, onRowHover, isRowDimmed, isRowActive, rowTitle, empty, pageSize, isLoading, 'aria-label': ariaLabel, className, }: MetricsTableProps<Row>): import("react").JSX.Element;
|