@perses-dev/components 0.55.0-beta.8 → 0.55.0-rc.0
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/DragAndDrop/DragAndDropList.d.ts +10 -2
- package/dist/DragAndDrop/DragAndDropList.d.ts.map +1 -1
- package/dist/DragAndDrop/DragAndDropList.js +6 -4
- package/dist/DragAndDrop/DragAndDropList.js.map +1 -1
- package/dist/EChart/EChart.d.ts +1 -1
- package/dist/EChart/EChart.d.ts.map +1 -1
- package/dist/EChart/EChart.js +12 -25
- package/dist/EChart/EChart.js.map +1 -1
- package/dist/ExemplarMetadata/ExemplarMetadataTooltip.d.ts +27 -0
- package/dist/ExemplarMetadata/ExemplarMetadataTooltip.d.ts.map +1 -0
- package/dist/ExemplarMetadata/ExemplarMetadataTooltip.js +239 -0
- package/dist/ExemplarMetadata/ExemplarMetadataTooltip.js.map +1 -0
- package/dist/ExemplarMetadata/index.d.ts +2 -0
- package/dist/ExemplarMetadata/index.d.ts.map +1 -0
- package/dist/{utils/component-ids.js → ExemplarMetadata/index.js} +2 -15
- package/dist/ExemplarMetadata/index.js.map +1 -0
- package/dist/FormatControls/FormatControls.d.ts.map +1 -1
- package/dist/FormatControls/FormatControls.js +42 -4
- package/dist/FormatControls/FormatControls.js.map +1 -1
- package/dist/FormatControls/UnitSelector.js +4 -4
- package/dist/FormatControls/UnitSelector.js.map +1 -1
- package/dist/Legend/TableLegend.d.ts.map +1 -1
- package/dist/Legend/TableLegend.js +2 -1
- package/dist/Legend/TableLegend.js.map +1 -1
- package/dist/LinksEditor/LinkEditorForm.d.ts +1 -0
- package/dist/LinksEditor/LinkEditorForm.d.ts.map +1 -1
- package/dist/LinksEditor/LinkEditorForm.js +1 -0
- package/dist/LinksEditor/LinkEditorForm.js.map +1 -1
- package/dist/OptionsEditorLayout/OptionsEditorControl.d.ts.map +1 -1
- package/dist/OptionsEditorLayout/OptionsEditorControl.js +2 -3
- package/dist/OptionsEditorLayout/OptionsEditorControl.js.map +1 -1
- package/dist/SettingsAutocomplete/SettingsAutocomplete.d.ts.map +1 -1
- package/dist/SettingsAutocomplete/SettingsAutocomplete.js +6 -3
- package/dist/SettingsAutocomplete/SettingsAutocomplete.js.map +1 -1
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +3 -0
- package/dist/Table/Table.js.map +1 -1
- package/dist/Table/TableToolbar.d.ts.map +1 -1
- package/dist/Table/TableToolbar.js +1 -0
- package/dist/Table/TableToolbar.js.map +1 -1
- package/dist/Table/VirtualizedTable.d.ts +1 -1
- package/dist/Table/VirtualizedTable.d.ts.map +1 -1
- package/dist/Table/VirtualizedTable.js +10 -19
- package/dist/Table/VirtualizedTable.js.map +1 -1
- package/dist/Table/model/table-model.d.ts +6 -2
- package/dist/Table/model/table-model.d.ts.map +1 -1
- package/dist/Table/model/table-model.js.map +1 -1
- package/dist/ThresholdsEditor/ThresholdsEditor.js +1 -3
- package/dist/ThresholdsEditor/ThresholdsEditor.js.map +1 -1
- package/dist/TimeRangeSelector/DateTimeRangePicker.js +1 -1
- package/dist/TimeRangeSelector/DateTimeRangePicker.js.map +1 -1
- package/dist/TimeRangeSelector/TimeRangeSelector.js +4 -4
- package/dist/TimeRangeSelector/TimeRangeSelector.js.map +1 -1
- package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts.map +1 -1
- package/dist/TimeSeriesTooltip/TimeChartTooltip.js +27 -16
- package/dist/TimeSeriesTooltip/TimeChartTooltip.js.map +1 -1
- package/dist/TimeSeriesTooltip/utils.d.ts.map +1 -1
- package/dist/TimeSeriesTooltip/utils.js +6 -2
- package/dist/TimeSeriesTooltip/utils.js.map +1 -1
- package/dist/TransformsEditor/TransformEditor.d.ts.map +1 -1
- package/dist/TransformsEditor/TransformEditor.js +89 -0
- package/dist/TransformsEditor/TransformEditor.js.map +1 -1
- package/dist/controls/TextField.d.ts.map +1 -1
- package/dist/controls/TextField.js +15 -10
- package/dist/controls/TextField.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/model/custom.d.ts +22 -0
- package/dist/model/custom.d.ts.map +1 -0
- package/dist/model/custom.js +243 -0
- package/dist/model/custom.js.map +1 -0
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +1 -0
- package/dist/model/index.js.map +1 -1
- package/dist/model/transforms.d.ts +22 -1
- package/dist/model/transforms.d.ts.map +1 -1
- package/dist/model/transforms.js +2 -1
- package/dist/model/transforms.js.map +1 -1
- package/dist/model/units.d.ts +12 -10
- package/dist/model/units.d.ts.map +1 -1
- package/dist/model/units.js +33 -28
- package/dist/model/units.js.map +1 -1
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +0 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js +14 -18
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/transform-data.d.ts +5 -0
- package/dist/utils/transform-data.d.ts.map +1 -1
- package/dist/utils/transform-data.js +96 -0
- package/dist/utils/transform-data.js.map +1 -1
- package/dist/utils/variable-interpolation.d.ts +11 -0
- package/dist/utils/variable-interpolation.d.ts.map +1 -1
- package/dist/utils/variable-interpolation.js +64 -0
- package/dist/utils/variable-interpolation.js.map +1 -1
- package/package.json +3 -3
- package/dist/utils/component-ids.d.ts +0 -8
- package/dist/utils/component-ids.d.ts.map +0 -1
- package/dist/utils/component-ids.js.map +0 -1
- package/dist/utils/memo.d.ts +0 -13
- package/dist/utils/memo.d.ts.map +0 -1
- package/dist/utils/memo.js +0 -50
- package/dist/utils/memo.js.map +0 -1
|
@@ -15,7 +15,7 @@ import { Box, MenuItem, Popover, Select, IconButton, TextField, Stack } from "@m
|
|
|
15
15
|
import { isRelativeTimeRange, toAbsoluteTimeRange } from "@perses-dev/spec";
|
|
16
16
|
import Calendar from "mdi-material-ui/Calendar";
|
|
17
17
|
import EarthIcon from "mdi-material-ui/Earth";
|
|
18
|
-
import { useMemo,
|
|
18
|
+
import { useMemo, useState } from "react";
|
|
19
19
|
import { useTimeZone } from "../context/index.js";
|
|
20
20
|
import { getTimeZoneOptions } from "../model/timeZoneOption.js";
|
|
21
21
|
import { SettingsAutocomplete } from "../SettingsAutocomplete/index.js";
|
|
@@ -30,7 +30,7 @@ import { buildCustomTimeOption, formatTimeRange } from "./utils.js";
|
|
|
30
30
|
*/ export function TimeRangeSelector({ value, timeOptions, onChange, height, showCustomTimeRange = true, timeZone: timeZoneProp, timeZoneOptions, onTimeZoneChange }) {
|
|
31
31
|
const { timeZone: ctxTimeZone } = useTimeZone();
|
|
32
32
|
const timeZone = timeZoneProp ?? ctxTimeZone;
|
|
33
|
-
const anchorEl =
|
|
33
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
34
34
|
const [showCustomDateSelector, setShowCustomDateSelector] = useState(false);
|
|
35
35
|
const convertedTimeRange = useMemo(()=>{
|
|
36
36
|
return isRelativeTimeRange(value) ? toAbsoluteTimeRange(value) : value;
|
|
@@ -98,7 +98,7 @@ import { buildCustomTimeOption, formatTimeRange } from "./utils.js";
|
|
|
98
98
|
})
|
|
99
99
|
}),
|
|
100
100
|
/*#__PURE__*/ _jsx(Popover, {
|
|
101
|
-
anchorEl: anchorEl
|
|
101
|
+
anchorEl: anchorEl,
|
|
102
102
|
anchorOrigin: {
|
|
103
103
|
vertical: 'bottom',
|
|
104
104
|
horizontal: 'center'
|
|
@@ -120,7 +120,7 @@ import { buildCustomTimeOption, formatTimeRange } from "./utils.js";
|
|
|
120
120
|
})
|
|
121
121
|
}),
|
|
122
122
|
/*#__PURE__*/ _jsx(Box, {
|
|
123
|
-
ref:
|
|
123
|
+
ref: setAnchorEl,
|
|
124
124
|
children: /*#__PURE__*/ _jsxs(Select, {
|
|
125
125
|
open: open,
|
|
126
126
|
value: formatTimeRange(value, timeZone),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/TimeRangeSelector/TimeRangeSelector.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, MenuItem, Popover, Select, IconButton, TextField, Stack } from '@mui/material';\nimport type { TimeRangeValue, AbsoluteTimeRange } from '@perses-dev/spec';\nimport { isRelativeTimeRange, toAbsoluteTimeRange } from '@perses-dev/spec';\nimport Calendar from 'mdi-material-ui/Calendar';\nimport EarthIcon from 'mdi-material-ui/Earth';\nimport type { ReactElement } from 'react';\nimport { useMemo, useRef, useState } from 'react';\n\nimport { useTimeZone } from '../context';\nimport type { TimeOption } from '../model';\nimport type { TimeZoneOption } from '../model/timeZoneOption';\nimport { getTimeZoneOptions } from '../model/timeZoneOption';\nimport { SettingsAutocomplete } from '../SettingsAutocomplete';\nimport { getGMTOffset } from '../utils/format';\nimport { DateTimeRangePicker } from './DateTimeRangePicker';\nimport { buildCustomTimeOption, formatTimeRange } from './utils';\n\ninterface TimeRangeSelectorProps {\n /**\n * The current value of the time range.\n */\n value: TimeRangeValue;\n /**\n * The list of time options to display in the dropdown.\n * The component will automatically add the last two options as a zoom out x2 and a custom absolute time range.\n */\n timeOptions: TimeOption[];\n /**\n * The callback to call when the time range changes.\n */\n onChange: (value: TimeRangeValue) => void;\n /**\n * Custom line height for the select component.\n */\n height?: string;\n /**\n * Whether to show the custom time range option.\n * Defaults to true.\n */\n showCustomTimeRange?: boolean;\n /** Optional explicit timezone and change handler to enable changing tz from the selector */\n timeZone?: string;\n timeZoneOptions?: TimeZoneOption[];\n onTimeZoneChange?: (timeZone: TimeZoneOption) => void;\n}\n\n/**\n * Date & time selection component to customize what data renders on dashboard.\n * This includes relative shortcuts and the ability to pick absolute start and end times.\n * @param props\n * @constructor\n */\nexport function TimeRangeSelector({\n value,\n timeOptions,\n onChange,\n height,\n showCustomTimeRange = true,\n timeZone: timeZoneProp,\n timeZoneOptions,\n onTimeZoneChange,\n}: TimeRangeSelectorProps): ReactElement {\n const { timeZone: ctxTimeZone } = useTimeZone();\n const timeZone = timeZoneProp ?? ctxTimeZone;\n\n const anchorEl = useRef();\n const [showCustomDateSelector, setShowCustomDateSelector] = useState(false);\n\n const convertedTimeRange = useMemo(() => {\n return isRelativeTimeRange(value) ? toAbsoluteTimeRange(value) : value;\n }, [value]);\n\n const lastOption = useMemo(\n () => buildCustomTimeOption(isRelativeTimeRange(value) ? undefined : value, timeZone),\n [value, timeZone],\n );\n\n const [open, setOpen] = useState(false);\n const tzOptions = timeZoneOptions ?? getTimeZoneOptions();\n const [tzAnchorEl, setTzAnchorEl] = useState<HTMLElement | null>(null);\n const tzOpen = Boolean(tzAnchorEl);\n const tzLabel = tzOptions.find((o) => o.value === timeZone)?.display ?? timeZone;\n const tzOffset = getGMTOffset(timeZone);\n const localOffset = getGMTOffset('local');\n const tzAutocompleteOptions = tzOptions.map((o) => ({ id: o.value, label: o.display }));\n const tzAutocompleteValue = tzAutocompleteOptions.find((option) => option.id === timeZone);\n\n return (\n <>\n <Popover\n anchorEl={tzAnchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n open={tzOpen}\n onClose={() => setTzAnchorEl(null)}\n sx={(theme) => ({ padding: theme.spacing(1) })}\n >\n <Box\n sx={{ p: 1, minWidth: 260 }}\n onClick={(e) => {\n e.stopPropagation();\n }}\n >\n <SettingsAutocomplete\n options={tzAutocompleteOptions}\n value={tzAutocompleteValue}\n onChange={(_e, option) => {\n if (option) {\n const selected = tzOptions.find((o) => o.value === option.id);\n if (selected) onTimeZoneChange?.(selected);\n }\n setTzAnchorEl(null);\n }}\n disableClearable\n renderInput={(params) => <TextField {...params} placeholder=\"Search timezones\" size=\"small\" />}\n />\n </Box>\n </Popover>\n <Popover\n anchorEl={anchorEl.current}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n open={showCustomDateSelector}\n onClose={() => setShowCustomDateSelector(false)}\n sx={(theme) => ({ padding: theme.spacing(2) })}\n >\n <DateTimeRangePicker\n initialTimeRange={convertedTimeRange}\n onChange={(value: AbsoluteTimeRange) => {\n onChange(value);\n setShowCustomDateSelector(false);\n setOpen(false);\n }}\n onCancel={() => setShowCustomDateSelector(false)}\n timeZone={timeZone}\n />\n </Popover>\n <Box ref={anchorEl}>\n <Select\n open={open}\n value={formatTimeRange(value, timeZone)}\n onClick={() => setOpen(!open)}\n IconComponent={Calendar}\n renderValue={() => (\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <span>\n {timeOptions.find((opt) => formatTimeRange(opt.value, timeZone) === formatTimeRange(value, timeZone))\n ?.display ?? formatTimeRange(value, timeZone)}\n </span>\n {tzOffset !== localOffset && (\n <Box sx={{ typography: 'caption', color: 'text.secondary' }}>· {tzOffset}</Box>\n )}\n </Stack>\n )}\n inputProps={{ 'aria-label': `Select time range. Currently set to ${value}` }}\n sx={{\n '.MuiSelect-icon': { marginTop: '1px', transform: 'none' },\n '.MuiSelect-select.MuiSelect-outlined.MuiInputBase-input': { paddingRight: '36px' },\n '.MuiSelect-select': height ? { lineHeight: height, paddingY: 0 } : {},\n }}\n >\n <MenuItem\n disableRipple\n onClick={(e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n sx={{ cursor: 'default', '&:hover': { backgroundColor: 'transparent' }, py: 0.5, px: 1 }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', width: '100%', justifyContent: 'space-between' }}>\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>\n <Box sx={{ typography: 'subtitle1' }}>Time Range</Box>\n <Box sx={{ color: 'text.secondary', typography: 'caption', mt: 0.25 }}>Timezone: {tzLabel}</Box>\n </Box>\n <Box sx={{ display: 'flex', alignItems: 'center', pr: 1, ml: 1.5 }}>\n <IconButton\n size=\"small\"\n aria-label=\"Select timezone\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setTzAnchorEl(e.currentTarget);\n }}\n >\n <EarthIcon fontSize=\"small\" />\n </IconButton>\n </Box>\n </Box>\n </MenuItem>\n {timeOptions.map((item, idx) => (\n <MenuItem\n key={idx}\n value={formatTimeRange(item.value, timeZone)}\n onClick={() => {\n onChange(item.value);\n }}\n >\n {item.display}\n </MenuItem>\n ))}\n {showCustomTimeRange && (\n <MenuItem\n value={formatTimeRange(lastOption.value, timeZone)}\n onClick={() => setShowCustomDateSelector(true)}\n >\n {lastOption.display}\n </MenuItem>\n )}\n </Select>\n </Box>\n </>\n );\n}\n"],"names":["Box","MenuItem","Popover","Select","IconButton","TextField","Stack","isRelativeTimeRange","toAbsoluteTimeRange","Calendar","EarthIcon","useMemo","useRef","useState","useTimeZone","getTimeZoneOptions","SettingsAutocomplete","getGMTOffset","DateTimeRangePicker","buildCustomTimeOption","formatTimeRange","TimeRangeSelector","value","timeOptions","onChange","height","showCustomTimeRange","timeZone","timeZoneProp","timeZoneOptions","onTimeZoneChange","ctxTimeZone","anchorEl","showCustomDateSelector","setShowCustomDateSelector","convertedTimeRange","lastOption","undefined","open","setOpen","tzOptions","tzAnchorEl","setTzAnchorEl","tzOpen","Boolean","tzLabel","find","o","display","tzOffset","localOffset","tzAutocompleteOptions","map","id","label","tzAutocompleteValue","option","anchorOrigin","vertical","horizontal","transformOrigin","onClose","sx","theme","padding","spacing","p","minWidth","onClick","e","stopPropagation","options","_e","selected","disableClearable","renderInput","params","placeholder","size","current","initialTimeRange","onCancel","ref","IconComponent","renderValue","direction","alignItems","span","opt","typography","color","inputProps","marginTop","transform","paddingRight","lineHeight","paddingY","disableRipple","preventDefault","cursor","backgroundColor","py","px","width","justifyContent","flexDirection","mt","pr","ml","aria-label","currentTarget","fontSize","item","idx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/TimeRangeSelector/TimeRangeSelector.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, MenuItem, Popover, Select, IconButton, TextField, Stack } from '@mui/material';\nimport type { TimeRangeValue, AbsoluteTimeRange } from '@perses-dev/spec';\nimport { isRelativeTimeRange, toAbsoluteTimeRange } from '@perses-dev/spec';\nimport Calendar from 'mdi-material-ui/Calendar';\nimport EarthIcon from 'mdi-material-ui/Earth';\nimport type { ReactElement } from 'react';\nimport { useMemo, useState } from 'react';\n\nimport { useTimeZone } from '../context';\nimport type { TimeOption } from '../model';\nimport type { TimeZoneOption } from '../model/timeZoneOption';\nimport { getTimeZoneOptions } from '../model/timeZoneOption';\nimport { SettingsAutocomplete } from '../SettingsAutocomplete';\nimport { getGMTOffset } from '../utils/format';\nimport { DateTimeRangePicker } from './DateTimeRangePicker';\nimport { buildCustomTimeOption, formatTimeRange } from './utils';\n\ninterface TimeRangeSelectorProps {\n /**\n * The current value of the time range.\n */\n value: TimeRangeValue;\n /**\n * The list of time options to display in the dropdown.\n * The component will automatically add the last two options as a zoom out x2 and a custom absolute time range.\n */\n timeOptions: TimeOption[];\n /**\n * The callback to call when the time range changes.\n */\n onChange: (value: TimeRangeValue) => void;\n /**\n * Custom line height for the select component.\n */\n height?: string;\n /**\n * Whether to show the custom time range option.\n * Defaults to true.\n */\n showCustomTimeRange?: boolean;\n /** Optional explicit timezone and change handler to enable changing tz from the selector */\n timeZone?: string;\n timeZoneOptions?: TimeZoneOption[];\n onTimeZoneChange?: (timeZone: TimeZoneOption) => void;\n}\n\n/**\n * Date & time selection component to customize what data renders on dashboard.\n * This includes relative shortcuts and the ability to pick absolute start and end times.\n * @param props\n * @constructor\n */\nexport function TimeRangeSelector({\n value,\n timeOptions,\n onChange,\n height,\n showCustomTimeRange = true,\n timeZone: timeZoneProp,\n timeZoneOptions,\n onTimeZoneChange,\n}: TimeRangeSelectorProps): ReactElement {\n const { timeZone: ctxTimeZone } = useTimeZone();\n const timeZone = timeZoneProp ?? ctxTimeZone;\n\n const [anchorEl, setAnchorEl] = useState<HTMLDivElement | null>(null);\n const [showCustomDateSelector, setShowCustomDateSelector] = useState(false);\n\n const convertedTimeRange = useMemo(() => {\n return isRelativeTimeRange(value) ? toAbsoluteTimeRange(value) : value;\n }, [value]);\n\n const lastOption = useMemo(\n () => buildCustomTimeOption(isRelativeTimeRange(value) ? undefined : value, timeZone),\n [value, timeZone],\n );\n\n const [open, setOpen] = useState(false);\n const tzOptions = timeZoneOptions ?? getTimeZoneOptions();\n const [tzAnchorEl, setTzAnchorEl] = useState<HTMLElement | null>(null);\n const tzOpen = Boolean(tzAnchorEl);\n const tzLabel = tzOptions.find((o) => o.value === timeZone)?.display ?? timeZone;\n const tzOffset = getGMTOffset(timeZone);\n const localOffset = getGMTOffset('local');\n const tzAutocompleteOptions = tzOptions.map((o) => ({ id: o.value, label: o.display }));\n const tzAutocompleteValue = tzAutocompleteOptions.find((option) => option.id === timeZone);\n\n return (\n <>\n <Popover\n anchorEl={tzAnchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n open={tzOpen}\n onClose={() => setTzAnchorEl(null)}\n sx={(theme) => ({ padding: theme.spacing(1) })}\n >\n <Box\n sx={{ p: 1, minWidth: 260 }}\n onClick={(e) => {\n e.stopPropagation();\n }}\n >\n <SettingsAutocomplete\n options={tzAutocompleteOptions}\n value={tzAutocompleteValue}\n onChange={(_e, option) => {\n if (option) {\n const selected = tzOptions.find((o) => o.value === option.id);\n if (selected) onTimeZoneChange?.(selected);\n }\n setTzAnchorEl(null);\n }}\n disableClearable\n renderInput={(params) => <TextField {...params} placeholder=\"Search timezones\" size=\"small\" />}\n />\n </Box>\n </Popover>\n <Popover\n anchorEl={anchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n open={showCustomDateSelector}\n onClose={() => setShowCustomDateSelector(false)}\n sx={(theme) => ({ padding: theme.spacing(2) })}\n >\n <DateTimeRangePicker\n initialTimeRange={convertedTimeRange}\n onChange={(value: AbsoluteTimeRange) => {\n onChange(value);\n setShowCustomDateSelector(false);\n setOpen(false);\n }}\n onCancel={() => setShowCustomDateSelector(false)}\n timeZone={timeZone}\n />\n </Popover>\n <Box ref={setAnchorEl}>\n <Select\n open={open}\n value={formatTimeRange(value, timeZone)}\n onClick={() => setOpen(!open)}\n IconComponent={Calendar}\n renderValue={() => (\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <span>\n {timeOptions.find((opt) => formatTimeRange(opt.value, timeZone) === formatTimeRange(value, timeZone))\n ?.display ?? formatTimeRange(value, timeZone)}\n </span>\n {tzOffset !== localOffset && (\n <Box sx={{ typography: 'caption', color: 'text.secondary' }}>· {tzOffset}</Box>\n )}\n </Stack>\n )}\n inputProps={{ 'aria-label': `Select time range. Currently set to ${value}` }}\n sx={{\n '.MuiSelect-icon': { marginTop: '1px', transform: 'none' },\n '.MuiSelect-select.MuiSelect-outlined.MuiInputBase-input': { paddingRight: '36px' },\n '.MuiSelect-select': height ? { lineHeight: height, paddingY: 0 } : {},\n }}\n >\n <MenuItem\n disableRipple\n onClick={(e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n sx={{ cursor: 'default', '&:hover': { backgroundColor: 'transparent' }, py: 0.5, px: 1 }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', width: '100%', justifyContent: 'space-between' }}>\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>\n <Box sx={{ typography: 'subtitle1' }}>Time Range</Box>\n <Box sx={{ color: 'text.secondary', typography: 'caption', mt: 0.25 }}>Timezone: {tzLabel}</Box>\n </Box>\n <Box sx={{ display: 'flex', alignItems: 'center', pr: 1, ml: 1.5 }}>\n <IconButton\n size=\"small\"\n aria-label=\"Select timezone\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setTzAnchorEl(e.currentTarget);\n }}\n >\n <EarthIcon fontSize=\"small\" />\n </IconButton>\n </Box>\n </Box>\n </MenuItem>\n {timeOptions.map((item, idx) => (\n <MenuItem\n key={idx}\n value={formatTimeRange(item.value, timeZone)}\n onClick={() => {\n onChange(item.value);\n }}\n >\n {item.display}\n </MenuItem>\n ))}\n {showCustomTimeRange && (\n <MenuItem\n value={formatTimeRange(lastOption.value, timeZone)}\n onClick={() => setShowCustomDateSelector(true)}\n >\n {lastOption.display}\n </MenuItem>\n )}\n </Select>\n </Box>\n </>\n );\n}\n"],"names":["Box","MenuItem","Popover","Select","IconButton","TextField","Stack","isRelativeTimeRange","toAbsoluteTimeRange","Calendar","EarthIcon","useMemo","useState","useTimeZone","getTimeZoneOptions","SettingsAutocomplete","getGMTOffset","DateTimeRangePicker","buildCustomTimeOption","formatTimeRange","TimeRangeSelector","value","timeOptions","onChange","height","showCustomTimeRange","timeZone","timeZoneProp","timeZoneOptions","onTimeZoneChange","ctxTimeZone","anchorEl","setAnchorEl","showCustomDateSelector","setShowCustomDateSelector","convertedTimeRange","lastOption","undefined","open","setOpen","tzOptions","tzAnchorEl","setTzAnchorEl","tzOpen","Boolean","tzLabel","find","o","display","tzOffset","localOffset","tzAutocompleteOptions","map","id","label","tzAutocompleteValue","option","anchorOrigin","vertical","horizontal","transformOrigin","onClose","sx","theme","padding","spacing","p","minWidth","onClick","e","stopPropagation","options","_e","selected","disableClearable","renderInput","params","placeholder","size","initialTimeRange","onCancel","ref","IconComponent","renderValue","direction","alignItems","span","opt","typography","color","inputProps","marginTop","transform","paddingRight","lineHeight","paddingY","disableRipple","preventDefault","cursor","backgroundColor","py","px","width","justifyContent","flexDirection","mt","pr","ml","aria-label","currentTarget","fontSize","item","idx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeChartTooltip.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesTooltip/TimeChartTooltip.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAI9C,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeChartTooltip.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesTooltip/TimeChartTooltip.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAI9C,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IACxD,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,aAAa,EAAE,sBAAsB,CAAC;IACtC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB;;OAEG;IACH,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,qKAW1B,qBAAqB,oDA0FtB,CAAC"}
|
|
@@ -21,7 +21,7 @@ import { TooltipHeader } from "./TooltipHeader.js";
|
|
|
21
21
|
import { assembleTransform, getTooltipStyles } from "./utils.js";
|
|
22
22
|
export const TimeChartTooltip = /*#__PURE__*/ memo(function TimeChartTooltip({ containerId, chartRef, data, seriesMapping, enablePinning = true, wrapLabels, format, seriesFormatMap, onUnpinClick, pinnedPos }) {
|
|
23
23
|
const [showAllSeries, setShowAllSeries] = useState(false);
|
|
24
|
-
const
|
|
24
|
+
const [nearbySeries, setNearbySeries] = useState([]);
|
|
25
25
|
const tooltipElementRef = useRef(null);
|
|
26
26
|
const mousePos = useMousePosition();
|
|
27
27
|
const { height, width, ref: tooltipRef } = useResizeObserver();
|
|
@@ -34,6 +34,29 @@ export const TimeChartTooltip = /*#__PURE__*/ memo(function TimeChartTooltip({ c
|
|
|
34
34
|
tooltipRef
|
|
35
35
|
]);
|
|
36
36
|
const containerElement = containerId ? document.querySelector(containerId) : undefined;
|
|
37
|
+
// Chart reads and highlight actions synchronize with ECharts after commit.
|
|
38
|
+
useLayoutEffect(()=>{
|
|
39
|
+
const chart = chartRef.current;
|
|
40
|
+
setNearbySeries(getNearbySeriesData({
|
|
41
|
+
mousePos,
|
|
42
|
+
data,
|
|
43
|
+
seriesMapping,
|
|
44
|
+
pinnedPos,
|
|
45
|
+
chart,
|
|
46
|
+
format,
|
|
47
|
+
seriesFormatMap,
|
|
48
|
+
showAllSeries
|
|
49
|
+
}));
|
|
50
|
+
}, [
|
|
51
|
+
chartRef,
|
|
52
|
+
mousePos,
|
|
53
|
+
data,
|
|
54
|
+
seriesMapping,
|
|
55
|
+
pinnedPos,
|
|
56
|
+
format,
|
|
57
|
+
seriesFormatMap,
|
|
58
|
+
showAllSeries
|
|
59
|
+
]);
|
|
37
60
|
// Synchronously reposition after every render to prevent one-frame viewport overflow.
|
|
38
61
|
useLayoutEffect(()=>{
|
|
39
62
|
if (mousePos === null) return;
|
|
@@ -42,27 +65,15 @@ export const TimeChartTooltip = /*#__PURE__*/ memo(function TimeChartTooltip({ c
|
|
|
42
65
|
const rect = node.getBoundingClientRect();
|
|
43
66
|
if (rect.height === 0 || rect.width === 0) return;
|
|
44
67
|
const nextTransform = assembleTransform(mousePos, pinnedPos, rect.height, rect.width, containerElement);
|
|
45
|
-
if (nextTransform && nextTransform !== transform
|
|
46
|
-
transform.current = nextTransform;
|
|
68
|
+
if (nextTransform && nextTransform !== node.style.transform) {
|
|
47
69
|
node.style.transform = nextTransform;
|
|
48
70
|
}
|
|
49
71
|
});
|
|
50
72
|
if (mousePos === null || mousePos.target === null || data === null) return null;
|
|
51
73
|
if (pinnedPos === null && mousePos.target.tagName !== 'CANVAS') return null;
|
|
52
|
-
const chart = chartRef.current;
|
|
53
74
|
// Cap height to container so the tooltip is not cut off.
|
|
54
75
|
const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined;
|
|
55
|
-
transform
|
|
56
|
-
const nearbySeries = getNearbySeriesData({
|
|
57
|
-
mousePos,
|
|
58
|
-
data,
|
|
59
|
-
seriesMapping,
|
|
60
|
-
pinnedPos,
|
|
61
|
-
chart,
|
|
62
|
-
format,
|
|
63
|
-
seriesFormatMap,
|
|
64
|
-
showAllSeries
|
|
65
|
-
});
|
|
76
|
+
const transform = assembleTransform(mousePos, pinnedPos, height ?? 0, width ?? 0, containerElement);
|
|
66
77
|
if (nearbySeries.length === 0) {
|
|
67
78
|
return null;
|
|
68
79
|
}
|
|
@@ -73,7 +84,7 @@ export const TimeChartTooltip = /*#__PURE__*/ memo(function TimeChartTooltip({ c
|
|
|
73
84
|
ref: setTooltipRef,
|
|
74
85
|
sx: (theme)=>getTooltipStyles(theme, pinnedPos, maxHeight),
|
|
75
86
|
style: {
|
|
76
|
-
transform
|
|
87
|
+
transform
|
|
77
88
|
},
|
|
78
89
|
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
79
90
|
spacing: 0.5,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/TimeSeriesTooltip/TimeChartTooltip.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Portal, Stack } from '@mui/material';\nimport type { TimeSeries } from '@perses-dev/spec';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\nimport type { MutableRefObject } from 'react';\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport useResizeObserver from 'use-resize-observer';\n\nimport type { FormatOptions, TimeChartSeriesMapping } from '../model';\nimport { getNearbySeriesData } from './nearby-series';\nimport type { CursorCoordinates } from './tooltip-model';\nimport { useMousePosition } from './tooltip-model';\nimport { TooltipContent } from './TooltipContent';\nimport { TooltipHeader } from './TooltipHeader';\nimport { assembleTransform, getTooltipStyles } from './utils';\n\nexport interface TimeChartTooltipProps {\n chartRef: MutableRefObject<EChartsInstance | undefined>;\n data: TimeSeries[];\n seriesMapping: TimeChartSeriesMapping;\n enablePinning?: boolean;\n pinnedPos: CursorCoordinates | null;\n /**\n * The id of the container that will have the chart tooltip appended to it.\n * By default, the chart tooltip is attached to document.body.\n */\n containerId?: string;\n onUnpinClick?: () => void;\n format?: FormatOptions;\n /**\n * Map of series ID to format options for per-series formatting (used with multiple Y axes)\n */\n seriesFormatMap?: Map<string, FormatOptions>;\n wrapLabels?: boolean;\n}\n\nexport const TimeChartTooltip = memo(function TimeChartTooltip({\n containerId,\n chartRef,\n data,\n seriesMapping,\n enablePinning = true,\n wrapLabels,\n format,\n seriesFormatMap,\n onUnpinClick,\n pinnedPos,\n}: TimeChartTooltipProps) {\n const [showAllSeries, setShowAllSeries] = useState(false);\n const
|
|
1
|
+
{"version":3,"sources":["../../src/TimeSeriesTooltip/TimeChartTooltip.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Portal, Stack } from '@mui/material';\nimport type { TimeSeries } from '@perses-dev/spec';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\nimport type { MutableRefObject } from 'react';\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport useResizeObserver from 'use-resize-observer';\n\nimport type { FormatOptions, TimeChartSeriesMapping } from '../model';\nimport type { NearbySeriesArray } from './nearby-series';\nimport { getNearbySeriesData } from './nearby-series';\nimport type { CursorCoordinates } from './tooltip-model';\nimport { useMousePosition } from './tooltip-model';\nimport { TooltipContent } from './TooltipContent';\nimport { TooltipHeader } from './TooltipHeader';\nimport { assembleTransform, getTooltipStyles } from './utils';\n\nexport interface TimeChartTooltipProps {\n chartRef: MutableRefObject<EChartsInstance | undefined>;\n data: TimeSeries[];\n seriesMapping: TimeChartSeriesMapping;\n enablePinning?: boolean;\n pinnedPos: CursorCoordinates | null;\n /**\n * The id of the container that will have the chart tooltip appended to it.\n * By default, the chart tooltip is attached to document.body.\n */\n containerId?: string;\n onUnpinClick?: () => void;\n format?: FormatOptions;\n /**\n * Map of series ID to format options for per-series formatting (used with multiple Y axes)\n */\n seriesFormatMap?: Map<string, FormatOptions>;\n wrapLabels?: boolean;\n}\n\nexport const TimeChartTooltip = memo(function TimeChartTooltip({\n containerId,\n chartRef,\n data,\n seriesMapping,\n enablePinning = true,\n wrapLabels,\n format,\n seriesFormatMap,\n onUnpinClick,\n pinnedPos,\n}: TimeChartTooltipProps) {\n const [showAllSeries, setShowAllSeries] = useState(false);\n const [nearbySeries, setNearbySeries] = useState<NearbySeriesArray>([]);\n const tooltipElementRef = useRef<HTMLDivElement | null>(null);\n\n const mousePos = useMousePosition();\n const { height, width, ref: tooltipRef } = useResizeObserver();\n\n const isTooltipPinned = pinnedPos !== null && enablePinning;\n\n // Stable callback — prevents the ResizeObserver from disconnecting/reconnecting on every render.\n const setTooltipRef = useCallback(\n (node: HTMLDivElement | null): void => {\n tooltipElementRef.current = node;\n tooltipRef(node);\n },\n [tooltipRef],\n );\n\n const containerElement = containerId ? document.querySelector(containerId) : undefined;\n\n // Chart reads and highlight actions synchronize with ECharts after commit.\n useLayoutEffect(() => {\n const chart = chartRef.current;\n setNearbySeries(\n getNearbySeriesData({\n mousePos,\n data,\n seriesMapping,\n pinnedPos,\n chart,\n format,\n seriesFormatMap,\n showAllSeries,\n }),\n );\n }, [chartRef, mousePos, data, seriesMapping, pinnedPos, format, seriesFormatMap, showAllSeries]);\n\n // Synchronously reposition after every render to prevent one-frame viewport overflow.\n useLayoutEffect(() => {\n if (mousePos === null) return;\n const node = tooltipElementRef.current;\n if (!node) return;\n const rect = node.getBoundingClientRect();\n if (rect.height === 0 || rect.width === 0) return;\n const nextTransform = assembleTransform(mousePos, pinnedPos, rect.height, rect.width, containerElement);\n if (nextTransform && nextTransform !== node.style.transform) {\n node.style.transform = nextTransform;\n }\n });\n\n if (mousePos === null || mousePos.target === null || data === null) return null;\n\n if (pinnedPos === null && (mousePos.target as HTMLElement).tagName !== 'CANVAS') return null;\n\n // Cap height to container so the tooltip is not cut off.\n const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined;\n\n const transform = assembleTransform(mousePos, pinnedPos, height ?? 0, width ?? 0, containerElement);\n\n if (nearbySeries.length === 0) {\n return null;\n }\n\n const totalSeries = data.length;\n\n return (\n <Portal container={containerElement}>\n <Box\n ref={setTooltipRef}\n sx={(theme) => getTooltipStyles(theme, pinnedPos, maxHeight)}\n style={{\n transform,\n }}\n >\n <Stack spacing={0.5}>\n <TooltipHeader\n nearbySeries={nearbySeries}\n totalSeries={totalSeries}\n enablePinning={enablePinning}\n isTooltipPinned={isTooltipPinned}\n showAllSeries={showAllSeries}\n onShowAllClick={(checked) => setShowAllSeries(checked)}\n onUnpinClick={onUnpinClick}\n />\n <TooltipContent series={nearbySeries} wrapLabels={wrapLabels} />\n </Stack>\n </Box>\n </Portal>\n );\n});\n"],"names":["Box","Portal","Stack","memo","useCallback","useLayoutEffect","useRef","useState","useResizeObserver","getNearbySeriesData","useMousePosition","TooltipContent","TooltipHeader","assembleTransform","getTooltipStyles","TimeChartTooltip","containerId","chartRef","data","seriesMapping","enablePinning","wrapLabels","format","seriesFormatMap","onUnpinClick","pinnedPos","showAllSeries","setShowAllSeries","nearbySeries","setNearbySeries","tooltipElementRef","mousePos","height","width","ref","tooltipRef","isTooltipPinned","setTooltipRef","node","current","containerElement","document","querySelector","undefined","chart","rect","getBoundingClientRect","nextTransform","style","transform","target","tagName","maxHeight","length","totalSeries","container","sx","theme","spacing","onShowAllClick","checked","series"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesTooltip/utils.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AASrE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,EAC9B,SAAS,EAAE,iBAAiB,GAAG,IAAI,EACnC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,GAChC,MAAM,GAAG,SAAS,CAuDpB;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesTooltip/utils.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AASrE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,EAC9B,SAAS,EAAE,iBAAiB,GAAG,IAAI,EACnC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,GAChC,MAAM,GAAG,SAAS,CAuDpB;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,iBAAiB,GAAG,IAAI,EACnC,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBzB;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAO1F;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,sBAAsB,EACrC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAcR;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CAiCnH;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQjC;AAED,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,eAAe,GACrB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAexC"}
|
|
@@ -58,6 +58,11 @@ import { TOOLTIP_MAX_WIDTH, TOOLTIP_MAX_HEIGHT, TOOLTIP_MIN_WIDTH, TOOLTIP_BG_CO
|
|
|
58
58
|
}
|
|
59
59
|
return `translate3d(${x}px, ${y}px, 0)`;
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Stacking level of a pinned tooltip. It must cover the table legend's sticky header, which
|
|
63
|
+
* react-virtuoso renders at z-index 2, and stay below PanelHeader (5, in @perses-dev/dashboards),
|
|
64
|
+
* the drawer and the sticky dashboard header.
|
|
65
|
+
*/ const PINNED_TOOLTIP_Z_INDEX = 3;
|
|
61
66
|
/**
|
|
62
67
|
* Helper for tooltip positioning styles
|
|
63
68
|
*/ export function getTooltipStyles(theme, pinnedPos, maxHeight) {
|
|
@@ -78,8 +83,7 @@ import { TOOLTIP_MAX_WIDTH, TOOLTIP_MAX_HEIGHT, TOOLTIP_MIN_WIDTH, TOOLTIP_BG_CO
|
|
|
78
83
|
opacity: 1,
|
|
79
84
|
// Animating transform causes intermediate positions outside the viewport; animate opacity/visibility instead.
|
|
80
85
|
transition: 'opacity 0.1s ease-out, visibility 0.1s ease-out',
|
|
81
|
-
|
|
82
|
-
zIndex: pinnedPos !== null ? 'auto' : theme.zIndex.tooltip,
|
|
86
|
+
zIndex: pinnedPos !== null ? PINNED_TOOLTIP_Z_INDEX : theme.zIndex.tooltip,
|
|
83
87
|
overflow: 'hidden',
|
|
84
88
|
'&:hover': {
|
|
85
89
|
overflowY: 'auto'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/TimeSeriesTooltip/utils.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { Theme } from '@mui/material';\nimport type { BarSeriesOption, LineSeriesOption } from 'echarts/charts';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\n\nimport type { TimeChartSeriesMapping } from '../model';\nimport type { CursorCoordinates, CursorData } from './tooltip-model';\nimport {\n TOOLTIP_MAX_WIDTH,\n TOOLTIP_MAX_HEIGHT,\n TOOLTIP_MIN_WIDTH,\n TOOLTIP_BG_COLOR_FALLBACK,\n TOOLTIP_PADDING,\n} from './tooltip-model';\n\n/**\n * Determine position of tooltip depending on chart dimensions and the number of focused series.\n */\nexport function assembleTransform(\n mousePos: CursorData['coords'],\n pinnedPos: CursorCoordinates | null,\n tooltipHeight: number,\n tooltipWidth: number,\n containerElement?: Element | null,\n): string | undefined {\n if (mousePos === null) {\n return undefined;\n }\n\n const cursorPaddingX = 32;\n const cursorPaddingY = 16;\n\n if (pinnedPos !== null) {\n mousePos = pinnedPos;\n }\n\n if (mousePos.plotCanvas.x === undefined) return undefined;\n\n // Fall back to max size before the resize observer reports a real measurement.\n const effectiveHeight = tooltipHeight > 0 ? tooltipHeight : TOOLTIP_MAX_HEIGHT;\n const effectiveWidth = tooltipWidth > 0 ? tooltipWidth : TOOLTIP_MAX_WIDTH;\n\n let x = mousePos.page.x + cursorPaddingX; // Default to right side of the cursor\n let y = mousePos.page.y + cursorPaddingY;\n\n // If containerElement is defined, adjust coordinates relative to the container\n if (containerElement) {\n const containerRect = containerElement.getBoundingClientRect();\n x = x - containerRect.left + containerElement.scrollLeft;\n y = y - containerRect.top + containerElement.scrollTop;\n\n // Ensure tooltip does not go out of the container's bottom\n const containerBottom = containerRect.top + containerElement.scrollHeight;\n if (y + effectiveHeight > containerBottom) {\n y = Math.max(containerBottom - effectiveHeight - cursorPaddingY, TOOLTIP_PADDING / 2);\n }\n } else {\n // Ensure tooltip does not go out of the screen on the bottom\n if (y + effectiveHeight > window.innerHeight + window.scrollY) {\n y = Math.max(window.innerHeight + window.scrollY - effectiveHeight - cursorPaddingY, TOOLTIP_PADDING / 2);\n }\n }\n\n // Ensure tooltip does not go out of the screen on the right\n if (x + effectiveWidth > window.innerWidth) {\n x = mousePos.page.x - effectiveWidth - cursorPaddingX; // Move to the left of the cursor\n }\n\n // Ensure tooltip does not go out of the screen on the left\n if (x < cursorPaddingX) {\n x = cursorPaddingX;\n }\n\n // Ensure tooltip does not go out of the screen on the top\n if (y < TOOLTIP_PADDING / 2) {\n y = TOOLTIP_PADDING / 2;\n }\n\n return `translate3d(${x}px, ${y}px, 0)`;\n}\n\n/**\n * Helper for tooltip positioning styles\n */\nexport function getTooltipStyles(\n theme: Theme,\n pinnedPos: CursorCoordinates | null,\n maxHeight?: number,\n): Record<string, unknown> {\n const adjustedMaxHeight = maxHeight ? maxHeight - TOOLTIP_PADDING : undefined;\n return {\n minWidth: TOOLTIP_MIN_WIDTH,\n maxWidth: TOOLTIP_MAX_WIDTH,\n maxHeight: adjustedMaxHeight ?? TOOLTIP_MAX_HEIGHT,\n padding: 0,\n position: 'absolute',\n top: 0,\n left: 0,\n backgroundColor: theme.palette.designSystem?.grey[800] ?? TOOLTIP_BG_COLOR_FALLBACK,\n borderRadius: '6px',\n color: '#fff',\n fontSize: '11px',\n visibility: 'visible',\n opacity: 1,\n // Animating transform causes intermediate positions outside the viewport; animate opacity/visibility instead.\n transition: 'opacity 0.1s ease-out, visibility 0.1s ease-out',\n // Pinned tooltip should not float above the drawer/sticky header.\n zIndex: pinnedPos !== null ? 'auto' : theme.zIndex.tooltip,\n overflow: 'hidden',\n '&:hover': {\n overflowY: 'auto',\n },\n };\n}\n\nexport function getPixelXFromGrid(timestamp: number, chart: EChartsInstance): number | null {\n try {\n const pixelCoords = chart.convertToPixel('grid', [timestamp, 0]);\n return pixelCoords?.[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns the cumulative (visual) Y for a series, accumulating stack totals in-place.\n * For non-stacked series, returns the raw yValue unchanged.\n * Mutates `stackTotals` — pass a fresh Map for each cursor evaluation.\n */\nexport function calculateVisualYForSeries(\n seriesIdx: number,\n yValue: number,\n seriesMapping: TimeChartSeriesMapping,\n stackTotals: Map<string, number>,\n): number {\n const currentSeries = seriesMapping[seriesIdx];\n if (!currentSeries) return yValue;\n\n const stackId = (currentSeries as LineSeriesOption | BarSeriesOption).stack;\n if (!stackId) {\n return yValue;\n }\n\n const stackIdStr = stackId.toString();\n const currentTotal = stackTotals.get(stackIdStr) ?? 0;\n const newTotal = currentTotal + yValue;\n stackTotals.set(stackIdStr, newTotal);\n return newTotal;\n}\n\nexport function calculateBarBandwidth(timestamp: number, sortedTimestamps: number[], chart: EChartsInstance): number {\n const currentIdx = sortedTimestamps.indexOf(timestamp);\n if (currentIdx === -1) {\n return 20;\n }\n\n const prevTimestamp = currentIdx > 0 ? (sortedTimestamps[currentIdx - 1] ?? null) : null;\n const nextTimestamp = currentIdx < sortedTimestamps.length - 1 ? (sortedTimestamps[currentIdx + 1] ?? null) : null;\n\n const currentPixelX = getPixelXFromGrid(timestamp, chart);\n if (currentPixelX === null) return 20;\n\n let leftBound: number;\n let rightBound: number;\n\n if (prevTimestamp !== null && nextTimestamp !== null) {\n const prevPixelX = getPixelXFromGrid(prevTimestamp, chart) ?? currentPixelX;\n const nextPixelX = getPixelXFromGrid(nextTimestamp, chart) ?? currentPixelX;\n leftBound = (currentPixelX + prevPixelX) / 2;\n rightBound = (currentPixelX + nextPixelX) / 2;\n } else if (prevTimestamp !== null) {\n const prevPixelX = getPixelXFromGrid(prevTimestamp, chart) ?? currentPixelX;\n leftBound = (currentPixelX + prevPixelX) / 2;\n rightBound = currentPixelX + (currentPixelX - leftBound);\n } else if (nextTimestamp !== null) {\n const nextPixelX = getPixelXFromGrid(nextTimestamp, chart) ?? currentPixelX;\n rightBound = (currentPixelX + nextPixelX) / 2;\n leftBound = currentPixelX - (rightBound - currentPixelX);\n } else {\n return 20;\n }\n\n return Math.max(1, rightBound - leftBound);\n}\n\n/**\n * Computes the pixel left/right bounds of one bar segment within a group.\n * @param barRelativeIdx - zero-based index among bar-only series\n * @param bandwidth - total pixel width for the bar group\n * @param centerPixelX - pixel X of the bar group centre\n * @param barCount - total bar series count (lines excluded)\n */\nexport function calculateBarSegmentBounds(\n barRelativeIdx: number,\n bandwidth: number,\n centerPixelX: number,\n barCount: number,\n): { left: number; right: number } {\n const count = Math.max(1, barCount);\n const segmentWidth = bandwidth / count;\n const segmentLeft = centerPixelX - bandwidth / 2 + barRelativeIdx * segmentWidth;\n return {\n left: segmentLeft,\n right: segmentLeft + segmentWidth,\n };\n}\n\nexport function calculateBarYBounds(\n visualYBottom: number,\n visualYTop: number,\n chart: EChartsInstance,\n): { top: number; bottom: number } | null {\n try {\n const bottomPixel = chart.convertToPixel('grid', [0, visualYBottom]);\n const topPixel = chart.convertToPixel('grid', [0, visualYTop]);\n\n if (!bottomPixel || !topPixel || bottomPixel[1] === undefined || topPixel[1] === undefined) return null;\n\n // Y increases downward in pixels; min/max normalizes the mapping for negative bar values.\n return {\n top: Math.min(topPixel[1], bottomPixel[1]),\n bottom: Math.max(topPixel[1], bottomPixel[1]),\n };\n } catch {\n return null;\n }\n}\n"],"names":["TOOLTIP_MAX_WIDTH","TOOLTIP_MAX_HEIGHT","TOOLTIP_MIN_WIDTH","TOOLTIP_BG_COLOR_FALLBACK","TOOLTIP_PADDING","assembleTransform","mousePos","pinnedPos","tooltipHeight","tooltipWidth","containerElement","undefined","cursorPaddingX","cursorPaddingY","plotCanvas","x","effectiveHeight","effectiveWidth","page","y","containerRect","getBoundingClientRect","left","scrollLeft","top","scrollTop","containerBottom","scrollHeight","Math","max","window","innerHeight","scrollY","innerWidth","getTooltipStyles","theme","maxHeight","adjustedMaxHeight","minWidth","maxWidth","padding","position","backgroundColor","palette","designSystem","grey","borderRadius","color","fontSize","visibility","opacity","transition","zIndex","tooltip","overflow","overflowY","getPixelXFromGrid","timestamp","chart","pixelCoords","convertToPixel","calculateVisualYForSeries","seriesIdx","yValue","seriesMapping","stackTotals","currentSeries","stackId","stack","stackIdStr","toString","currentTotal","get","newTotal","set","calculateBarBandwidth","sortedTimestamps","currentIdx","indexOf","prevTimestamp","nextTimestamp","length","currentPixelX","leftBound","rightBound","prevPixelX","nextPixelX","calculateBarSegmentBounds","barRelativeIdx","bandwidth","centerPixelX","barCount","count","segmentWidth","segmentLeft","right","calculateBarYBounds","visualYBottom","visualYTop","bottomPixel","topPixel","min","bottom"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/TimeSeriesTooltip/utils.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { Theme } from '@mui/material';\nimport type { BarSeriesOption, LineSeriesOption } from 'echarts/charts';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\n\nimport type { TimeChartSeriesMapping } from '../model';\nimport type { CursorCoordinates, CursorData } from './tooltip-model';\nimport {\n TOOLTIP_MAX_WIDTH,\n TOOLTIP_MAX_HEIGHT,\n TOOLTIP_MIN_WIDTH,\n TOOLTIP_BG_COLOR_FALLBACK,\n TOOLTIP_PADDING,\n} from './tooltip-model';\n\n/**\n * Determine position of tooltip depending on chart dimensions and the number of focused series.\n */\nexport function assembleTransform(\n mousePos: CursorData['coords'],\n pinnedPos: CursorCoordinates | null,\n tooltipHeight: number,\n tooltipWidth: number,\n containerElement?: Element | null,\n): string | undefined {\n if (mousePos === null) {\n return undefined;\n }\n\n const cursorPaddingX = 32;\n const cursorPaddingY = 16;\n\n if (pinnedPos !== null) {\n mousePos = pinnedPos;\n }\n\n if (mousePos.plotCanvas.x === undefined) return undefined;\n\n // Fall back to max size before the resize observer reports a real measurement.\n const effectiveHeight = tooltipHeight > 0 ? tooltipHeight : TOOLTIP_MAX_HEIGHT;\n const effectiveWidth = tooltipWidth > 0 ? tooltipWidth : TOOLTIP_MAX_WIDTH;\n\n let x = mousePos.page.x + cursorPaddingX; // Default to right side of the cursor\n let y = mousePos.page.y + cursorPaddingY;\n\n // If containerElement is defined, adjust coordinates relative to the container\n if (containerElement) {\n const containerRect = containerElement.getBoundingClientRect();\n x = x - containerRect.left + containerElement.scrollLeft;\n y = y - containerRect.top + containerElement.scrollTop;\n\n // Ensure tooltip does not go out of the container's bottom\n const containerBottom = containerRect.top + containerElement.scrollHeight;\n if (y + effectiveHeight > containerBottom) {\n y = Math.max(containerBottom - effectiveHeight - cursorPaddingY, TOOLTIP_PADDING / 2);\n }\n } else {\n // Ensure tooltip does not go out of the screen on the bottom\n if (y + effectiveHeight > window.innerHeight + window.scrollY) {\n y = Math.max(window.innerHeight + window.scrollY - effectiveHeight - cursorPaddingY, TOOLTIP_PADDING / 2);\n }\n }\n\n // Ensure tooltip does not go out of the screen on the right\n if (x + effectiveWidth > window.innerWidth) {\n x = mousePos.page.x - effectiveWidth - cursorPaddingX; // Move to the left of the cursor\n }\n\n // Ensure tooltip does not go out of the screen on the left\n if (x < cursorPaddingX) {\n x = cursorPaddingX;\n }\n\n // Ensure tooltip does not go out of the screen on the top\n if (y < TOOLTIP_PADDING / 2) {\n y = TOOLTIP_PADDING / 2;\n }\n\n return `translate3d(${x}px, ${y}px, 0)`;\n}\n\n/**\n * Stacking level of a pinned tooltip. It must cover the table legend's sticky header, which\n * react-virtuoso renders at z-index 2, and stay below PanelHeader (5, in @perses-dev/dashboards),\n * the drawer and the sticky dashboard header.\n */\nconst PINNED_TOOLTIP_Z_INDEX = 3;\n\n/**\n * Helper for tooltip positioning styles\n */\nexport function getTooltipStyles(\n theme: Theme,\n pinnedPos: CursorCoordinates | null,\n maxHeight?: number,\n): Record<string, unknown> {\n const adjustedMaxHeight = maxHeight ? maxHeight - TOOLTIP_PADDING : undefined;\n return {\n minWidth: TOOLTIP_MIN_WIDTH,\n maxWidth: TOOLTIP_MAX_WIDTH,\n maxHeight: adjustedMaxHeight ?? TOOLTIP_MAX_HEIGHT,\n padding: 0,\n position: 'absolute',\n top: 0,\n left: 0,\n backgroundColor: theme.palette.designSystem?.grey[800] ?? TOOLTIP_BG_COLOR_FALLBACK,\n borderRadius: '6px',\n color: '#fff',\n fontSize: '11px',\n visibility: 'visible',\n opacity: 1,\n // Animating transform causes intermediate positions outside the viewport; animate opacity/visibility instead.\n transition: 'opacity 0.1s ease-out, visibility 0.1s ease-out',\n zIndex: pinnedPos !== null ? PINNED_TOOLTIP_Z_INDEX : theme.zIndex.tooltip,\n overflow: 'hidden',\n '&:hover': {\n overflowY: 'auto',\n },\n };\n}\n\nexport function getPixelXFromGrid(timestamp: number, chart: EChartsInstance): number | null {\n try {\n const pixelCoords = chart.convertToPixel('grid', [timestamp, 0]);\n return pixelCoords?.[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns the cumulative (visual) Y for a series, accumulating stack totals in-place.\n * For non-stacked series, returns the raw yValue unchanged.\n * Mutates `stackTotals` — pass a fresh Map for each cursor evaluation.\n */\nexport function calculateVisualYForSeries(\n seriesIdx: number,\n yValue: number,\n seriesMapping: TimeChartSeriesMapping,\n stackTotals: Map<string, number>,\n): number {\n const currentSeries = seriesMapping[seriesIdx];\n if (!currentSeries) return yValue;\n\n const stackId = (currentSeries as LineSeriesOption | BarSeriesOption).stack;\n if (!stackId) {\n return yValue;\n }\n\n const stackIdStr = stackId.toString();\n const currentTotal = stackTotals.get(stackIdStr) ?? 0;\n const newTotal = currentTotal + yValue;\n stackTotals.set(stackIdStr, newTotal);\n return newTotal;\n}\n\nexport function calculateBarBandwidth(timestamp: number, sortedTimestamps: number[], chart: EChartsInstance): number {\n const currentIdx = sortedTimestamps.indexOf(timestamp);\n if (currentIdx === -1) {\n return 20;\n }\n\n const prevTimestamp = currentIdx > 0 ? (sortedTimestamps[currentIdx - 1] ?? null) : null;\n const nextTimestamp = currentIdx < sortedTimestamps.length - 1 ? (sortedTimestamps[currentIdx + 1] ?? null) : null;\n\n const currentPixelX = getPixelXFromGrid(timestamp, chart);\n if (currentPixelX === null) return 20;\n\n let leftBound: number;\n let rightBound: number;\n\n if (prevTimestamp !== null && nextTimestamp !== null) {\n const prevPixelX = getPixelXFromGrid(prevTimestamp, chart) ?? currentPixelX;\n const nextPixelX = getPixelXFromGrid(nextTimestamp, chart) ?? currentPixelX;\n leftBound = (currentPixelX + prevPixelX) / 2;\n rightBound = (currentPixelX + nextPixelX) / 2;\n } else if (prevTimestamp !== null) {\n const prevPixelX = getPixelXFromGrid(prevTimestamp, chart) ?? currentPixelX;\n leftBound = (currentPixelX + prevPixelX) / 2;\n rightBound = currentPixelX + (currentPixelX - leftBound);\n } else if (nextTimestamp !== null) {\n const nextPixelX = getPixelXFromGrid(nextTimestamp, chart) ?? currentPixelX;\n rightBound = (currentPixelX + nextPixelX) / 2;\n leftBound = currentPixelX - (rightBound - currentPixelX);\n } else {\n return 20;\n }\n\n return Math.max(1, rightBound - leftBound);\n}\n\n/**\n * Computes the pixel left/right bounds of one bar segment within a group.\n * @param barRelativeIdx - zero-based index among bar-only series\n * @param bandwidth - total pixel width for the bar group\n * @param centerPixelX - pixel X of the bar group centre\n * @param barCount - total bar series count (lines excluded)\n */\nexport function calculateBarSegmentBounds(\n barRelativeIdx: number,\n bandwidth: number,\n centerPixelX: number,\n barCount: number,\n): { left: number; right: number } {\n const count = Math.max(1, barCount);\n const segmentWidth = bandwidth / count;\n const segmentLeft = centerPixelX - bandwidth / 2 + barRelativeIdx * segmentWidth;\n return {\n left: segmentLeft,\n right: segmentLeft + segmentWidth,\n };\n}\n\nexport function calculateBarYBounds(\n visualYBottom: number,\n visualYTop: number,\n chart: EChartsInstance,\n): { top: number; bottom: number } | null {\n try {\n const bottomPixel = chart.convertToPixel('grid', [0, visualYBottom]);\n const topPixel = chart.convertToPixel('grid', [0, visualYTop]);\n\n if (!bottomPixel || !topPixel || bottomPixel[1] === undefined || topPixel[1] === undefined) return null;\n\n // Y increases downward in pixels; min/max normalizes the mapping for negative bar values.\n return {\n top: Math.min(topPixel[1], bottomPixel[1]),\n bottom: Math.max(topPixel[1], bottomPixel[1]),\n };\n } catch {\n return null;\n }\n}\n"],"names":["TOOLTIP_MAX_WIDTH","TOOLTIP_MAX_HEIGHT","TOOLTIP_MIN_WIDTH","TOOLTIP_BG_COLOR_FALLBACK","TOOLTIP_PADDING","assembleTransform","mousePos","pinnedPos","tooltipHeight","tooltipWidth","containerElement","undefined","cursorPaddingX","cursorPaddingY","plotCanvas","x","effectiveHeight","effectiveWidth","page","y","containerRect","getBoundingClientRect","left","scrollLeft","top","scrollTop","containerBottom","scrollHeight","Math","max","window","innerHeight","scrollY","innerWidth","PINNED_TOOLTIP_Z_INDEX","getTooltipStyles","theme","maxHeight","adjustedMaxHeight","minWidth","maxWidth","padding","position","backgroundColor","palette","designSystem","grey","borderRadius","color","fontSize","visibility","opacity","transition","zIndex","tooltip","overflow","overflowY","getPixelXFromGrid","timestamp","chart","pixelCoords","convertToPixel","calculateVisualYForSeries","seriesIdx","yValue","seriesMapping","stackTotals","currentSeries","stackId","stack","stackIdStr","toString","currentTotal","get","newTotal","set","calculateBarBandwidth","sortedTimestamps","currentIdx","indexOf","prevTimestamp","nextTimestamp","length","currentPixelX","leftBound","rightBound","prevPixelX","nextPixelX","calculateBarSegmentBounds","barRelativeIdx","bandwidth","centerPixelX","barCount","count","segmentWidth","segmentLeft","right","calculateBarYBounds","visualYBottom","visualYTop","bottomPixel","topPixel","min","bottom"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransformEditor.d.ts","sourceRoot":"","sources":["../../src/TransformsEditor/TransformEditor.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TransformEditor.d.ts","sourceRoot":"","sources":["../../src/TransformsEditor/TransformEditor.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAMV,SAAS,EACV,MAAM,UAAU,CAAC;AAiLlB,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;IAC/F,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CAC1C;AAED,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,oBAAoB,GAAG,YAAY,CA+CjG"}
|
|
@@ -263,6 +263,20 @@ export function TransformEditor({ value, onChange, ...props }) {
|
|
|
263
263
|
})
|
|
264
264
|
]
|
|
265
265
|
})
|
|
266
|
+
}),
|
|
267
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
268
|
+
value: "PivotByLabel",
|
|
269
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
270
|
+
children: [
|
|
271
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
272
|
+
children: "Pivot by label"
|
|
273
|
+
}),
|
|
274
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
275
|
+
variant: "caption",
|
|
276
|
+
children: "Time × label matrix (rows = time, columns = label values)"
|
|
277
|
+
})
|
|
278
|
+
]
|
|
279
|
+
})
|
|
266
280
|
})
|
|
267
281
|
]
|
|
268
282
|
}),
|
|
@@ -281,6 +295,81 @@ export function TransformEditor({ value, onChange, ...props }) {
|
|
|
281
295
|
value.kind === 'MergeSeries' && /*#__PURE__*/ _jsx(MergeSeriesTransformEditor, {
|
|
282
296
|
value: value,
|
|
283
297
|
onChange: onChange
|
|
298
|
+
}),
|
|
299
|
+
value.kind === 'PivotByLabel' && /*#__PURE__*/ _jsx(PivotByLabelTransformEditor, {
|
|
300
|
+
value: value,
|
|
301
|
+
onChange: onChange
|
|
302
|
+
})
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function PivotByLabelTransformEditor({ value, onChange }) {
|
|
307
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
308
|
+
gap: 2,
|
|
309
|
+
children: [
|
|
310
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
311
|
+
label: "Column label",
|
|
312
|
+
fullWidth: true,
|
|
313
|
+
value: value.spec.columnLabel ?? '',
|
|
314
|
+
onChange: (e)=>onChange({
|
|
315
|
+
...value,
|
|
316
|
+
spec: {
|
|
317
|
+
...value.spec,
|
|
318
|
+
columnLabel: e.target.value
|
|
319
|
+
}
|
|
320
|
+
}),
|
|
321
|
+
helperText: "Label that becomes dynamic column headers (e.g. farm_short)"
|
|
322
|
+
}),
|
|
323
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
324
|
+
label: "Row field",
|
|
325
|
+
fullWidth: true,
|
|
326
|
+
value: value.spec.rowField ?? 'timestamp',
|
|
327
|
+
onChange: (e)=>onChange({
|
|
328
|
+
...value,
|
|
329
|
+
spec: {
|
|
330
|
+
...value.spec,
|
|
331
|
+
rowField: e.target.value
|
|
332
|
+
}
|
|
333
|
+
}),
|
|
334
|
+
helperText: "Field used for row identity (default: timestamp)"
|
|
335
|
+
}),
|
|
336
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
337
|
+
label: "Value field",
|
|
338
|
+
fullWidth: true,
|
|
339
|
+
value: value.spec.valueField ?? 'value',
|
|
340
|
+
onChange: (e)=>onChange({
|
|
341
|
+
...value,
|
|
342
|
+
spec: {
|
|
343
|
+
...value.spec,
|
|
344
|
+
valueField: e.target.value
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
}),
|
|
348
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
349
|
+
label: "Row column name",
|
|
350
|
+
fullWidth: true,
|
|
351
|
+
value: value.spec.rowColumnName ?? '',
|
|
352
|
+
onChange: (e)=>onChange({
|
|
353
|
+
...value,
|
|
354
|
+
spec: {
|
|
355
|
+
...value.spec,
|
|
356
|
+
rowColumnName: e.target.value || undefined
|
|
357
|
+
}
|
|
358
|
+
}),
|
|
359
|
+
helperText: "Optional display name for the row column (default: row field)"
|
|
360
|
+
}),
|
|
361
|
+
/*#__PURE__*/ _jsx(FormControlLabel, {
|
|
362
|
+
control: /*#__PURE__*/ _jsx(Switch, {
|
|
363
|
+
checked: !!value.spec.disabled,
|
|
364
|
+
onChange: (_, checked)=>onChange({
|
|
365
|
+
...value,
|
|
366
|
+
spec: {
|
|
367
|
+
...value.spec,
|
|
368
|
+
disabled: checked
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
}),
|
|
372
|
+
label: "Disabled"
|
|
284
373
|
})
|
|
285
374
|
]
|
|
286
375
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/TransformsEditor/TransformEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { StackProps } from '@mui/material';\nimport {\n Autocomplete,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n Typography,\n TextField as MuiTextField,\n} from '@mui/material';\nimport type { ReactElement } from 'react';\n\nimport { TextField } from '../controls';\nimport type {\n JoinByColumnValueTransform,\n MergeColumnsTransform,\n MergeIndexedColumnsTransform,\n MergeSeriesTransform,\n Transform,\n} from '../model';\n\ninterface TransformSpecEditorProps<Spec> {\n value: Spec;\n onChange: (transform: Spec) => void;\n}\n\nfunction JoinByColumnValueTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<JoinByColumnValueTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <Autocomplete\n freeSolo\n multiple\n id=\"join-columns\"\n sx={{ width: '100%' }}\n options={[]} // TODO: autofill columns name when query results is available to panel editors\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\" gap={1} alignItems=\"center\">\n <Autocomplete\n freeSolo\n multiple\n id=\"merge-columns-columns\"\n sx={{ width: '100%' }}\n options={[]}\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n\n <TextField\n id=\"merge-columns-name\"\n variant=\"outlined\"\n label=\"Output Name\"\n value={value.spec.name ?? ''}\n sx={{ width: '100%' }}\n onChange={(name) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n name: name,\n },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeIndexedColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeIndexedColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <TextField\n id=\"merge-indexed-columns\"\n variant=\"outlined\"\n label=\"Column\"\n placeholder=\"Example: 'value' for merging 'value #1', 'value #2' and 'value #...'\"\n value={value.spec.column ?? ''}\n sx={{ width: '100%' }}\n onChange={(column) => {\n onChange({\n ...value,\n spec: { ...value.spec, column: column },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeSeriesTransformEditor({ value, onChange }: TransformSpecEditorProps<MergeSeriesTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nexport interface TransformEditorProps extends Omit<StackProps, 'children' | 'value' | 'onChange'> {\n value: Transform;\n onChange: (transform: Transform) => void;\n}\n\nexport function TransformEditor({ value, onChange, ...props }: TransformEditorProps): ReactElement {\n return (\n <Stack gap={2} sx={{ width: '100%' }} mt={1} {...props}>\n <TextField\n select\n label=\"Kind\"\n value={value.kind}\n onChange={(kind) => onChange({ ...value, kind: kind as unknown as Transform['kind'] } as Transform)}\n >\n <MenuItem value=\"JoinByColumnValue\">\n <Stack>\n <Typography>Join by column value</Typography>\n <Typography variant=\"caption\">Regroup rows with equal cell value in a column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeColumns\">\n <Stack>\n <Typography>Merge columns</Typography>\n <Typography variant=\"caption\">Multiple columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeIndexedColumns\">\n <Stack>\n <Typography>Merge indexed columns</Typography>\n <Typography variant=\"caption\">Indexed columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeSeries\">\n <Stack>\n <Typography>Merge series</Typography>\n <Typography variant=\"caption\">Series will be merged by their labels</Typography>\n </Stack>\n </MenuItem>\n </TextField>\n {value.kind === 'JoinByColumnValue' && <JoinByColumnValueTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeColumns' && <MergeColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeIndexedColumns' && <MergeIndexedColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeSeries' && <MergeSeriesTransformEditor value={value} onChange={onChange} />}\n </Stack>\n );\n}\n"],"names":["Autocomplete","FormControlLabel","MenuItem","Stack","Switch","Typography","TextField","MuiTextField","JoinByColumnValueTransformEditor","value","onChange","direction","freeSolo","multiple","id","sx","width","options","spec","columns","renderInput","params","variant","label","required","_","labelPlacement","control","disabled","checked","e","target","MergeColumnsTransformEditor","gap","alignItems","name","MergeIndexedColumnsTransformEditor","placeholder","column","MergeSeriesTransformEditor","TransformEditor","props","mt","select","kind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/TransformsEditor/TransformEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { StackProps } from '@mui/material';\nimport {\n Autocomplete,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n Typography,\n TextField as MuiTextField,\n} from '@mui/material';\nimport type { ReactElement } from 'react';\n\nimport { TextField } from '../controls';\nimport type {\n JoinByColumnValueTransform,\n MergeColumnsTransform,\n MergeIndexedColumnsTransform,\n MergeSeriesTransform,\n PivotByLabelTransform,\n Transform,\n} from '../model';\n\ninterface TransformSpecEditorProps<Spec> {\n value: Spec;\n onChange: (transform: Spec) => void;\n}\n\nfunction JoinByColumnValueTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<JoinByColumnValueTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <Autocomplete\n freeSolo\n multiple\n id=\"join-columns\"\n sx={{ width: '100%' }}\n options={[]} // TODO: autofill columns name when query results is available to panel editors\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\" gap={1} alignItems=\"center\">\n <Autocomplete\n freeSolo\n multiple\n id=\"merge-columns-columns\"\n sx={{ width: '100%' }}\n options={[]}\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n\n <TextField\n id=\"merge-columns-name\"\n variant=\"outlined\"\n label=\"Output Name\"\n value={value.spec.name ?? ''}\n sx={{ width: '100%' }}\n onChange={(name) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n name: name,\n },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeIndexedColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeIndexedColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <TextField\n id=\"merge-indexed-columns\"\n variant=\"outlined\"\n label=\"Column\"\n placeholder=\"Example: 'value' for merging 'value #1', 'value #2' and 'value #...'\"\n value={value.spec.column ?? ''}\n sx={{ width: '100%' }}\n onChange={(column) => {\n onChange({\n ...value,\n spec: { ...value.spec, column: column },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeSeriesTransformEditor({ value, onChange }: TransformSpecEditorProps<MergeSeriesTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nexport interface TransformEditorProps extends Omit<StackProps, 'children' | 'value' | 'onChange'> {\n value: Transform;\n onChange: (transform: Transform) => void;\n}\n\nexport function TransformEditor({ value, onChange, ...props }: TransformEditorProps): ReactElement {\n return (\n <Stack gap={2} sx={{ width: '100%' }} mt={1} {...props}>\n <TextField\n select\n label=\"Kind\"\n value={value.kind}\n onChange={(kind) => onChange({ ...value, kind: kind as unknown as Transform['kind'] } as Transform)}\n >\n <MenuItem value=\"JoinByColumnValue\">\n <Stack>\n <Typography>Join by column value</Typography>\n <Typography variant=\"caption\">Regroup rows with equal cell value in a column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeColumns\">\n <Stack>\n <Typography>Merge columns</Typography>\n <Typography variant=\"caption\">Multiple columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeIndexedColumns\">\n <Stack>\n <Typography>Merge indexed columns</Typography>\n <Typography variant=\"caption\">Indexed columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeSeries\">\n <Stack>\n <Typography>Merge series</Typography>\n <Typography variant=\"caption\">Series will be merged by their labels</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"PivotByLabel\">\n <Stack>\n <Typography>Pivot by label</Typography>\n <Typography variant=\"caption\">Time × label matrix (rows = time, columns = label values)</Typography>\n </Stack>\n </MenuItem>\n </TextField>\n {value.kind === 'JoinByColumnValue' && <JoinByColumnValueTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeColumns' && <MergeColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeIndexedColumns' && <MergeIndexedColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeSeries' && <MergeSeriesTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'PivotByLabel' && <PivotByLabelTransformEditor value={value} onChange={onChange} />}\n </Stack>\n );\n}\n\nfunction PivotByLabelTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<PivotByLabelTransform>): ReactElement {\n return (\n <Stack gap={2}>\n <MuiTextField\n label=\"Column label\"\n fullWidth\n value={value.spec.columnLabel ?? ''}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, columnLabel: e.target.value } })}\n helperText=\"Label that becomes dynamic column headers (e.g. farm_short)\"\n />\n <MuiTextField\n label=\"Row field\"\n fullWidth\n value={value.spec.rowField ?? 'timestamp'}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, rowField: e.target.value } })}\n helperText=\"Field used for row identity (default: timestamp)\"\n />\n <MuiTextField\n label=\"Value field\"\n fullWidth\n value={value.spec.valueField ?? 'value'}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, valueField: e.target.value } })}\n />\n <MuiTextField\n label=\"Row column name\"\n fullWidth\n value={value.spec.rowColumnName ?? ''}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, rowColumnName: e.target.value || undefined },\n })\n }\n helperText=\"Optional display name for the row column (default: row field)\"\n />\n <FormControlLabel\n control={\n <Switch\n checked={!!value.spec.disabled}\n onChange={(_, checked) => onChange({ ...value, spec: { ...value.spec, disabled: checked } })}\n />\n }\n label=\"Disabled\"\n />\n </Stack>\n );\n}\n"],"names":["Autocomplete","FormControlLabel","MenuItem","Stack","Switch","Typography","TextField","MuiTextField","JoinByColumnValueTransformEditor","value","onChange","direction","freeSolo","multiple","id","sx","width","options","spec","columns","renderInput","params","variant","label","required","_","labelPlacement","control","disabled","checked","e","target","MergeColumnsTransformEditor","gap","alignItems","name","MergeIndexedColumnsTransformEditor","placeholder","column","MergeSeriesTransformEditor","TransformEditor","props","mt","select","kind","PivotByLabelTransformEditor","fullWidth","columnLabel","helperText","rowField","valueField","rowColumnName","undefined"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../src/controls/TextField.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../src/controls/TextField.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAOzE,KAAK,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAExH,eAAO,MAAM,SAAS,wHAwBpB,CAAC"}
|
|
@@ -13,22 +13,27 @@
|
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
14
|
import { TextField as MuiTextField } from "@mui/material";
|
|
15
15
|
import debounce from "lodash/debounce";
|
|
16
|
-
import { forwardRef, useCallback,
|
|
16
|
+
import { forwardRef, useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
17
17
|
export const TextField = /*#__PURE__*/ forwardRef(function({ debounceMs = 250, value, onChange, ...props }, ref) {
|
|
18
18
|
const [currentValue, setCurrentValue] = useState(value);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
const handleDebounceFn = useCallback((inputValue)=>{
|
|
24
|
-
onChange?.(inputValue);
|
|
19
|
+
const onChangeRef = useRef(onChange);
|
|
20
|
+
useLayoutEffect(()=>{
|
|
21
|
+
onChangeRef.current = onChange;
|
|
25
22
|
}, [
|
|
26
23
|
onChange
|
|
27
24
|
]);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const debounceRef = useRef(null);
|
|
26
|
+
useLayoutEffect(()=>{
|
|
27
|
+
const debounceFn = debounce((inputValue)=>onChangeRef.current?.(inputValue), debounceMs);
|
|
28
|
+
debounceRef.current = debounceFn;
|
|
29
|
+
return ()=>debounceFn.cancel();
|
|
30
|
+
}, [
|
|
31
|
+
debounceMs
|
|
31
32
|
]);
|
|
33
|
+
const handleChange = useCallback((event)=>{
|
|
34
|
+
setCurrentValue(event.target.value);
|
|
35
|
+
debounceRef.current?.(event.target.value);
|
|
36
|
+
}, []);
|
|
32
37
|
return /*#__PURE__*/ _jsx(MuiTextField, {
|
|
33
38
|
ref: ref,
|
|
34
39
|
value: currentValue,
|