mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-16 18:36:05 +08:00
feat: research on data limit for signoz dashboard perf
This commit is contained in:
parent
f9cb9f10be
commit
520a3f93c6
@ -0,0 +1,85 @@
|
|||||||
|
.custom-data-controls {
|
||||||
|
margin: 8px 0;
|
||||||
|
|
||||||
|
.custom-data-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-data-inputs {
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-custom-data-controls {
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark-mode {
|
||||||
|
background-color: #141414;
|
||||||
|
border: 1px solid #303030;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inline-layout {
|
||||||
|
.custom-data-inline-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.title-switch-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
min-width: 180px;
|
||||||
|
|
||||||
|
.ant-typography {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputs-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
margin-right: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce vertical padding for the card
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
import './CustomDataControls.styles.scss';
|
||||||
|
|
||||||
|
import { Card, InputNumber, Switch, Typography } from 'antd';
|
||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
interface CustomDataControlsProps {
|
||||||
|
widget: Widgets;
|
||||||
|
onUpdate: (updatedWidget: Partial<Widgets>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
function CustomDataControls({
|
||||||
|
widget,
|
||||||
|
onUpdate,
|
||||||
|
}: CustomDataControlsProps): JSX.Element {
|
||||||
|
const handleCustomDataModeChange = (checked: boolean): void => {
|
||||||
|
onUpdate({
|
||||||
|
customDataMode: checked,
|
||||||
|
customXData: checked ? widget.customXData || 15 : undefined,
|
||||||
|
customYData: checked ? widget.customYData || 4 : undefined,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDataPointsChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
onUpdate({ customXData: value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSeriesCountChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
onUpdate({ customYData: value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="custom-data-controls" size="small">
|
||||||
|
<div className="custom-data-header">
|
||||||
|
<Text strong>Custom Data Generator</Text>
|
||||||
|
<Switch
|
||||||
|
checked={widget.customDataMode || false}
|
||||||
|
onChange={handleCustomDataModeChange}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{widget.customDataMode && (
|
||||||
|
<div className="custom-data-inputs">
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Data Points (X):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={widget.customXData || 15}
|
||||||
|
onChange={handleDataPointsChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Series Count (Y):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={widget.customYData || 4}
|
||||||
|
onChange={handleSeriesCountChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomDataControls;
|
@ -0,0 +1,91 @@
|
|||||||
|
import './CustomDataControls.styles.scss';
|
||||||
|
|
||||||
|
import { Card, InputNumber, Switch, Typography } from 'antd';
|
||||||
|
|
||||||
|
interface GlobalCustomDataControlsProps {
|
||||||
|
customDataMode: boolean;
|
||||||
|
setCustomDataMode: (value: boolean) => void;
|
||||||
|
customXData: number;
|
||||||
|
setCustomXData: (value: number) => void;
|
||||||
|
customYData: number;
|
||||||
|
setCustomYData: (value: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
function GlobalCustomDataControls({
|
||||||
|
customDataMode,
|
||||||
|
setCustomDataMode,
|
||||||
|
customXData,
|
||||||
|
setCustomXData,
|
||||||
|
customYData,
|
||||||
|
setCustomYData,
|
||||||
|
}: GlobalCustomDataControlsProps): JSX.Element {
|
||||||
|
const handleCustomDataModeChange = (checked: boolean): void => {
|
||||||
|
setCustomDataMode(checked);
|
||||||
|
|
||||||
|
// Set default values if not already set
|
||||||
|
if (checked) {
|
||||||
|
if (!customXData) setCustomXData(15);
|
||||||
|
if (!customYData) setCustomYData(4);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDataPointsChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
setCustomXData(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSeriesCountChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
setCustomYData(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className="custom-data-controls global-custom-data-controls"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<div className="custom-data-header">
|
||||||
|
<Text strong>Global Custom Data Generator</Text>
|
||||||
|
<Switch
|
||||||
|
checked={customDataMode}
|
||||||
|
onChange={handleCustomDataModeChange}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{customDataMode && (
|
||||||
|
<div className="custom-data-inputs">
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Data Points (X):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={customXData || 15}
|
||||||
|
onChange={handleDataPointsChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
min={1}
|
||||||
|
max={1000}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Series Count (Y):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={customYData || 4}
|
||||||
|
onChange={handleSeriesCountChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
min={1}
|
||||||
|
max={20}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GlobalCustomDataControls;
|
@ -0,0 +1,88 @@
|
|||||||
|
import './CustomDataControls.styles.scss';
|
||||||
|
|
||||||
|
import { Card, InputNumber, Switch, Typography } from 'antd';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
function GlobalCustomDataControlsHeader(): JSX.Element {
|
||||||
|
const {
|
||||||
|
globalCustomDataMode,
|
||||||
|
setGlobalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
setGlobalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
|
setGlobalCustomYData,
|
||||||
|
} = useDashboard();
|
||||||
|
|
||||||
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
|
const handleCustomDataModeChange = (checked: boolean): void => {
|
||||||
|
setGlobalCustomDataMode(checked);
|
||||||
|
|
||||||
|
// Set default values if not already set
|
||||||
|
if (checked) {
|
||||||
|
if (!globalCustomXData) setGlobalCustomXData(15);
|
||||||
|
if (!globalCustomYData) setGlobalCustomYData(4);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDataPointsChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
setGlobalCustomXData(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSeriesCountChange = (value: number | null): void => {
|
||||||
|
if (value !== null && value > 0) {
|
||||||
|
setGlobalCustomYData(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className={`custom-data-controls global-custom-data-controls inline-layout ${
|
||||||
|
isDarkMode ? 'dark-mode' : ''
|
||||||
|
}`}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<div className="custom-data-inline-container">
|
||||||
|
<div className="title-switch-group">
|
||||||
|
<Text strong>Custom Data Generator</Text>
|
||||||
|
<Switch
|
||||||
|
checked={globalCustomDataMode}
|
||||||
|
onChange={handleCustomDataModeChange}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{globalCustomDataMode && (
|
||||||
|
<div className="inputs-container">
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Points (X):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={globalCustomXData || 15}
|
||||||
|
onChange={handleDataPointsChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="input-group">
|
||||||
|
<Text className="input-label">Series (Y):</Text>
|
||||||
|
<InputNumber
|
||||||
|
value={globalCustomYData || 4}
|
||||||
|
onChange={handleSeriesCountChange}
|
||||||
|
size="small"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GlobalCustomDataControlsHeader;
|
@ -121,6 +121,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.global-custom-data-section {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-details {
|
.dashboard-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import logEvent from 'api/common/logEvent';
|
import logEvent from 'api/common/logEvent';
|
||||||
|
import GlobalCustomDataControlsHeader from 'components/CustomDataControls/GlobalCustomDataControlsHeader';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
@ -478,6 +479,9 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section className="global-custom-data-section">
|
||||||
|
<GlobalCustomDataControlsHeader />
|
||||||
|
</section>
|
||||||
{(tags?.length || 0) > 0 && (
|
{(tags?.length || 0) > 0 && (
|
||||||
<div className="dashboard-tags">
|
<div className="dashboard-tags">
|
||||||
{tags?.map((tag) => (
|
{tags?.map((tag) => (
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
Switch,
|
Switch,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
|
import CustomDataControls from 'components/CustomDataControls/CustomDataControls';
|
||||||
import TimePreference from 'components/TimePreferenceDropDown';
|
import TimePreference from 'components/TimePreferenceDropDown';
|
||||||
import { PANEL_TYPES, PanelDisplay } from 'constants/queryBuilder';
|
import { PANEL_TYPES, PanelDisplay } from 'constants/queryBuilder';
|
||||||
import GraphTypes, {
|
import GraphTypes, {
|
||||||
@ -113,6 +114,12 @@ function RightContainer({
|
|||||||
customLegendColors,
|
customLegendColors,
|
||||||
setCustomLegendColors,
|
setCustomLegendColors,
|
||||||
queryResponse,
|
queryResponse,
|
||||||
|
customDataMode,
|
||||||
|
setCustomDataMode,
|
||||||
|
customXData,
|
||||||
|
setCustomXData,
|
||||||
|
customYData,
|
||||||
|
setCustomYData,
|
||||||
}: RightContainerProps): JSX.Element {
|
}: RightContainerProps): JSX.Element {
|
||||||
const { selectedDashboard } = useDashboard();
|
const { selectedDashboard } = useDashboard();
|
||||||
const [inputValue, setInputValue] = useState(title);
|
const [inputValue, setInputValue] = useState(title);
|
||||||
@ -280,6 +287,30 @@ function RightContainer({
|
|||||||
rootClassName="description-input"
|
rootClassName="description-input"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Custom Data Controls */}
|
||||||
|
{selectedWidget && (
|
||||||
|
<CustomDataControls
|
||||||
|
widget={{
|
||||||
|
...selectedWidget,
|
||||||
|
customDataMode,
|
||||||
|
customXData,
|
||||||
|
customYData,
|
||||||
|
}}
|
||||||
|
onUpdate={(updatedWidget: Partial<Widgets>): void => {
|
||||||
|
if (updatedWidget.customDataMode !== undefined) {
|
||||||
|
setCustomDataMode(updatedWidget.customDataMode);
|
||||||
|
}
|
||||||
|
if (updatedWidget.customXData !== undefined) {
|
||||||
|
setCustomXData(updatedWidget.customXData);
|
||||||
|
}
|
||||||
|
if (updatedWidget.customYData !== undefined) {
|
||||||
|
setCustomYData(updatedWidget.customYData);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<section className="panel-config">
|
<section className="panel-config">
|
||||||
<Typography.Text className="typography">Panel Type</Typography.Text>
|
<Typography.Text className="typography">Panel Type</Typography.Text>
|
||||||
<Select
|
<Select
|
||||||
@ -554,6 +585,12 @@ interface RightContainerProps {
|
|||||||
SuccessResponse<MetricRangePayloadProps, unknown>,
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
Error
|
Error
|
||||||
>;
|
>;
|
||||||
|
customDataMode: boolean;
|
||||||
|
setCustomDataMode: Dispatch<SetStateAction<boolean>>;
|
||||||
|
customXData: number;
|
||||||
|
setCustomXData: Dispatch<SetStateAction<number>>;
|
||||||
|
customYData: number;
|
||||||
|
setCustomYData: Dispatch<SetStateAction<number>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
RightContainer.defaultProps = {
|
RightContainer.defaultProps = {
|
||||||
|
@ -239,6 +239,17 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
selectedWidget?.columnUnits || {},
|
selectedWidget?.columnUnits || {},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Custom data generator state
|
||||||
|
const [customDataMode, setCustomDataMode] = useState<boolean>(
|
||||||
|
selectedWidget?.customDataMode || false,
|
||||||
|
);
|
||||||
|
const [customXData, setCustomXData] = useState<number>(
|
||||||
|
selectedWidget?.customXData || 15,
|
||||||
|
);
|
||||||
|
const [customYData, setCustomYData] = useState<number>(
|
||||||
|
selectedWidget?.customYData || 4,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedWidget((prev) => {
|
setSelectedWidget((prev) => {
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
@ -268,6 +279,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
legendPosition,
|
legendPosition,
|
||||||
customLegendColors,
|
customLegendColors,
|
||||||
columnWidths: columnWidths?.[selectedWidget?.id],
|
columnWidths: columnWidths?.[selectedWidget?.id],
|
||||||
|
customDataMode,
|
||||||
|
customXData,
|
||||||
|
customYData,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@ -294,6 +308,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
legendPosition,
|
legendPosition,
|
||||||
customLegendColors,
|
customLegendColors,
|
||||||
columnWidths,
|
columnWidths,
|
||||||
|
customDataMode,
|
||||||
|
customXData,
|
||||||
|
customYData,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const closeModal = (): void => {
|
const closeModal = (): void => {
|
||||||
@ -503,6 +520,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
||||||
legendPosition: selectedWidget?.legendPosition || LegendPosition.BOTTOM,
|
legendPosition: selectedWidget?.legendPosition || LegendPosition.BOTTOM,
|
||||||
customLegendColors: selectedWidget?.customLegendColors || {},
|
customLegendColors: selectedWidget?.customLegendColors || {},
|
||||||
|
customDataMode: selectedWidget?.customDataMode || false,
|
||||||
|
customXData: selectedWidget?.customXData || 15,
|
||||||
|
customYData: selectedWidget?.customYData || 4,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
@ -532,6 +552,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
||||||
legendPosition: selectedWidget?.legendPosition || LegendPosition.BOTTOM,
|
legendPosition: selectedWidget?.legendPosition || LegendPosition.BOTTOM,
|
||||||
customLegendColors: selectedWidget?.customLegendColors || {},
|
customLegendColors: selectedWidget?.customLegendColors || {},
|
||||||
|
customDataMode: selectedWidget?.customDataMode || false,
|
||||||
|
customXData: selectedWidget?.customXData || 15,
|
||||||
|
customYData: selectedWidget?.customYData || 4,
|
||||||
},
|
},
|
||||||
...afterWidgets,
|
...afterWidgets,
|
||||||
],
|
],
|
||||||
@ -796,6 +819,12 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
setSoftMin={setSoftMin}
|
setSoftMin={setSoftMin}
|
||||||
softMax={softMax}
|
softMax={softMax}
|
||||||
setSoftMax={setSoftMax}
|
setSoftMax={setSoftMax}
|
||||||
|
customDataMode={customDataMode}
|
||||||
|
setCustomDataMode={setCustomDataMode}
|
||||||
|
customXData={customXData}
|
||||||
|
setCustomXData={setCustomXData}
|
||||||
|
customYData={customYData}
|
||||||
|
setCustomYData={setCustomYData}
|
||||||
/>
|
/>
|
||||||
</OverlayScrollbar>
|
</OverlayScrollbar>
|
||||||
</RightContainerWrapper>
|
</RightContainerWrapper>
|
||||||
|
@ -10,12 +10,19 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { useResizeObserver } from 'hooks/useDimensions';
|
import { useResizeObserver } from 'hooks/useDimensions';
|
||||||
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
||||||
|
import {
|
||||||
|
getCustomApiResponse,
|
||||||
|
getCustomChartData,
|
||||||
|
} from 'lib/uPlotLib/utils/getCustomChartData';
|
||||||
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
||||||
import { cloneDeep, isEqual, isUndefined } from 'lodash-es';
|
import { cloneDeep, isEqual, isUndefined } from 'lodash-es';
|
||||||
import _noop from 'lodash-es/noop';
|
import _noop from 'lodash-es/noop';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useTimezone } from 'providers/Timezone';
|
import { useTimezone } from 'providers/Timezone';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import uPlot from 'uplot';
|
import uPlot from 'uplot';
|
||||||
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
||||||
import { getTimeRange } from 'utils/getTimeRange';
|
import { getTimeRange } from 'utils/getTimeRange';
|
||||||
@ -35,7 +42,14 @@ function UplotPanelWrapper({
|
|||||||
customTooltipElement,
|
customTooltipElement,
|
||||||
customSeries,
|
customSeries,
|
||||||
}: PanelWrapperProps): JSX.Element {
|
}: PanelWrapperProps): JSX.Element {
|
||||||
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
const {
|
||||||
|
toScrollWidgetId,
|
||||||
|
setToScrollWidgetId,
|
||||||
|
globalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
|
} = useDashboard();
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
const lineChartRef = useRef<ToggleGraphProps>();
|
const lineChartRef = useRef<ToggleGraphProps>();
|
||||||
const graphRef = useRef<HTMLDivElement>(null);
|
const graphRef = useRef<HTMLDivElement>(null);
|
||||||
@ -43,6 +57,11 @@ function UplotPanelWrapper({
|
|||||||
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
||||||
const { currentQuery } = useQueryBuilder();
|
const { currentQuery } = useQueryBuilder();
|
||||||
|
|
||||||
|
// Get global time for custom data generation
|
||||||
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
const [hiddenGraph, setHiddenGraph] = useState<{ [key: string]: boolean }>();
|
const [hiddenGraph, setHiddenGraph] = useState<{ [key: string]: boolean }>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -56,12 +75,64 @@ function UplotPanelWrapper({
|
|||||||
}
|
}
|
||||||
}, [toScrollWidgetId, setToScrollWidgetId, widget.id]);
|
}, [toScrollWidgetId, setToScrollWidgetId, widget.id]);
|
||||||
|
|
||||||
|
// Create custom response when custom data mode is enabled (either via widget or global setting)
|
||||||
|
const effectiveQueryResponse = useMemo(() => {
|
||||||
|
// If global custom data mode is enabled, it should override widget settings
|
||||||
|
const isCustomDataEnabled = globalCustomDataMode || widget.customDataMode;
|
||||||
|
|
||||||
|
// When global custom data is enabled, use global values regardless of widget settings
|
||||||
|
let xData = null;
|
||||||
|
let yData = null;
|
||||||
|
|
||||||
|
if (globalCustomDataMode) {
|
||||||
|
// Global settings override widget settings
|
||||||
|
xData = globalCustomXData;
|
||||||
|
yData = globalCustomYData;
|
||||||
|
} else if (widget.customDataMode) {
|
||||||
|
// Only use widget settings if global is not enabled
|
||||||
|
xData = widget.customXData;
|
||||||
|
yData = widget.customYData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCustomDataEnabled && xData && yData) {
|
||||||
|
// Convert nanoseconds to seconds for custom data generation
|
||||||
|
const startTimeSeconds = Math.floor(minTime / 1000000000);
|
||||||
|
const endTimeSeconds = Math.floor(maxTime / 1000000000);
|
||||||
|
|
||||||
|
const customResponse = getCustomApiResponse(
|
||||||
|
xData,
|
||||||
|
yData,
|
||||||
|
startTimeSeconds,
|
||||||
|
endTimeSeconds,
|
||||||
|
);
|
||||||
|
// Return a properly structured response that matches the expected type
|
||||||
|
return {
|
||||||
|
...queryResponse,
|
||||||
|
data: customResponse,
|
||||||
|
isSuccess: true,
|
||||||
|
isError: false,
|
||||||
|
isLoading: false,
|
||||||
|
} as typeof queryResponse;
|
||||||
|
}
|
||||||
|
return queryResponse;
|
||||||
|
}, [
|
||||||
|
queryResponse,
|
||||||
|
widget.customDataMode,
|
||||||
|
widget.customXData,
|
||||||
|
widget.customYData,
|
||||||
|
globalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect((): void => {
|
useEffect((): void => {
|
||||||
const { startTime, endTime } = getTimeRange(queryResponse);
|
const { startTime, endTime } = getTimeRange(effectiveQueryResponse);
|
||||||
|
|
||||||
setMinTimeScale(startTime);
|
setMinTimeScale(startTime);
|
||||||
setMaxTimeScale(endTime);
|
setMaxTimeScale(endTime);
|
||||||
}, [queryResponse]);
|
}, [effectiveQueryResponse]);
|
||||||
|
|
||||||
const containerDimensions = useResizeObserver(graphRef);
|
const containerDimensions = useResizeObserver(graphRef);
|
||||||
|
|
||||||
@ -69,28 +140,71 @@ function UplotPanelWrapper({
|
|||||||
const {
|
const {
|
||||||
graphVisibilityStates: localStoredVisibilityState,
|
graphVisibilityStates: localStoredVisibilityState,
|
||||||
} = getLocalStorageGraphVisibilityState({
|
} = getLocalStorageGraphVisibilityState({
|
||||||
apiResponse: queryResponse.data?.payload.data.result || [],
|
apiResponse: effectiveQueryResponse.data?.payload.data.result || [],
|
||||||
name: widget.id,
|
name: widget.id,
|
||||||
});
|
});
|
||||||
if (setGraphVisibility) {
|
if (setGraphVisibility) {
|
||||||
setGraphVisibility(localStoredVisibilityState);
|
setGraphVisibility(localStoredVisibilityState);
|
||||||
}
|
}
|
||||||
}, [queryResponse.data?.payload.data.result, setGraphVisibility, widget.id]);
|
}, [
|
||||||
|
effectiveQueryResponse.data?.payload.data.result,
|
||||||
|
setGraphVisibility,
|
||||||
|
widget.id,
|
||||||
|
]);
|
||||||
|
|
||||||
if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
|
if (effectiveQueryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
|
||||||
const sortedSeriesData = getSortedSeriesData(
|
const sortedSeriesData = getSortedSeriesData(
|
||||||
queryResponse.data?.payload.data.result,
|
effectiveQueryResponse.data?.payload.data.result,
|
||||||
);
|
);
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
queryResponse.data.payload.data.result = sortedSeriesData;
|
effectiveQueryResponse.data.payload.data.result = sortedSeriesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chartData = getUPlotChartData(
|
const chartData = useMemo(() => {
|
||||||
queryResponse?.data?.payload,
|
// If global custom data mode is enabled, it should override widget settings
|
||||||
|
const isCustomDataEnabled = globalCustomDataMode || widget.customDataMode;
|
||||||
|
|
||||||
|
// When global custom data is enabled, use global values regardless of widget settings
|
||||||
|
let xData = null;
|
||||||
|
let yData = null;
|
||||||
|
|
||||||
|
if (globalCustomDataMode) {
|
||||||
|
// Global settings override widget settings
|
||||||
|
xData = globalCustomXData;
|
||||||
|
yData = globalCustomYData;
|
||||||
|
} else if (widget.customDataMode) {
|
||||||
|
// Only use widget settings if global is not enabled
|
||||||
|
xData = widget.customXData;
|
||||||
|
yData = widget.customYData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCustomDataEnabled && xData && yData) {
|
||||||
|
// Convert nanoseconds to seconds for custom data generation
|
||||||
|
const startTimeSeconds = Math.floor(minTime / 1000000000);
|
||||||
|
const endTimeSeconds = Math.floor(maxTime / 1000000000);
|
||||||
|
|
||||||
|
return getCustomChartData(xData, yData, startTimeSeconds, endTimeSeconds);
|
||||||
|
}
|
||||||
|
return getUPlotChartData(
|
||||||
|
effectiveQueryResponse?.data?.payload,
|
||||||
|
widget.fillSpans,
|
||||||
|
widget?.stackedBarChart,
|
||||||
|
hiddenGraph,
|
||||||
|
);
|
||||||
|
}, [
|
||||||
|
widget.customDataMode,
|
||||||
|
widget.customXData,
|
||||||
|
widget.customYData,
|
||||||
|
globalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
effectiveQueryResponse?.data?.payload,
|
||||||
widget.fillSpans,
|
widget.fillSpans,
|
||||||
widget?.stackedBarChart,
|
widget?.stackedBarChart,
|
||||||
hiddenGraph,
|
hiddenGraph,
|
||||||
);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (widget.panelTypes === PANEL_TYPES.BAR && widget?.stackedBarChart) {
|
if (widget.panelTypes === PANEL_TYPES.BAR && widget?.stackedBarChart) {
|
||||||
@ -110,16 +224,22 @@ function UplotPanelWrapper({
|
|||||||
|
|
||||||
const { timezone } = useTimezone();
|
const { timezone } = useTimezone();
|
||||||
|
|
||||||
|
// Standard click handler without performance monitoring
|
||||||
|
const enhancedClickHandler = useMemo(() => {
|
||||||
|
if (!onClickHandler) return _noop;
|
||||||
|
return onClickHandler;
|
||||||
|
}, [onClickHandler]);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getUPlotChartOptions({
|
getUPlotChartOptions({
|
||||||
id: widget?.id,
|
id: widget?.id,
|
||||||
apiResponse: queryResponse.data?.payload,
|
apiResponse: effectiveQueryResponse.data?.payload,
|
||||||
dimensions: containerDimensions,
|
dimensions: containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
yAxisUnit: widget?.yAxisUnit,
|
yAxisUnit: widget?.yAxisUnit,
|
||||||
onClickHandler: onClickHandler || _noop,
|
onClickHandler: enhancedClickHandler,
|
||||||
thresholds: widget.thresholds,
|
thresholds: widget.thresholds,
|
||||||
minTimeScale,
|
minTimeScale,
|
||||||
maxTimeScale,
|
maxTimeScale,
|
||||||
@ -150,11 +270,11 @@ function UplotPanelWrapper({
|
|||||||
widget.softMin,
|
widget.softMin,
|
||||||
widget.panelTypes,
|
widget.panelTypes,
|
||||||
widget?.stackedBarChart,
|
widget?.stackedBarChart,
|
||||||
queryResponse.data?.payload,
|
effectiveQueryResponse.data?.payload,
|
||||||
containerDimensions,
|
containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
onClickHandler,
|
enhancedClickHandler,
|
||||||
minTimeScale,
|
minTimeScale,
|
||||||
maxTimeScale,
|
maxTimeScale,
|
||||||
graphVisibility,
|
graphVisibility,
|
||||||
@ -171,6 +291,14 @@ function UplotPanelWrapper({
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'chartData',
|
||||||
|
'x-axis',
|
||||||
|
chartData[0].length,
|
||||||
|
'y-axis',
|
||||||
|
chartData.length,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
||||||
<Uplot options={options} data={chartData} ref={lineChartRef} />
|
<Uplot options={options} data={chartData} ref={lineChartRef} />
|
||||||
@ -183,7 +311,10 @@ function UplotPanelWrapper({
|
|||||||
)}
|
)}
|
||||||
{isFullViewMode && setGraphVisibility && !widget?.stackedBarChart && (
|
{isFullViewMode && setGraphVisibility && !widget?.stackedBarChart && (
|
||||||
<GraphManager
|
<GraphManager
|
||||||
data={getUPlotChartData(queryResponse?.data?.payload, widget.fillSpans)}
|
data={getUPlotChartData(
|
||||||
|
effectiveQueryResponse?.data?.payload,
|
||||||
|
widget.fillSpans,
|
||||||
|
)}
|
||||||
name={widget.id}
|
name={widget.id}
|
||||||
options={options}
|
options={options}
|
||||||
yAxisUnit={widget.yAxisUnit}
|
yAxisUnit={widget.yAxisUnit}
|
||||||
|
@ -431,9 +431,10 @@ export const getUPlotChartOptions = ({
|
|||||||
// Add single global cleanup listener for this chart
|
// Add single global cleanup listener for this chart
|
||||||
const globalCleanupHandler = (e: MouseEvent): void => {
|
const globalCleanupHandler = (e: MouseEvent): void => {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
|
console.log('target', target);
|
||||||
if (
|
if (
|
||||||
!target.closest('.u-legend') &&
|
!target?.closest?.('.u-legend') &&
|
||||||
!target.classList.contains('legend-tooltip')
|
!target?.classList?.contains('legend-tooltip')
|
||||||
) {
|
) {
|
||||||
cleanupAllTooltips();
|
cleanupAllTooltips();
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useMutation, useQuery, UseQueryResult } from 'react-query';
|
import { useMutation, useQuery, UseQueryResult } from 'react-query';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useRouteMatch } from 'react-router-dom';
|
import { useRouteMatch } from 'react-router-dom';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch as ReduxDispatch } from 'redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import AppActions from 'types/actions';
|
import AppActions from 'types/actions';
|
||||||
import { UPDATE_TIME_INTERVAL } from 'types/actions/globalTime';
|
import { UPDATE_TIME_INTERVAL } from 'types/actions/globalTime';
|
||||||
@ -51,7 +51,7 @@ const DashboardContext = createContext<IDashboardContext>({
|
|||||||
isDashboardSliderOpen: false,
|
isDashboardSliderOpen: false,
|
||||||
isDashboardLocked: false,
|
isDashboardLocked: false,
|
||||||
handleToggleDashboardSlider: () => {},
|
handleToggleDashboardSlider: () => {},
|
||||||
handleDashboardLockToggle: () => {},
|
handleDashboardLockToggle: async () => {},
|
||||||
dashboardResponse: {} as UseQueryResult<Dashboard, unknown>,
|
dashboardResponse: {} as UseQueryResult<Dashboard, unknown>,
|
||||||
selectedDashboard: {} as Dashboard,
|
selectedDashboard: {} as Dashboard,
|
||||||
dashboardId: '',
|
dashboardId: '',
|
||||||
@ -80,6 +80,13 @@ const DashboardContext = createContext<IDashboardContext>({
|
|||||||
isDashboardFetching: false,
|
isDashboardFetching: false,
|
||||||
columnWidths: {},
|
columnWidths: {},
|
||||||
setColumnWidths: () => {},
|
setColumnWidths: () => {},
|
||||||
|
// Global custom data state
|
||||||
|
globalCustomDataMode: false,
|
||||||
|
setGlobalCustomDataMode: () => {},
|
||||||
|
globalCustomXData: 15,
|
||||||
|
setGlobalCustomXData: () => {},
|
||||||
|
globalCustomYData: 4,
|
||||||
|
setGlobalCustomYData: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -146,7 +153,7 @@ export function DashboardProvider({
|
|||||||
|
|
||||||
function setListSortOrder(sortOrder: DashboardSortOrder): void {
|
function setListSortOrder(sortOrder: DashboardSortOrder): void {
|
||||||
if (!isEqual(sortOrder, listSortOrder)) {
|
if (!isEqual(sortOrder, listSortOrder)) {
|
||||||
setListOrder(sortOrder);
|
setListOrder(sortOrder as any);
|
||||||
}
|
}
|
||||||
params.set('columnKey', sortOrder.columnKey as string);
|
params.set('columnKey', sortOrder.columnKey as string);
|
||||||
params.set('order', sortOrder.order as string);
|
params.set('order', sortOrder.order as string);
|
||||||
@ -155,7 +162,7 @@ export function DashboardProvider({
|
|||||||
safeNavigate({ search: params.toString() });
|
safeNavigate({ search: params.toString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
const dispatch = useDispatch<ReduxDispatch<AppActions>>();
|
||||||
|
|
||||||
const globalTime = useSelector<AppState, GlobalReducer>(
|
const globalTime = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
@ -416,6 +423,13 @@ export function DashboardProvider({
|
|||||||
|
|
||||||
const [columnWidths, setColumnWidths] = useState<WidgetColumnWidths>({});
|
const [columnWidths, setColumnWidths] = useState<WidgetColumnWidths>({});
|
||||||
|
|
||||||
|
// Global custom data state
|
||||||
|
const [globalCustomDataMode, setGlobalCustomDataMode] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
const [globalCustomXData, setGlobalCustomXData] = useState<number>(15);
|
||||||
|
const [globalCustomYData, setGlobalCustomYData] = useState<number>(4);
|
||||||
|
|
||||||
const value: IDashboardContext = useMemo(
|
const value: IDashboardContext = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
toScrollWidgetId,
|
toScrollWidgetId,
|
||||||
@ -424,7 +438,7 @@ export function DashboardProvider({
|
|||||||
handleToggleDashboardSlider,
|
handleToggleDashboardSlider,
|
||||||
handleDashboardLockToggle,
|
handleDashboardLockToggle,
|
||||||
dashboardResponse,
|
dashboardResponse,
|
||||||
selectedDashboard,
|
selectedDashboard: selectedDashboard as Dashboard,
|
||||||
dashboardId,
|
dashboardId,
|
||||||
layouts,
|
layouts,
|
||||||
listSortOrder,
|
listSortOrder,
|
||||||
@ -445,6 +459,13 @@ export function DashboardProvider({
|
|||||||
isDashboardFetching,
|
isDashboardFetching,
|
||||||
columnWidths,
|
columnWidths,
|
||||||
setColumnWidths,
|
setColumnWidths,
|
||||||
|
// Global custom data state
|
||||||
|
globalCustomDataMode,
|
||||||
|
setGlobalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
setGlobalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
|
setGlobalCustomYData,
|
||||||
}),
|
}),
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[
|
[
|
||||||
@ -469,6 +490,10 @@ export function DashboardProvider({
|
|||||||
isDashboardFetching,
|
isDashboardFetching,
|
||||||
columnWidths,
|
columnWidths,
|
||||||
setColumnWidths,
|
setColumnWidths,
|
||||||
|
// Global custom data state
|
||||||
|
globalCustomDataMode,
|
||||||
|
globalCustomXData,
|
||||||
|
globalCustomYData,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
import dayjs from 'dayjs';
|
import { Dayjs } from 'dayjs';
|
||||||
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { Layout } from 'react-grid-layout';
|
import { Layout } from 'react-grid-layout';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
export interface DashboardSortOrder {
|
export interface DashboardSortOrder {
|
||||||
columnKey: string;
|
columnKey?: string | null;
|
||||||
order: string;
|
order?: string | null;
|
||||||
pagination: string;
|
pagination?: string;
|
||||||
search: string;
|
search?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WidgetColumnWidths = {
|
export interface WidgetColumnWidths {
|
||||||
[widgetId: string]: Record<string, number>;
|
[key: string]: Record<string, number>;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface IDashboardContext {
|
export interface IDashboardContext {
|
||||||
isDashboardSliderOpen: boolean;
|
isDashboardSliderOpen: boolean;
|
||||||
isDashboardLocked: boolean;
|
isDashboardLocked: boolean;
|
||||||
handleToggleDashboardSlider: (value: boolean) => void;
|
handleToggleDashboardSlider: (value: boolean) => void;
|
||||||
handleDashboardLockToggle: (value: boolean) => void;
|
handleDashboardLockToggle: (value: boolean) => Promise<void>;
|
||||||
dashboardResponse: UseQueryResult<Dashboard, unknown>;
|
dashboardResponse: UseQueryResult<Dashboard, unknown>;
|
||||||
selectedDashboard: Dashboard | undefined;
|
selectedDashboard: Dashboard;
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
layouts: Layout[];
|
layouts: Layout[];
|
||||||
panelMap: Record<string, { widgets: Layout[]; collapsed: boolean }>;
|
panelMap: Record<string, { widgets: Layout[]; collapsed: boolean }>;
|
||||||
setPanelMap: React.Dispatch<React.SetStateAction<Record<string, any>>>;
|
setPanelMap: Dispatch<
|
||||||
listSortOrder: DashboardSortOrder;
|
SetStateAction<Record<string, { widgets: Layout[]; collapsed: boolean }>>
|
||||||
setListSortOrder: (sortOrder: DashboardSortOrder) => void;
|
|
||||||
setLayouts: React.Dispatch<React.SetStateAction<Layout[]>>;
|
|
||||||
setSelectedDashboard: React.Dispatch<
|
|
||||||
React.SetStateAction<Dashboard | undefined>
|
|
||||||
>;
|
>;
|
||||||
updatedTimeRef: React.MutableRefObject<dayjs.Dayjs | null>;
|
listSortOrder: DashboardSortOrder;
|
||||||
|
setListSortOrder: (value: DashboardSortOrder) => void;
|
||||||
|
setLayouts: Dispatch<SetStateAction<Layout[]>>;
|
||||||
|
setSelectedDashboard: Dispatch<SetStateAction<Dashboard | undefined>>;
|
||||||
|
updatedTimeRef: React.MutableRefObject<Dayjs | null>;
|
||||||
toScrollWidgetId: string;
|
toScrollWidgetId: string;
|
||||||
setToScrollWidgetId: React.Dispatch<React.SetStateAction<string>>;
|
setToScrollWidgetId: Dispatch<SetStateAction<string>>;
|
||||||
updateLocalStorageDashboardVariables: (
|
updateLocalStorageDashboardVariables: (
|
||||||
id: string,
|
id: string,
|
||||||
selectedValue:
|
selectedValue:
|
||||||
@ -46,12 +47,19 @@ export interface IDashboardContext {
|
|||||||
allSelected: boolean,
|
allSelected: boolean,
|
||||||
) => void;
|
) => void;
|
||||||
variablesToGetUpdated: string[];
|
variablesToGetUpdated: string[];
|
||||||
setVariablesToGetUpdated: React.Dispatch<React.SetStateAction<string[]>>;
|
setVariablesToGetUpdated: Dispatch<SetStateAction<string[]>>;
|
||||||
dashboardQueryRangeCalled: boolean;
|
dashboardQueryRangeCalled: boolean;
|
||||||
setDashboardQueryRangeCalled: (value: boolean) => void;
|
setDashboardQueryRangeCalled: Dispatch<SetStateAction<boolean>>;
|
||||||
selectedRowWidgetId: string | null;
|
selectedRowWidgetId: string | null;
|
||||||
setSelectedRowWidgetId: React.Dispatch<React.SetStateAction<string | null>>;
|
setSelectedRowWidgetId: Dispatch<SetStateAction<string | null>>;
|
||||||
isDashboardFetching: boolean;
|
isDashboardFetching: boolean;
|
||||||
columnWidths: WidgetColumnWidths;
|
columnWidths: WidgetColumnWidths;
|
||||||
setColumnWidths: React.Dispatch<React.SetStateAction<WidgetColumnWidths>>;
|
setColumnWidths: Dispatch<SetStateAction<WidgetColumnWidths>>;
|
||||||
|
// Global custom data state
|
||||||
|
globalCustomDataMode: boolean;
|
||||||
|
setGlobalCustomDataMode: Dispatch<SetStateAction<boolean>>;
|
||||||
|
globalCustomXData: number;
|
||||||
|
setGlobalCustomXData: Dispatch<SetStateAction<number>>;
|
||||||
|
globalCustomYData: number;
|
||||||
|
setGlobalCustomYData: Dispatch<SetStateAction<number>>;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,9 @@ export interface IBaseWidget {
|
|||||||
columnWidths?: Record<string, number>;
|
columnWidths?: Record<string, number>;
|
||||||
legendPosition?: LegendPosition;
|
legendPosition?: LegendPosition;
|
||||||
customLegendColors?: Record<string, string>;
|
customLegendColors?: Record<string, string>;
|
||||||
|
customDataMode?: boolean;
|
||||||
|
customXData?: number; // number of data points
|
||||||
|
customYData?: number; // number of series
|
||||||
}
|
}
|
||||||
export interface Widgets extends IBaseWidget {
|
export interface Widgets extends IBaseWidget {
|
||||||
query: Query;
|
query: Query;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user