mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 06:39:03 +08:00
Merge branch 'develop' into release/v0.15.0
This commit is contained in:
commit
e6ce80213b
@ -511,13 +511,15 @@ else
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e "🟢 Your frontend is running on http://localhost:3301"
|
echo -e "🟢 Your frontend is running on http://localhost:3301"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "ℹ️ By default, retention period is set to 7 days for logs and traces, and 30 days for metrics."
|
||||||
|
echo -e "To change this, navigate to the General tab on the Settings page of SigNoz UI. For more details, refer to https://signoz.io/docs/userguide/retention-period \n"
|
||||||
|
|
||||||
echo "ℹ️ To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
|
echo "ℹ️ To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"
|
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"
|
||||||
echo ""
|
echo ""
|
||||||
echo "👉 Need help Getting Started?"
|
echo "👉 Need help in Getting Started?"
|
||||||
echo -e "Join us on Slack https://signoz.io/slack"
|
echo -e "Join us on Slack https://signoz.io/slack"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "\n📨 Please share your email to receive support & updates about SigNoz!"
|
echo -e "\n📨 Please share your email to receive support & updates about SigNoz!"
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
"react-graph-vis": "^1.0.5",
|
"react-graph-vis": "^1.0.5",
|
||||||
"react-grid-layout": "^1.3.4",
|
"react-grid-layout": "^1.3.4",
|
||||||
"react-i18next": "^11.16.1",
|
"react-i18next": "^11.16.1",
|
||||||
|
"react-intersection-observer": "9.4.1",
|
||||||
"react-query": "^3.34.19",
|
"react-query": "^3.34.19",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
|
@ -8,6 +8,7 @@ import getChartData from 'lib/getChartData';
|
|||||||
import isEmpty from 'lodash-es/isEmpty';
|
import isEmpty from 'lodash-es/isEmpty';
|
||||||
import React, { memo, useCallback, useMemo, useState } from 'react';
|
import React, { memo, useCallback, useMemo, useState } from 'react';
|
||||||
import { Layout } from 'react-grid-layout';
|
import { Layout } from 'react-grid-layout';
|
||||||
|
import { useInView } from 'react-intersection-observer';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
import { bindActionCreators, Dispatch } from 'redux';
|
import { bindActionCreators, Dispatch } from 'redux';
|
||||||
@ -39,6 +40,11 @@ function GridCardGraph({
|
|||||||
setLayout,
|
setLayout,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
}: GridCardGraphProps): JSX.Element {
|
}: GridCardGraphProps): JSX.Element {
|
||||||
|
const { ref: graphRef, inView: isGraphVisible } = useInView({
|
||||||
|
threshold: 0,
|
||||||
|
triggerOnce: true,
|
||||||
|
});
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState<string | undefined>('');
|
const [errorMessage, setErrorMessage] = useState<string | undefined>('');
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
const [modal, setModal] = useState(false);
|
const [modal, setModal] = useState(false);
|
||||||
@ -79,6 +85,7 @@ function GridCardGraph({
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
|
enabled: isGraphVisible,
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@ -160,7 +167,7 @@ function GridCardGraph({
|
|||||||
|
|
||||||
if (queryResponse.isError && !isEmptyLayout) {
|
if (queryResponse.isError && !isEmptyLayout) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span ref={graphRef}>
|
||||||
{getModals()}
|
{getModals()}
|
||||||
{!isEmpty(widget) && prevChartDataSetRef && (
|
{!isEmpty(widget) && prevChartDataSetRef && (
|
||||||
<>
|
<>
|
||||||
@ -192,7 +199,7 @@ function GridCardGraph({
|
|||||||
|
|
||||||
if (prevChartDataSetRef?.labels === undefined && queryResponse.isLoading) {
|
if (prevChartDataSetRef?.labels === undefined && queryResponse.isLoading) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span ref={graphRef}>
|
||||||
{!isEmpty(widget) && prevChartDataSetRef?.labels ? (
|
{!isEmpty(widget) && prevChartDataSetRef?.labels ? (
|
||||||
<>
|
<>
|
||||||
<div className="drag-handle">
|
<div className="drag-handle">
|
||||||
@ -225,6 +232,7 @@ function GridCardGraph({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
ref={graphRef}
|
||||||
onMouseOver={(): void => {
|
onMouseOver={(): void => {
|
||||||
setHovered(true);
|
setHovered(true);
|
||||||
}}
|
}}
|
||||||
@ -260,7 +268,7 @@ function GridCardGraph({
|
|||||||
data={chartData}
|
data={chartData}
|
||||||
isStacked={widget.isStacked}
|
isStacked={widget.isStacked}
|
||||||
opacity={widget.opacity}
|
opacity={widget.opacity}
|
||||||
title={' '} // empty title to accommodate absolutely positioned widget header
|
title={' '} // `empty title to accommodate absolutely positioned widget header
|
||||||
name={name}
|
name={name}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
|
@ -10,4 +10,13 @@ export const tooltipStyles = {
|
|||||||
right: '0.313rem',
|
right: '0.313rem',
|
||||||
color: themeColors.errorColor,
|
color: themeColors.errorColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const errorTooltipPosition = 'top';
|
export const errorTooltipPosition = 'top';
|
||||||
|
|
||||||
|
export const overlayStyles: React.CSSProperties = {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
position: 'absolute',
|
||||||
|
};
|
||||||
|
@ -5,11 +5,12 @@ import {
|
|||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined,
|
||||||
FullscreenOutlined,
|
FullscreenOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Dropdown, Menu, Tooltip, Typography } from 'antd';
|
import { Dropdown, MenuProps, Tooltip, Typography } from 'antd';
|
||||||
|
import { MenuItemType } from 'antd/es/menu/hooks/useItems';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import useComponentPermission from 'hooks/useComponentPermission';
|
import useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import React, { useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
@ -18,12 +19,16 @@ import { Widgets } from 'types/api/dashboard/getAll';
|
|||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
|
|
||||||
import { errorTooltipPosition, spinnerStyles, tooltipStyles } from './config';
|
import {
|
||||||
|
errorTooltipPosition,
|
||||||
|
overlayStyles,
|
||||||
|
spinnerStyles,
|
||||||
|
tooltipStyles,
|
||||||
|
} from './config';
|
||||||
import {
|
import {
|
||||||
ArrowContainer,
|
ArrowContainer,
|
||||||
HeaderContainer,
|
HeaderContainer,
|
||||||
HeaderContentContainer,
|
HeaderContentContainer,
|
||||||
MenuItemContainer,
|
|
||||||
} from './styles';
|
} from './styles';
|
||||||
|
|
||||||
type TWidgetOptions = 'view' | 'edit' | 'delete' | string;
|
type TWidgetOptions = 'view' | 'edit' | 'delete' | string;
|
||||||
@ -48,17 +53,19 @@ function WidgetHeader({
|
|||||||
errorMessage,
|
errorMessage,
|
||||||
}: IWidgetHeaderProps): JSX.Element {
|
}: IWidgetHeaderProps): JSX.Element {
|
||||||
const [localHover, setLocalHover] = useState(false);
|
const [localHover, setLocalHover] = useState(false);
|
||||||
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
const onEditHandler = (): void => {
|
const onEditHandler = useCallback((): void => {
|
||||||
const widgetId = widget.id;
|
const widgetId = widget.id;
|
||||||
history.push(
|
history.push(
|
||||||
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
|
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`,
|
||||||
);
|
);
|
||||||
};
|
}, [widget.id, widget.panelTypes]);
|
||||||
|
|
||||||
const keyMethodMapping: {
|
const keyMethodMapping: {
|
||||||
[K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
|
[K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
|
||||||
} = {
|
} = useMemo(
|
||||||
|
() => ({
|
||||||
view: {
|
view: {
|
||||||
key: 'view',
|
key: 'view',
|
||||||
method: onView,
|
method: onView,
|
||||||
@ -71,10 +78,20 @@ function WidgetHeader({
|
|||||||
key: 'delete',
|
key: 'delete',
|
||||||
method: onDelete,
|
method: onDelete,
|
||||||
},
|
},
|
||||||
};
|
}),
|
||||||
const onMenuItemSelectHandler = ({ key }: { key: TWidgetOptions }): void => {
|
[onDelete, onEditHandler, onView],
|
||||||
keyMethodMapping[key]?.method();
|
);
|
||||||
};
|
|
||||||
|
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
|
||||||
|
({ key }: { key: TWidgetOptions }): void => {
|
||||||
|
const functionToCall = keyMethodMapping[key]?.method;
|
||||||
|
if (functionToCall) {
|
||||||
|
functionToCall();
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[keyMethodMapping],
|
||||||
|
);
|
||||||
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
const [deleteWidget, editWidget] = useComponentPermission(
|
const [deleteWidget, editWidget] = useComponentPermission(
|
||||||
@ -82,49 +99,67 @@ function WidgetHeader({
|
|||||||
role,
|
role,
|
||||||
);
|
);
|
||||||
|
|
||||||
const menu = (
|
const menuList: MenuItemType[] = useMemo(
|
||||||
<Menu onClick={onMenuItemSelectHandler}>
|
() => [
|
||||||
<Menu.Item key={keyMethodMapping.view.key}>
|
{
|
||||||
<MenuItemContainer>
|
key: keyMethodMapping.view.key,
|
||||||
<span>View</span> <FullscreenOutlined />
|
icon: <FullscreenOutlined />,
|
||||||
</MenuItemContainer>
|
disabled: queryResponse.isLoading,
|
||||||
</Menu.Item>
|
label: 'View',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: keyMethodMapping.edit.key,
|
||||||
|
icon: <EditFilled />,
|
||||||
|
disabled: !editWidget,
|
||||||
|
label: 'Edit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: keyMethodMapping.delete.key,
|
||||||
|
icon: <DeleteOutlined />,
|
||||||
|
disabled: !deleteWidget,
|
||||||
|
danger: true,
|
||||||
|
label: 'Delete',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
deleteWidget,
|
||||||
|
editWidget,
|
||||||
|
keyMethodMapping.delete.key,
|
||||||
|
keyMethodMapping.edit.key,
|
||||||
|
keyMethodMapping.view.key,
|
||||||
|
queryResponse.isLoading,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
{editWidget && (
|
const onClickHandler = useCallback(() => {
|
||||||
<Menu.Item key={keyMethodMapping.edit.key}>
|
setIsOpen((open) => !open);
|
||||||
<MenuItemContainer>
|
}, []);
|
||||||
<span>Edit</span> <EditFilled />
|
|
||||||
</MenuItemContainer>
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{deleteWidget && (
|
const menu = useMemo(
|
||||||
<>
|
() => ({
|
||||||
<Menu.Divider />
|
items: menuList,
|
||||||
<Menu.Item key={keyMethodMapping.delete.key} danger>
|
onClick: onMenuItemSelectHandler,
|
||||||
<MenuItemContainer>
|
}),
|
||||||
<span>Delete</span> <DeleteOutlined />
|
[menuList, onMenuItemSelectHandler],
|
||||||
</MenuItemContainer>
|
|
||||||
</Menu.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Menu>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
overlay={menu}
|
destroyPopupOnHide
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={setIsOpen}
|
||||||
|
menu={menu}
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
overlayStyle={{ minWidth: 100 }}
|
overlayStyle={overlayStyles}
|
||||||
placement="bottom"
|
|
||||||
>
|
>
|
||||||
<>
|
|
||||||
<HeaderContainer
|
<HeaderContainer
|
||||||
onMouseOver={(): void => setLocalHover(true)}
|
onMouseOver={(): void => setLocalHover(true)}
|
||||||
onMouseOut={(): void => setLocalHover(false)}
|
onMouseOut={(): void => setLocalHover(false)}
|
||||||
hover={localHover}
|
hover={localHover}
|
||||||
|
onClick={onClickHandler}
|
||||||
>
|
>
|
||||||
<HeaderContentContainer onClick={(e): void => e.preventDefault()}>
|
<HeaderContentContainer>
|
||||||
<Typography.Text style={{ maxWidth: '80%' }} ellipsis>
|
<Typography.Text style={{ maxWidth: '80%' }} ellipsis>
|
||||||
{title}
|
{title}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
@ -133,6 +168,7 @@ function WidgetHeader({
|
|||||||
</ArrowContainer>
|
</ArrowContainer>
|
||||||
</HeaderContentContainer>
|
</HeaderContentContainer>
|
||||||
</HeaderContainer>
|
</HeaderContainer>
|
||||||
|
</Dropdown>
|
||||||
{queryResponse.isFetching && !queryResponse.isError && (
|
{queryResponse.isFetching && !queryResponse.isError && (
|
||||||
<Spinner height="5vh" style={spinnerStyles} />
|
<Spinner height="5vh" style={spinnerStyles} />
|
||||||
)}
|
)}
|
||||||
@ -141,8 +177,7 @@ function WidgetHeader({
|
|||||||
<ExclamationCircleOutlined style={tooltipStyles} />
|
<ExclamationCircleOutlined style={tooltipStyles} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
</Dropdown>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import { grey } from '@ant-design/colors';
|
import { grey } from '@ant-design/colors';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const MenuItemContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const HeaderContainer = styled.div<{ hover: boolean }>`
|
export const HeaderContainer = styled.div<{ hover: boolean }>`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -47,6 +47,11 @@ function SearchFields({
|
|||||||
}
|
}
|
||||||
}, [parsedQuery]);
|
}, [parsedQuery]);
|
||||||
|
|
||||||
|
const updateFieldsQuery = (updated: QueryFields[][]): void => {
|
||||||
|
setFieldsQuery(updated);
|
||||||
|
keyPrefixRef.current = hashCode(JSON.stringify(updated));
|
||||||
|
};
|
||||||
|
|
||||||
const addSuggestedField = useCallback(
|
const addSuggestedField = useCallback(
|
||||||
(name: string): void => {
|
(name: string): void => {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@ -97,7 +102,7 @@ function SearchFields({
|
|||||||
keyPrefix={keyPrefixRef.current}
|
keyPrefix={keyPrefixRef.current}
|
||||||
onDropDownToggleHandler={onDropDownToggleHandler}
|
onDropDownToggleHandler={onDropDownToggleHandler}
|
||||||
fieldsQuery={fieldsQuery}
|
fieldsQuery={fieldsQuery}
|
||||||
setFieldsQuery={setFieldsQuery}
|
setFieldsQuery={updateFieldsQuery}
|
||||||
/>
|
/>
|
||||||
<SearchFieldsActionBar
|
<SearchFieldsActionBar
|
||||||
applyUpdate={applyUpdate}
|
applyUpdate={applyUpdate}
|
||||||
|
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useCopyToClipboard } from 'react-use';
|
import { useCopyToClipboard } from 'react-use';
|
||||||
import { DashboardData } from 'types/api/dashboard/getAll';
|
import { DashboardData } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
import { downloadObjectAsJson } from './util';
|
import { cleardQueryData, downloadObjectAsJson } from './util';
|
||||||
|
|
||||||
function ShareModal({
|
function ShareModal({
|
||||||
isJSONModalVisible,
|
isJSONModalVisible,
|
||||||
@ -51,6 +51,7 @@ function ShareModal({
|
|||||||
}
|
}
|
||||||
}, [state.error, state.value, t]);
|
}, [state.error, state.value, t]);
|
||||||
|
|
||||||
|
const selectedDataCleaned = cleardQueryData(selectedData);
|
||||||
const GetFooterComponent = useMemo(() => {
|
const GetFooterComponent = useMemo(() => {
|
||||||
if (!isViewJSON) {
|
if (!isViewJSON) {
|
||||||
return (
|
return (
|
||||||
@ -66,7 +67,7 @@ function ShareModal({
|
|||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
downloadObjectAsJson(selectedData, selectedData.title);
|
downloadObjectAsJson(selectedDataCleaned, selectedData.title);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('download_json')}
|
{t('download_json')}
|
||||||
@ -79,7 +80,7 @@ function ShareModal({
|
|||||||
{t('copy_to_clipboard')}
|
{t('copy_to_clipboard')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}, [isViewJSON, jsonValue, selectedData, setCopy, t]);
|
}, [isViewJSON, jsonValue, selectedData, selectedDataCleaned, setCopy, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { DashboardData } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
export function downloadObjectAsJson(
|
export function downloadObjectAsJson(
|
||||||
exportObj: unknown,
|
exportObj: unknown,
|
||||||
exportName: string,
|
exportName: string,
|
||||||
@ -12,3 +14,18 @@ export function downloadObjectAsJson(
|
|||||||
downloadAnchorNode.click();
|
downloadAnchorNode.click();
|
||||||
downloadAnchorNode.remove();
|
downloadAnchorNode.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cleardQueryData(param: DashboardData): DashboardData {
|
||||||
|
return {
|
||||||
|
...param,
|
||||||
|
widgets: param.widgets?.map((widget) => ({
|
||||||
|
...widget,
|
||||||
|
queryData: {
|
||||||
|
...widget.queryData,
|
||||||
|
data: {
|
||||||
|
queryData: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -37,8 +37,11 @@ function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
|
|||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
const isDisabled = useMemo(
|
const isDisabled = useMemo(
|
||||||
() => disabled || globalTime.isAutoRefreshDisabled,
|
() =>
|
||||||
[globalTime.isAutoRefreshDisabled, disabled],
|
disabled ||
|
||||||
|
globalTime.isAutoRefreshDisabled ||
|
||||||
|
globalTime.selectedTime === 'custom',
|
||||||
|
[globalTime.isAutoRefreshDisabled, disabled, globalTime.selectedTime],
|
||||||
);
|
);
|
||||||
|
|
||||||
const localStorageData = JSON.parse(get(DASHBOARD_TIME_IN_DURATION) || '{}');
|
const localStorageData = JSON.parse(get(DASHBOARD_TIME_IN_DURATION) || '{}');
|
||||||
@ -132,6 +135,11 @@ function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
|
|||||||
[localStorageData, pathname],
|
[localStorageData, pathname],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (globalTime.selectedTime === 'custom') {
|
||||||
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
placement="bottomLeft"
|
placement="bottomLeft"
|
||||||
|
@ -88,6 +88,14 @@ function DateTimeSelection({
|
|||||||
return timeInterval;
|
return timeInterval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedTime === 'custom') {
|
||||||
|
setRefreshButtonHidden(true);
|
||||||
|
} else {
|
||||||
|
setRefreshButtonHidden(false);
|
||||||
|
}
|
||||||
|
}, [selectedTime]);
|
||||||
|
|
||||||
const getDefaultTime = (pathName: string): Time => {
|
const getDefaultTime = (pathName: string): Time => {
|
||||||
const defaultSelectedOption = getDefaultOption(pathName);
|
const defaultSelectedOption = getDefaultOption(pathName);
|
||||||
|
|
||||||
|
@ -11104,6 +11104,11 @@ react-i18next@^11.16.1:
|
|||||||
"@babel/runtime" "^7.14.5"
|
"@babel/runtime" "^7.14.5"
|
||||||
html-parse-stringify "^3.0.1"
|
html-parse-stringify "^3.0.1"
|
||||||
|
|
||||||
|
react-intersection-observer@9.4.1:
|
||||||
|
version "9.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz#4ccb21e16acd0b9cf5b28d275af7055bef878f6b"
|
||||||
|
integrity sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==
|
||||||
|
|
||||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
|
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user