Compare commits

...

2 Commits

Author SHA1 Message Date
Yunus M
9c4046d84a fix: revert the resizeable quick filter changes (#12058) 2026-07-09 19:00:19 +00:00
Vikrant Gupta
a91cee2b95 chore(sql): enable txlock immediate by default (#12048)
* chore(sql): enable txlock immediate by default

* chore(sql): remove the redundant flag from integration tests
2026-07-09 16:05:13 +00:00
28 changed files with 120 additions and 800 deletions

View File

@@ -129,7 +129,7 @@ sqlstore:
# The timeout for the sqlite database to wait for a lock.
busy_timeout: 10s
# The default transaction locking behavior. Supported values: deferred, immediate, exclusive.
transaction_mode: deferred
transaction_mode: immediate
##################### APIServer #####################
apiserver:

View File

@@ -31,12 +31,6 @@ export enum LOCALSTORAGE {
METRICS_LIST_OPTIONS = 'METRICS_LIST_OPTIONS',
SHOW_EXCEPTIONS_QUICK_FILTERS = 'SHOW_EXCEPTIONS_QUICK_FILTERS',
QUICK_FILTERS_SETTINGS_ANNOUNCEMENT = 'QUICK_FILTERS_SETTINGS_ANNOUNCEMENT',
QUICK_FILTERS_WIDTH_LOGS = 'QUICK_FILTERS_WIDTH_LOGS',
QUICK_FILTERS_WIDTH_TRACES = 'QUICK_FILTERS_WIDTH_TRACES',
QUICK_FILTERS_WIDTH_METER = 'QUICK_FILTERS_WIDTH_METER',
QUICK_FILTERS_WIDTH_API_MONITORING = 'QUICK_FILTERS_WIDTH_API_MONITORING',
QUICK_FILTERS_WIDTH_EXCEPTIONS = 'QUICK_FILTERS_WIDTH_EXCEPTIONS',
QUICK_FILTERS_WIDTH_INFRA = 'QUICK_FILTERS_WIDTH_INFRA',
FUNNEL_STEPS = 'FUNNEL_STEPS',
SPAN_DETAILS_PINNED_ATTRIBUTES = 'SPAN_DETAILS_PINNED_ATTRIBUTES',
LAST_USED_CUSTOM_TIME_RANGES = 'LAST_USED_CUSTOM_TIME_RANGES',

View File

@@ -163,23 +163,12 @@
}
&.filter-visible {
// Width is owned by ResizableBox (inline style); this section is the
// ResizableBox root, so it stays position: relative for the drag handle.
.api-quick-filter-left-section {
.resizable-box__content {
display: flex;
flex-direction: column;
}
.quick-filters-container {
flex: 1;
min-height: 0;
}
width: 260px;
}
.api-module-right-section {
flex: 1;
min-width: 0;
width: calc(100% - 260px);
}
}
}

View File

@@ -4,49 +4,21 @@ import logEvent from 'api/common/logEvent';
import cx from 'classnames';
import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource, SignalType } from 'components/QuickFilters/types';
import { LOCALSTORAGE } from 'constants/localStorage';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import DomainList from './Domains/DomainList';
import './Explorer.styles.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 260;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function Explorer(): JSX.Element {
useEffect(() => {
logEvent('API Monitoring: Landing page visited', {});
}, []);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_API_MONITORING,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
return (
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
<div className={cx('api-monitoring-page', 'filter-visible')}>
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className="api-quick-filter-left-section"
handleTestId="quick-filters-resize-handle"
>
<section className="api-quick-filter-left-section">
<QuickFilters
className="qf-api-monitoring"
source={QuickFiltersSource.API_MONITORING}
@@ -55,7 +27,7 @@ function Explorer(): JSX.Element {
showQueryName={false}
handleFilterVisibilityChange={(): void => {}}
/>
</ResizableBox>
</section>
<DomainList />
</div>
</Sentry.ErrorBoundary>

View File

@@ -6,7 +6,6 @@ import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource } from 'components/QuickFilters/types';
import { InfraMonitoringEvents } from 'constants/events';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import K8sBaseDetails from 'container/InfraMonitoringK8s/Base/K8sBaseDetails';
import { K8sBaseList } from 'container/InfraMonitoringK8s/Base/K8sBaseList';
import { K8sBaseFilters } from 'container/InfraMonitoringK8s/Base/types';
@@ -17,8 +16,6 @@ import {
} from 'container/InfraMonitoringK8s/hooks';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { useAppContext } from 'providers/App/App';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@@ -43,21 +40,8 @@ import { getHostsQuickFiltersConfig } from './utils';
import styles from './InfraMonitoringHosts.module.scss';
import { ArrowUpToLine, Filter } from '@signozhq/icons';
const QUICK_FILTERS_DEFAULT_WIDTH = 280;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function Hosts(): JSX.Element {
const [showFilters, setShowFilters] = useState(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_INFRA,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const [, setCurrentPage] = useInfraMonitoringPageListing();
const [urlFilters, setUrlFilters] = useInfraMonitoringFiltersK8s();
@@ -155,18 +139,7 @@ function Hosts(): JSX.Element {
<div className={styles.infraMonitoringContainer}>
<div className={styles.infraContentRow}>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className={styles.quickFiltersContainer}
handleTestId="quick-filters-resize-handle"
>
<div className={styles.quickFiltersContainer}>
<div className={styles.quickFiltersContainerHeader}>
<Typography.Text>Filters</Typography.Text>
<Tooltip title="Collapse Filters">
@@ -183,7 +156,7 @@ function Hosts(): JSX.Element {
handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleQuickFiltersChange}
/>
</ResizableBox>
</div>
)}
<div
className={`${styles.listContainer}${

View File

@@ -44,20 +44,26 @@
}
.quickFiltersContainer {
// Width is owned by ResizableBox (inline style). No overflow here: the panel
// must not scroll (QuickFilters scrolls its own list internally) — an
// overflow on the root would also clip the edge-mounted resize grip.
flex-shrink: 0;
width: 280px;
min-width: 280px;
border-right: 1px solid var(--l1-border);
overflow-y: auto;
:global(.resizable-box__content) {
display: flex;
flex-direction: column;
&::-webkit-scrollbar {
width: 0.1rem;
height: 0.1rem;
}
:global(.quick-filters-container) {
flex: 1;
min-height: 0;
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--accent-primary);
}
&::-webkit-scrollbar-thumb:hover {
background: colox-mix(var(--accent-primary), var(--bg-vanilla-100), 20%);
}
:global(.ant-collapse-header) {
@@ -136,9 +142,7 @@
}
.listContainerFiltersVisible {
// Width is driven by flex now that the filters panel is resizable; the list
// fills whatever space the (variable-width) panel leaves.
max-width: 100%;
max-width: calc(100% - 280px);
}
.quickFiltersToggleContainer {

View File

@@ -6,7 +6,6 @@ import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource } from 'components/QuickFilters/types';
import { InfraMonitoringEvents } from 'constants/events';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import K8sBaseDetails from 'container/InfraMonitoringK8sV2/Base/K8sBaseDetails';
import { K8sBaseList } from 'container/InfraMonitoringK8sV2/Base/K8sBaseList';
import { K8sBaseFilters } from 'container/InfraMonitoringK8sV2/Base/types';
@@ -17,8 +16,6 @@ import {
} from 'container/InfraMonitoringK8sV2/hooks';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { useAppContext } from 'providers/App/App';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@@ -43,21 +40,8 @@ import { getHostsQuickFiltersConfig } from './utils';
import styles from './InfraMonitoringHosts.module.scss';
import { ArrowUpToLine, Filter } from '@signozhq/icons';
const QUICK_FILTERS_DEFAULT_WIDTH = 280;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function Hosts(): JSX.Element {
const [showFilters, setShowFilters] = useState(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_INFRA,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const [, setCurrentPage] = useInfraMonitoringPageListing();
const [urlFilters, setUrlFilters] = useInfraMonitoringFiltersK8s();
@@ -155,18 +139,7 @@ function Hosts(): JSX.Element {
<div className={styles.infraMonitoringContainer}>
<div className={styles.infraContentRow}>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className={styles.quickFiltersContainer}
handleTestId="quick-filters-resize-handle"
>
<div className={styles.quickFiltersContainer}>
<div className={styles.quickFiltersContainerHeader}>
<Typography.Text>Filters</Typography.Text>
<Tooltip title="Collapse Filters">
@@ -183,7 +156,7 @@ function Hosts(): JSX.Element {
handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleQuickFiltersChange}
/>
</ResizableBox>
</div>
)}
<div
className={`${styles.listContainer}${

View File

@@ -44,20 +44,26 @@
}
.quickFiltersContainer {
// Width is owned by ResizableBox (inline style). No overflow here: the panel
// must not scroll (QuickFilters scrolls its own list internally) — an
// overflow on the root would also clip the edge-mounted resize grip.
flex-shrink: 0;
width: 280px;
min-width: 280px;
border-right: 1px solid var(--l1-border);
overflow-y: auto;
:global(.resizable-box__content) {
display: flex;
flex-direction: column;
&::-webkit-scrollbar {
width: 0.1rem;
height: 0.1rem;
}
:global(.quick-filters-container) {
flex: 1;
min-height: 0;
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--accent-primary);
}
&::-webkit-scrollbar-thumb:hover {
background: colox-mix(var(--accent-primary), var(--bg-vanilla-100), 20%);
}
:global(.ant-collapse-header) {
@@ -136,9 +142,7 @@
}
.listContainerFiltersVisible {
// Width is driven by flex now that the filters panel is resizable; the list
// fills whatever space the (variable-width) panel leaves.
max-width: 100%;
max-width: calc(100% - 280px);
}
.quickFiltersToggleContainer {

View File

@@ -44,15 +44,26 @@
}
.quickFiltersContainer {
// Width is owned by ResizableBox (inline style). No overflow here: the panel
// must not scroll (QuickFilters scrolls its own list internally) — an
// overflow on the root would also clip the edge-mounted resize grip.
flex-shrink: 0;
width: 280px;
min-width: 280px;
border-right: 1px solid var(--l1-border);
overflow-y: auto;
:global(.resizable-box__content) {
display: flex;
flex-direction: column;
&::-webkit-scrollbar {
width: 0.1rem;
height: 0.1rem;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--accent-primary);
}
&::-webkit-scrollbar-thumb:hover {
background: colox-mix(var(--accent-primary), var(--bg-vanilla-100), 20%);
}
:global(.quick-filters) {
@@ -117,9 +128,7 @@
}
.listContainerFiltersVisible {
// Width is driven by flex now that the filters panel is resizable; the list
// fills whatever space the (variable-width) panel leaves.
max-width: 100%;
max-width: calc(100% - 280px);
}
.categorySelectorSection {
@@ -210,16 +219,8 @@
.quickFiltersSection {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow-y: auto;
:global(.quick-filters-container) {
flex: 1;
min-height: 0;
}
&::-webkit-scrollbar {
width: 0.1rem;
}

View File

@@ -6,7 +6,6 @@ import logEvent from 'api/common/logEvent';
import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource } from 'components/QuickFilters/types';
import { InfraMonitoringEvents } from 'constants/events';
import { LOCALSTORAGE } from 'constants/localStorage';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import {
@@ -23,8 +22,6 @@ import {
Workflow,
} from '@signozhq/icons';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { FeatureKeys } from '../../constants/features';
@@ -59,23 +56,9 @@ import K8sVolumesList from './Volumes/K8sVolumesList';
import styles from './InfraMonitoringK8s.module.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 280;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
export default function InfraMonitoringK8s(): JSX.Element {
const [showFilters, setShowFilters] = useState(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_INFRA,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const [selectedCategory, setSelectedCategory] = useInfraMonitoringCategory();
const [urlFilters, setUrlFilters] = useInfraMonitoringFiltersK8s();
const [, setGroupBy] = useInfraMonitoringGroupBy();
@@ -229,18 +212,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
<div className={styles.infraMonitoringContainer}>
<div className={styles.infraContentRow}>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className={styles.quickFiltersContainer}
handleTestId="quick-filters-resize-handle"
>
<div className={styles.quickFiltersContainer}>
<div className={styles.categorySelectorSection}>
<div className={styles.sectionHeader} data-type="resource">
<Typography.Text className={styles.sectionLabel}>
@@ -293,7 +265,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
/>
)}
</div>
</ResizableBox>
</div>
)}
<div

View File

@@ -44,15 +44,26 @@
}
.quickFiltersContainer {
// Width is owned by ResizableBox (inline style). No overflow here: the panel
// must not scroll (QuickFilters scrolls its own list internally) — an
// overflow on the root would also clip the edge-mounted resize grip.
flex-shrink: 0;
width: 280px;
min-width: 280px;
border-right: 1px solid var(--l1-border);
overflow-y: auto;
:global(.resizable-box__content) {
display: flex;
flex-direction: column;
&::-webkit-scrollbar {
width: 0.1rem;
height: 0.1rem;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--accent-primary);
}
&::-webkit-scrollbar-thumb:hover {
background: colox-mix(var(--accent-primary), var(--bg-vanilla-100), 20%);
}
:global(.quick-filters) {
@@ -117,9 +128,7 @@
}
.listContainerFiltersVisible {
// Width is driven by flex now that the filters panel is resizable; the list
// fills whatever space the (variable-width) panel leaves.
max-width: 100%;
max-width: calc(100% - 280px);
}
.categorySelectorSection {
@@ -210,16 +219,8 @@
.quickFiltersSection {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow-y: auto;
:global(.quick-filters-container) {
flex: 1;
min-height: 0;
}
&::-webkit-scrollbar {
width: 0.1rem;
}

View File

@@ -6,7 +6,6 @@ import logEvent from 'api/common/logEvent';
import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource } from 'components/QuickFilters/types';
import { InfraMonitoringEvents } from 'constants/events';
import { LOCALSTORAGE } from 'constants/localStorage';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import {
@@ -23,8 +22,6 @@ import {
Workflow,
} from '@signozhq/icons';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { FeatureKeys } from '../../constants/features';
@@ -59,23 +56,9 @@ import K8sVolumesList from './Volumes/K8sVolumesList';
import styles from './InfraMonitoringK8s.module.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 280;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
export default function InfraMonitoringK8s(): JSX.Element {
const [showFilters, setShowFilters] = useState(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_INFRA,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const [selectedCategory, setSelectedCategory] = useInfraMonitoringCategory();
const [urlFilters, setUrlFilters] = useInfraMonitoringFiltersK8s();
const [, setGroupBy] = useInfraMonitoringGroupBy();
@@ -229,18 +212,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
<div className={styles.infraMonitoringContainer}>
<div className={styles.infraContentRow}>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className={styles.quickFiltersContainer}
handleTestId="quick-filters-resize-handle"
>
<div className={styles.quickFiltersContainer}>
<div className={styles.categorySelectorSection}>
<div className={styles.sectionHeader} data-type="resource">
<Typography.Text className={styles.sectionLabel}>
@@ -293,7 +265,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
/>
)}
</div>
</ResizableBox>
</div>
)}
<div

View File

@@ -3,23 +3,12 @@
flex-direction: row;
.meter-explorer-quick-filters-section {
// Width is owned by ResizableBox (inline style).
flex-shrink: 0;
width: 280px;
border-right: 1px solid var(--l1-border);
&.hidden {
display: none;
}
.resizable-box__content {
display: flex;
flex-direction: column;
}
.quick-filters-container {
flex: 1;
min-height: 0;
}
}
.meter-explorer-content-section {
@@ -97,9 +86,7 @@
&.quick-filters-open {
.meter-explorer-content-section {
flex: 1;
width: auto;
min-width: 0;
width: calc(100% - 280px);
}
}

View File

@@ -7,7 +7,6 @@ import cx from 'classnames';
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource, SignalType } from 'components/QuickFilters/types';
import { LOCALSTORAGE } from 'constants/localStorage';
import { initialQueryMeterWithType, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ExplorerOptionWrapper from 'container/ExplorerOptions/ExplorerOptionWrapper';
@@ -19,8 +18,6 @@ import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import { Filter } from '@signozhq/icons';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { Dashboard } from 'types/api/dashboard/getAll';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
@@ -33,10 +30,6 @@ import { splitQueryIntoOneChartPerQuery } from './utils';
import './Explorer.styles.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 280;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function Explorer(): JSX.Element {
const {
handleRunQuery,
@@ -62,16 +55,6 @@ function Explorer(): JSX.Element {
const [showQuickFilters, setShowQuickFilters] = useState(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_METER,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const defaultQuery = useMemo(
() =>
updateAllQueriesOperators(
@@ -144,19 +127,10 @@ function Explorer(): JSX.Element {
'quick-filters-open': showQuickFilters,
})}
>
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
<div
className={cx('meter-explorer-quick-filters-section', {
hidden: !showQuickFilters,
})}
handleTestId="quick-filters-resize-handle"
>
<QuickFilters
className="qf-meter-explorer"
@@ -168,7 +142,7 @@ function Explorer(): JSX.Element {
setShowQuickFilters(!showQuickFilters);
}}
/>
</ResizableBox>
</div>
<div className="meter-explorer-content-section">
<div className="meter-explorer-explore-content">

View File

@@ -20,23 +20,12 @@
}
&.filter-visible {
// Width is owned by ResizableBox (inline style); this section is the
// ResizableBox root, so it stays position: relative for the drag handle.
.all-errors-quick-filter-section {
.resizable-box__content {
display: flex;
flex-direction: column;
}
.quick-filters-container {
flex: 1;
min-height: 0;
}
width: 260px;
}
.all-errors-right-section {
flex: 1;
min-width: 0;
width: calc(100% - 260px);
}
}
}

View File

@@ -18,18 +18,12 @@ import Toolbar from 'container/Toolbar/Toolbar';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import history from 'lib/history';
import { isNull } from 'lodash-es';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { routes } from './config';
import { useAllErrorsQueryState } from './QueryStateContext';
import './AllErrors.styles.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 260;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function AllErrors(): JSX.Element {
const { pathname } = useLocation();
const { handleRunQuery } = useQueryBuilder();
@@ -61,38 +55,17 @@ function AllErrors(): JSX.Element {
setShowFilters((prev) => !prev);
};
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_EXCEPTIONS,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
return (
<div className={cx('all-errors-page', showFilters ? 'filter-visible' : '')}>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className="all-errors-quick-filter-section"
handleTestId="quick-filters-resize-handle"
>
<section className={cx('all-errors-quick-filter-section')}>
<QuickFilters
className="qf-exceptions"
source={QuickFiltersSource.EXCEPTIONS}
signal={SignalType.EXCEPTIONS}
handleFilterVisibilityChange={handleFilterVisibilityChange}
/>
</ResizableBox>
</section>
)}
<section
className={cx(

View File

@@ -41,18 +41,15 @@
}
&.filter-visible {
// Width is owned by ResizableBox (inline style); this section is the
// ResizableBox root, so it stays position: relative for the drag handle.
.log-quick-filter-left-section {
width: 260px;
height: 100%;
overflow: visible;
min-height: 0;
position: relative;
z-index: 2;
.resizable-box__content {
display: flex;
flex-direction: column;
}
display: flex;
flex-direction: column;
.quick-filters-container {
flex: 1;
@@ -61,9 +58,7 @@
}
.log-module-right-section {
flex: 1;
width: auto;
min-width: 0;
width: calc(100% - 260px);
}
}
}

View File

@@ -26,8 +26,6 @@ import {
import { useIsAIAssistantEnabled } from 'hooks/useIsAIAssistantEnabled';
import { defaultTo, isEmpty, isNull } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { EventSourceProvider } from 'providers/EventSource';
import { Warning } from 'types/api';
import { DataSource } from 'types/common/queryBuilder';
@@ -46,23 +44,9 @@ import { ExplorerViews } from './utils';
import './LogsExplorer.styles.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 260;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function LogsExplorer(): JSX.Element {
const [showLiveLogs, setShowLiveLogs] = useState<boolean>(false);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_LOGS,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
// Get panel type from URL
const panelTypesFromUrl = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
@@ -242,25 +226,14 @@ function LogsExplorer(): JSX.Element {
className={cx('logs-module-page', showFilters ? 'filter-visible' : '')}
>
{showFilters && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className="log-quick-filter-left-section"
handleTestId="quick-filters-resize-handle"
>
<section className={cx('log-quick-filter-left-section')}>
<QuickFilters
className="qf-logs-explorer"
signal={SignalType.LOGS}
source={QuickFiltersSource.LOGS_EXPLORER}
handleFilterVisibilityChange={handleFilterVisibilityChange}
/>
</ResizableBox>
</section>
)}
<section className={cx('log-module-right-section')}>
<Toolbar

View File

@@ -76,8 +76,7 @@
--input-focus-border-color: var(--internal-ant-border-color-hover);
.filter {
// Width is owned by ResizableBox (inline style).
flex-shrink: 0;
width: 260px;
height: 100%;
min-height: 100vh;
@@ -85,14 +84,9 @@
border: 1px solid var(--l1-border);
background-color: var(--l1-background);
.resizable-box__content {
display: flex;
flex-direction: column;
}
.quick-filters-container {
flex: 1;
min-height: 0;
> .ant-card-body {
padding: 0;
width: 258px;
}
}
@@ -107,8 +101,6 @@
border-color: var(--l1-border);
}
.trace-explorer.filters-expanded {
flex: 1;
width: auto;
min-width: 0;
width: calc(100% - 260px);
}
}

View File

@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useQueryClient } from 'react-query';
import { useSearchParams } from 'react-router-dom-v5-compat';
import * as Sentry from '@sentry/react';
import { Card } from 'antd';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
@@ -40,8 +41,6 @@ import { isEmpty } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { ExplorerViews } from 'pages/LogsExplorer/utils';
import { TOOLBAR_VIEWS } from 'pages/TracesExplorer/constants';
import { ResizableBox } from 'periscope/components/ResizableBox';
import usePanelWidth from 'periscope/components/ResizableBox/usePanelWidth';
import { Warning } from 'types/api';
import { Dashboard } from 'types/api/dashboard/getAll';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@@ -63,10 +62,6 @@ import TimeSeriesView from './TimeSeriesView';
import './TracesExplorer.styles.scss';
const QUICK_FILTERS_DEFAULT_WIDTH = 260;
const QUICK_FILTERS_MIN_WIDTH = 240;
const QUICK_FILTERS_MAX_WIDTH = 500;
function TracesExplorer(): JSX.Element {
const {
panelType,
@@ -122,16 +117,6 @@ function TracesExplorer(): JSX.Element {
const [warning, setWarning] = useState<Warning | undefined>();
const [isOpen, setOpen] = useState<boolean>(true);
const {
initialWidth: quickFiltersInitialWidth,
persistWidth: persistQuickFiltersWidth,
} = usePanelWidth({
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_TRACES,
defaultWidth: QUICK_FILTERS_DEFAULT_WIDTH,
minWidth: QUICK_FILTERS_MIN_WIDTH,
maxWidth: QUICK_FILTERS_MAX_WIDTH,
});
const defaultQuery = useMemo(
(): Query =>
updateAllQueriesOperators(
@@ -265,29 +250,16 @@ function TracesExplorer(): JSX.Element {
return (
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
<div className="trace-explorer-page">
{isOpen && (
<ResizableBox
handle="right"
defaultWidth={QUICK_FILTERS_DEFAULT_WIDTH}
initialWidth={quickFiltersInitialWidth}
minWidth={QUICK_FILTERS_MIN_WIDTH}
maxWidth={QUICK_FILTERS_MAX_WIDTH}
onResize={persistQuickFiltersWidth}
resetToDefaultOnDoubleClick
withHandle
className="filter"
handleTestId="quick-filters-resize-handle"
>
<QuickFilters
className="qf-traces-explorer"
source={QuickFiltersSource.TRACES_EXPLORER}
signal={SignalType.TRACES}
handleFilterVisibilityChange={(): void => {
setOpen(!isOpen);
}}
/>
</ResizableBox>
)}
<Card className="filter" hidden={!isOpen}>
<QuickFilters
className="qf-traces-explorer"
source={QuickFiltersSource.TRACES_EXPLORER}
signal={SignalType.TRACES}
handleFilterVisibilityChange={(): void => {
setOpen(!isOpen);
}}
/>
</Card>
<div
className={cx('trace-explorer', {
'filters-expanded': isOpen,

View File

@@ -1,5 +1,6 @@
.resizable-box {
position: relative;
overflow: hidden;
&--disabled {
flex: 1;
@@ -17,17 +18,6 @@
z-index: 10;
background: var(--l2-border);
// Extend the interactive area beyond the 1px visual line so the handle
// is easy to grab and double-click, without changing its appearance.
&::before {
content: '';
position: absolute;
top: -4px;
right: -4px;
bottom: -4px;
left: -4px;
}
&:hover,
&:active {
background: var(--primary);
@@ -65,29 +55,4 @@
right: 0;
}
}
// Visible grip indicator (opt-in via the `withHandle` prop). Purely visual —
// pointer events fall through to the handle so it still owns drag + reset.
&__grip {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 26px;
border: 1px solid var(--l2-border);
border-radius: 4px;
background: var(--l1-background);
color: var(--l2-foreground);
pointer-events: none;
}
&__handle:hover &__grip,
&__handle:active &__grip {
border-color: var(--primary);
color: var(--primary);
}
}

View File

@@ -1,4 +1,3 @@
import { GripVertical } from '@signozhq/icons';
import { useCallback, useRef, useState } from 'react';
import './ResizableBox.styles.scss';
@@ -12,28 +11,15 @@ export interface ResizableBoxProps {
// resize (width). Dragging the handle away from the content grows the box;
// dragging it toward the content shrinks it.
handle?: ResizableBoxHandle;
// Canonical default size, and the target that double-click reset restores to.
defaultHeight?: number;
minHeight?: number;
maxHeight?: number;
defaultWidth?: number;
minWidth?: number;
maxWidth?: number;
// Starting size when different from the default (e.g. a persisted value).
// Falls back to defaultWidth/defaultHeight when omitted, preserving the
// behavior of callers that don't opt in.
initialWidth?: number;
initialHeight?: number;
// When true, double-clicking the handle resets the size to
// defaultWidth/defaultHeight and fires onResize with that value.
resetToDefaultOnDoubleClick?: boolean;
// When true, renders a visible grip indicator on the handle so it is
// discoverable as a draggable affordance.
withHandle?: boolean;
onResize?: (size: number) => void;
disabled?: boolean;
className?: string;
handleTestId?: string;
}
function ResizableBox({
@@ -45,22 +31,13 @@ function ResizableBox({
defaultWidth = 200,
minWidth = 50,
maxWidth = Infinity,
initialWidth,
initialHeight,
resetToDefaultOnDoubleClick = false,
withHandle = false,
onResize,
disabled = false,
className,
handleTestId,
}: ResizableBoxProps): JSX.Element {
const isHorizontal = handle === 'left' || handle === 'right';
const isStartHandle = handle === 'top' || handle === 'left';
const [size, setSize] = useState(
isHorizontal
? (initialWidth ?? defaultWidth)
: (initialHeight ?? defaultHeight),
);
const [size, setSize] = useState(isHorizontal ? defaultWidth : defaultHeight);
const containerRef = useRef<HTMLDivElement>(null);
const handleMouseDown = useCallback(
@@ -106,21 +83,6 @@ function ResizableBox({
],
);
const handleDoubleClick = useCallback((): void => {
if (!resetToDefaultOnDoubleClick) {
return;
}
const nextSize = isHorizontal ? defaultWidth : defaultHeight;
setSize(nextSize);
onResize?.(nextSize);
}, [
resetToDefaultOnDoubleClick,
isHorizontal,
defaultWidth,
defaultHeight,
onResize,
]);
const containerStyle = disabled
? undefined
: isHorizontal
@@ -137,22 +99,7 @@ function ResizableBox({
style={containerStyle}
>
<div className="resizable-box__content">{children}</div>
{!disabled && (
<div
role="separator"
aria-orientation={isHorizontal ? 'vertical' : 'horizontal'}
className={handleClass}
onMouseDown={handleMouseDown}
onDoubleClick={handleDoubleClick}
data-testid={handleTestId}
>
{withHandle && (
<span className="resizable-box__grip">
<GripVertical size={12} />
</span>
)}
</div>
)}
{!disabled && <div className={handleClass} onMouseDown={handleMouseDown} />}
</div>
);
}

View File

@@ -1,137 +0,0 @@
import { fireEvent, render, screen } from '@testing-library/react';
import ResizableBox from '../ResizableBox';
const HANDLE_TEST_ID = 'resize-handle';
describe('ResizableBox', () => {
it('starts at defaultWidth when initialWidth is omitted', () => {
render(
<ResizableBox
handle="right"
defaultWidth={260}
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
const box = screen.getByTestId(HANDLE_TEST_ID).parentElement as HTMLElement;
expect(box.style.width).toBe('260px');
});
it('starts at initialWidth when provided', () => {
render(
<ResizableBox
handle="right"
defaultWidth={260}
initialWidth={340}
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
const box = screen.getByTestId(HANDLE_TEST_ID).parentElement as HTMLElement;
expect(box.style.width).toBe('340px');
});
it('resets to defaultWidth and fires onResize on double-click when enabled', () => {
const onResize = jest.fn();
render(
<ResizableBox
handle="right"
defaultWidth={260}
initialWidth={480}
onResize={onResize}
resetToDefaultOnDoubleClick
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
const handle = screen.getByTestId(HANDLE_TEST_ID);
const box = handle.parentElement as HTMLElement;
expect(box.style.width).toBe('480px');
fireEvent.doubleClick(handle);
expect(box.style.width).toBe('260px');
expect(onResize).toHaveBeenCalledWith(260);
});
it('does nothing on double-click when reset is not enabled', () => {
const onResize = jest.fn();
render(
<ResizableBox
handle="right"
defaultWidth={260}
initialWidth={480}
onResize={onResize}
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
const handle = screen.getByTestId(HANDLE_TEST_ID);
const box = handle.parentElement as HTMLElement;
fireEvent.doubleClick(handle);
expect(box.style.width).toBe('480px');
expect(onResize).not.toHaveBeenCalled();
});
it('renders a visible grip only when withHandle is set', () => {
const { rerender, container } = render(
<ResizableBox
handle="right"
defaultWidth={260}
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
expect(container.querySelector('.resizable-box__grip')).toBeNull();
rerender(
<ResizableBox
handle="right"
defaultWidth={260}
withHandle
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
expect(container.querySelector('.resizable-box__grip')).not.toBeNull();
});
it('clamps drag to maxWidth and reports the clamped size via onResize', () => {
const onResize = jest.fn();
render(
<ResizableBox
handle="right"
defaultWidth={260}
minWidth={240}
maxWidth={500}
onResize={onResize}
handleTestId={HANDLE_TEST_ID}
>
<div>content</div>
</ResizableBox>,
);
const handle = screen.getByTestId(HANDLE_TEST_ID);
const box = handle.parentElement as HTMLElement;
fireEvent.mouseDown(handle, { clientX: 0 });
fireEvent.mouseMove(document, { clientX: 1000 });
fireEvent.mouseUp(document);
expect(box.style.width).toBe('500px');
expect(onResize).toHaveBeenLastCalledWith(500);
});
});

View File

@@ -1,89 +0,0 @@
import { act, renderHook } from '@testing-library/react';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import { LOCALSTORAGE } from 'constants/localStorage';
import usePanelWidth from '../usePanelWidth';
jest.mock('api/browser/localstorage/get');
jest.mock('api/browser/localstorage/set');
const mockedGet = getLocalStorageKey as jest.MockedFunction<
typeof getLocalStorageKey
>;
const mockedSet = setLocalStorageKey as jest.MockedFunction<
typeof setLocalStorageKey
>;
const ARGS = {
storageKey: LOCALSTORAGE.QUICK_FILTERS_WIDTH_LOGS,
defaultWidth: 260,
minWidth: 240,
maxWidth: 500,
};
describe('usePanelWidth', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
it('returns defaultWidth when nothing is persisted', () => {
mockedGet.mockReturnValue(null);
const { result } = renderHook(() => usePanelWidth(ARGS));
expect(result.current.initialWidth).toBe(260);
});
it('returns the persisted width when present', () => {
mockedGet.mockReturnValue('340');
const { result } = renderHook(() => usePanelWidth(ARGS));
expect(result.current.initialWidth).toBe(340);
});
it('clamps an out-of-bounds persisted width on read', () => {
mockedGet.mockReturnValue('9999');
const { result } = renderHook(() => usePanelWidth(ARGS));
expect(result.current.initialWidth).toBe(500);
});
it('falls back to defaultWidth for an invalid persisted value', () => {
mockedGet.mockReturnValue('not-a-number');
const { result } = renderHook(() => usePanelWidth(ARGS));
expect(result.current.initialWidth).toBe(260);
});
it('persists a clamped width (debounced)', () => {
mockedGet.mockReturnValue(null);
const { result } = renderHook(() => usePanelWidth(ARGS));
act(() => {
result.current.persistWidth(320);
jest.advanceTimersByTime(200);
});
expect(mockedSet).toHaveBeenCalledWith(
LOCALSTORAGE.QUICK_FILTERS_WIDTH_LOGS,
'320',
);
});
it('clamps below-min widths before persisting', () => {
mockedGet.mockReturnValue(null);
const { result } = renderHook(() => usePanelWidth(ARGS));
act(() => {
result.current.persistWidth(10);
jest.advanceTimersByTime(200);
});
expect(mockedSet).toHaveBeenCalledWith(
LOCALSTORAGE.QUICK_FILTERS_WIDTH_LOGS,
'240',
);
});
});

View File

@@ -1,68 +0,0 @@
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import { LOCALSTORAGE } from 'constants/localStorage';
import debounce from 'lodash-es/debounce';
import { useCallback, useMemo, useRef } from 'react';
const PERSIST_DEBOUNCE_MS = 150;
interface UsePanelWidthArgs {
/** Per-page localStorage key the width is persisted under. */
storageKey: LOCALSTORAGE;
/** Canonical default width, used when nothing is persisted. */
defaultWidth: number;
minWidth: number;
maxWidth: number;
}
interface UsePanelWidthReturn {
/** Width to start from: the persisted value (clamped) or the default. */
initialWidth: number;
/** Clamp and persist a width. Debounced to avoid a write per mousemove. */
persistWidth: (width: number) => void;
}
const clamp = (value: number, min: number, max: number): number =>
Math.min(max, Math.max(min, value));
/**
* Per-page localStorage persistence for a resizable panel width. Mirrors the
* getLocalStorageKey/setLocalStorageKey idiom used for the trace span-details
* panel position. Pairs with ResizableBox: feed initialWidth into its
* initialWidth prop and persistWidth into its onResize.
*/
function usePanelWidth({
storageKey,
defaultWidth,
minWidth,
maxWidth,
}: UsePanelWidthArgs): UsePanelWidthReturn {
// Read once on mount. Kept in a ref so a re-render doesn't re-read storage.
const initialWidthRef = useRef<number | null>(null);
if (initialWidthRef.current === null) {
const stored = getLocalStorageKey(storageKey);
const parsed = stored !== null && stored !== '' ? Number(stored) : NaN;
initialWidthRef.current = Number.isFinite(parsed)
? clamp(parsed, minWidth, maxWidth)
: defaultWidth;
}
const debouncedWrite = useMemo(
() =>
debounce((width: number): void => {
setLocalStorageKey(storageKey, String(width));
}, PERSIST_DEBOUNCE_MS),
[storageKey],
);
const persistWidth = useCallback(
(width: number): void => {
debouncedWrite(clamp(width, minWidth, maxWidth));
},
[debouncedWrite, minWidth, maxWidth],
);
return { initialWidth: initialWidthRef.current, persistWidth };
}
export default usePanelWidth;

View File

@@ -60,7 +60,7 @@ func newConfig() factory.Config {
Path: "/var/lib/signoz/signoz.db",
Mode: "wal",
BusyTimeout: 10000 * time.Millisecond, // increasing the defaults from https://github.com/mattn/go-sqlite3/blob/master/sqlite3.go#L1098 because of transpilation from C to GO
TransactionMode: "deferred",
TransactionMode: "immediate",
},
}

View File

@@ -62,12 +62,6 @@ def pytest_addoption(parser: pytest.Parser):
default="delete",
help="sqlite mode",
)
parser.addoption(
"--sqlite-transaction-mode",
action="store",
default="deferred",
help="sqlite transaction mode",
)
parser.addoption(
"--postgres-version",
action="store",

View File

@@ -30,7 +30,6 @@ def sqlite(
assert result.fetchone()[0] == 1
mode = pytestconfig.getoption("--sqlite-mode")
transaction_mode = pytestconfig.getoption("--sqlite-transaction-mode")
return types.TestContainerSQL(
container=types.TestContainerDocker(
id="",
@@ -42,7 +41,6 @@ def sqlite(
"SIGNOZ_SQLSTORE_PROVIDER": "sqlite",
"SIGNOZ_SQLSTORE_SQLITE_PATH": str(path),
"SIGNOZ_SQLSTORE_SQLITE_MODE": mode,
"SIGNOZ_SQLSTORE_SQLITE_TRANSACTION__MODE": transaction_mode,
},
)