Compare commits

...

8 Commits

Author SHA1 Message Date
primus-bot[bot]
3080c3c493 chore(release): bump to v0.120.0 (#11052)
Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com>
2026-04-22 07:11:54 +00:00
Vinicius Lourenço
b0e9fbe24f test(organization-traces): try unflaky both tests (#11046)
* test(organization-traces): try unflaky both tests

* fix: improve test speeds

* fix: increase timeout

---------

Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
2026-04-22 07:11:25 +00:00
Abhi kumar
aeb71469d9 fix: minor tooltip css fix (#11053) 2026-04-22 07:04:29 +00:00
Ashwin Bhatkal
1ff9a748ee refactor: rename selectedDashboard to dashboardData (#11040)
Renames the `selectedDashboard` store field (and related setters/getters
`setSelectedDashboard`, `getSelectedDashboard`) to `dashboardData` across
the frontend. Also renames incidental locals (`updatedSelectedDashboard`,
`mockSelectedDashboard`, and the ExportPanel's local `selectedDashboardId`).
2026-04-22 05:58:21 +00:00
Yunus M
dfa8625e3d refactor: update styles and components for consistency and improved UI (#11043)
Some checks failed
build-staging / staging (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-04-21 19:58:42 +00:00
swapnil-signoz
a60f8551dd feat: adding missing AWS regions (#11039)
* feat: adding missing AWS regions

* feat: fe add new AWS regions for Mexico and Asia Pacific

* refactor: adding missing region in migration as well
2026-04-21 19:28:01 +00:00
Tushar Vats
e607908b29 fix: not_in expression in having input box (#11035)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* fix: not_in expression in having input box

* fix: revert spacing check
2026-04-21 17:05:35 +00:00
swapnil-signoz
210ac2e74b feat: adding migration AWS cloud integration regions config (#10983)
* feat: adding migration AWS cloud integration regions config

* refactor: removing raw queries

* refactor: using table expr for table name

* refactor: using updated AWS regions declaration

* refactor: cleanup

* refactor: update AWS region migration logic to use new configuration method

* refactor: adding aws regions in migration

---------

Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2026-04-21 16:53:55 +00:00
107 changed files with 708 additions and 1540 deletions

View File

@@ -190,7 +190,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.119.0
image: signoz/signoz:v0.120.0
ports:
- "8080:8080" # signoz port
# - "6060:6060" # pprof port
@@ -213,7 +213,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.144.2
image: signoz/signoz-otel-collector:v0.144.3
entrypoint:
- /bin/sh
command:
@@ -241,7 +241,7 @@ services:
replicas: 3
signoz-telemetrystore-migrator:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.144.2
image: signoz/signoz-otel-collector:v0.144.3
environment:
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster

View File

@@ -117,7 +117,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.119.0
image: signoz/signoz:v0.120.0
ports:
- "8080:8080" # signoz port
volumes:
@@ -139,7 +139,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.144.2
image: signoz/signoz-otel-collector:v0.144.3
entrypoint:
- /bin/sh
command:
@@ -167,7 +167,7 @@ services:
replicas: 3
signoz-telemetrystore-migrator:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:v0.144.2
image: signoz/signoz-otel-collector:v0.144.3
environment:
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster

View File

@@ -181,7 +181,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.119.0}
image: signoz/signoz:${VERSION:-v0.120.0}
container_name: signoz
ports:
- "8080:8080" # signoz port
@@ -204,7 +204,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.3}
container_name: signoz-otel-collector
entrypoint:
- /bin/sh
@@ -229,7 +229,7 @@ services:
- "4318:4318" # OTLP HTTP receiver
signoz-telemetrystore-migrator:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.3}
container_name: signoz-telemetrystore-migrator
environment:
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000

View File

@@ -109,7 +109,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.119.0}
image: signoz/signoz:${VERSION:-v0.120.0}
container_name: signoz
ports:
- "8080:8080" # signoz port
@@ -132,7 +132,7 @@ services:
retries: 3
otel-collector:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.3}
container_name: signoz-otel-collector
entrypoint:
- /bin/sh
@@ -157,7 +157,7 @@ services:
- "4318:4318" # OTLP HTTP receiver
signoz-telemetrystore-migrator:
!!merge <<: *db-depend
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.2}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.144.3}
container_name: signoz-telemetrystore-migrator
environment:
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000

View File

@@ -79,7 +79,7 @@ export function useNavigateToExplorer(): (
);
const { getUpdatedQuery } = useUpdatedQuery();
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const { notifications } = useNotifications();
return useCallback(
@@ -111,7 +111,7 @@ export function useNavigateToExplorer(): (
panelTypes: PANEL_TYPES.TIME_SERIES,
timePreferance: 'GLOBAL_TIME',
},
selectedDashboard,
dashboardData,
})
.then((query) => {
preparedQuery = query;
@@ -140,7 +140,7 @@ export function useNavigateToExplorer(): (
minTime,
maxTime,
getUpdatedQuery,
selectedDashboard,
dashboardData,
notifications,
],
);

View File

@@ -1,14 +1,8 @@
.download-popover {
.ant-popover-inner {
border-radius: 4px;
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
var(--l2-background) 0%,
var(--l3-background) 98.68%
);
background-color: var(--l2-background);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
padding: 0 8px 12px 8px;
margin: 6px 0;
}
@@ -19,7 +13,7 @@
.title {
display: flex;
color: var(--l3-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -38,7 +32,7 @@
flex-direction: column;
:global(.ant-radio-wrapper) {
color: var(--foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 13px;
}

View File

@@ -3,7 +3,8 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux'; // old code, TODO: fix this correctly
import { useCopyToClipboard, useLocation } from 'react-use';
import { Color, Spacing } from '@signozhq/design-tokens';
import { Button, Divider, Drawer, Radio, Tooltip, Typography } from 'antd';
import { Button } from '@signozhq/ui';
import { Divider, Drawer, Radio, Tooltip, Typography } from 'antd';
import type { RadioChangeEvent } from 'antd/lib';
import cx from 'classnames';
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
@@ -363,7 +364,9 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
icon={<ChevronUp size={14} />}
variant="outlined"
color="secondary"
prefix={<ChevronUp size={14} />}
className="log-arrow-btn log-arrow-btn-up"
disabled={isPrevDisabled}
onClick={(): void => handleNavigateLog({ direction: 'previous' })}
@@ -375,7 +378,9 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
icon={<ChevronDown size={14} />}
variant="outlined"
color="secondary"
prefix={<ChevronDown size={14} />}
className="log-arrow-btn log-arrow-btn-down"
disabled={isNextDisabled}
onClick={(): void => handleNavigateLog({ direction: 'next' })}
@@ -385,8 +390,10 @@ function LogDetailInner({
{showOpenInExplorerBtn && (
<div>
<Button
variant="outlined"
color="secondary"
prefix={<Compass size={16} />}
className="open-in-explorer-btn"
icon={<Compass size={16} />}
onClick={handleOpenInExplorer}
>
Open in Explorer
@@ -482,8 +489,10 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
className="action-btn"
icon={<Filter size={16} />}
variant="link"
color="secondary"
size="sm"
prefix={<Filter size={12} />}
onClick={handleFilterVisible}
/>
</Tooltip>
@@ -498,8 +507,10 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
className="action-btn"
icon={<Copy size={16} />}
variant="link"
color="secondary"
size="sm"
prefix={<Copy size={12} />}
onClick={selectedView === VIEW_TYPES.JSON ? handleJSONCopy : onLogCopy}
/>
</Tooltip>

View File

@@ -1,4 +1,5 @@
import { CSSProperties } from 'react';
import { Color } from '@signozhq/design-tokens';
import { TableProps } from 'antd';
export function getDefaultCellStyle(isDarkMode?: boolean): CSSProperties {
@@ -7,7 +8,7 @@ export function getDefaultCellStyle(isDarkMode?: boolean): CSSProperties {
paddingBottom: 6,
paddingRight: 8,
paddingLeft: 8,
color: isDarkMode ? 'var(--bg-vanilla-400)' : 'var(--bg-slate-400)',
color: isDarkMode ? Color.BG_VANILLA_100 : Color.BG_INK_400,
fontSize: '14px',
fontStyle: 'normal',
fontWeight: 400,

View File

@@ -1,3 +1,4 @@
import { Color } from '@signozhq/design-tokens';
import { FontSize } from 'container/OptionsMenu/types';
import styled from 'styled-components';
@@ -10,7 +11,7 @@ interface TableBodyContentProps {
export const TableBodyContent = styled.div<TableBodyContentProps>`
margin-bottom: 0;
color: ${(props): string =>
props.isDarkMode ? 'var(--bg-vanilla-400, #c0c1c3)' : 'var(--bg-slate-400)'};
props.isDarkMode ? Color.BG_VANILLA_100 : Color.BG_INK_400};
font-size: 14px;
font-style: normal;
font-weight: 400;

View File

@@ -33,8 +33,9 @@
display: flex;
align-items: center;
p {
margin-bottom: 0;
.timestamp-text {
color: var(--l1-foreground);
margin: 0 !important;
}
}

View File

@@ -123,7 +123,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
return {
children: (
<div className="table-timestamp">
<p className={cx('text', fontSize)}>{date}</p>
<p className={cx('timestamp-text text', fontSize)}>{date}</p>
</div>
),
};

View File

@@ -35,7 +35,7 @@
}
.text {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -93,7 +93,7 @@
gap: 12px;
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -139,7 +139,8 @@
line-height: 18px;
letter-spacing: 0.08em;
text-align: left;
color: var(--muted-foreground);
color: var(--l1-foreground);
}
.menu-items {
@@ -177,7 +178,7 @@
padding: 12px;
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -330,7 +331,7 @@
}
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -486,169 +487,3 @@
}
}
}
.lightMode {
.format-options-popover {
.ant-popover-inner {
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
.nested-menu-container {
.font-size-dropdown {
.back-btn {
.text {
color: var(--l2-background);
}
}
.content {
.option-btn {
.text {
color: var(--l2-background);
}
.text:hover {
color: var(--l3-background);
}
}
}
}
.add-new-column-container {
.add-new-column-header {
.title {
color: var(--l2-foreground);
}
}
.add-new-column-content {
.column-format-new-options {
.column-name {
color: var(--l2-background);
&.selected {
background-color: var(--l3-background);
}
}
}
.loading-container {
color: var(--l2-background);
}
}
}
.font-size-container {
.title {
color: var(--l2-foreground);
}
.value {
.font-value {
color: var(--l2-background);
}
}
}
.horizontal-line {
background: var(--l3-background);
}
.item-content {
.column-divider {
border-top: 2px solid var(--l1-border);
}
}
.max-lines-per-row {
.title {
color: var(--l2-foreground);
.lucide {
color: var(--l1-foreground);
}
}
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
.periscope-btn {
background: var(--l3-background);
}
}
}
.menu-container {
.title {
color: var(--l2-foreground);
}
.item {
.item-label {
color: var(--l2-background);
}
}
}
.selected-item-content-container {
.title {
color: var(--l2-foreground);
.lucide {
color: var(--l1-foreground);
}
}
.horizontal-line {
background: var(--l3-background);
}
.item-content {
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
.periscope-btn {
background: var(--l3-background);
}
}
.column-format,
.column-format-new-options {
.column-name {
color: var(--l1-foreground);
}
}
}
}
&.active {
.nested-menu-container {
backdrop-filter: blur(18px);
.item {
.item-label {
color: var(--l1-foreground);
}
}
}
.selected-item-content-container {
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
}
}
}
}
}
}

View File

@@ -50,8 +50,8 @@ const havingOperators = [
value: 'IN',
},
{
label: 'NOT_IN',
value: 'NOT_IN',
label: 'NOT IN',
value: 'NOT IN',
},
];
@@ -129,7 +129,7 @@ function HavingFilter({
const operator = havingOperators[j];
newOptions.push({
label: `${opt.func}(${opt.arg}) ${operator.label}`,
value: `${opt.func}(${opt.arg}) ${operator.label} `,
value: `${opt.func}(${opt.arg}) ${operator.value} `,
apply: (
view: EditorView,
completion: { label: string; value: string },

View File

@@ -87,8 +87,8 @@ jest.mock('hooks/useDarkMode', () => ({
}));
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): { selectedDashboard: undefined } => ({
selectedDashboard: undefined,
useDashboardStore: (): { dashboardData: undefined } => ({
dashboardData: undefined,
}),
}));

View File

@@ -11,6 +11,8 @@
&__title {
font-weight: 500;
font-size: 15px;
padding: 0;
margin: 0;
}
&__container {
@@ -19,7 +21,7 @@
background-color: var(--primary-background);
color: var(--primary-foreground);
border-radius: 8px;
padding: 16px;
padding: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
}
@@ -43,14 +45,23 @@
&__footer {
display: flex;
justify-content: flex-end;
}
&__button {
background: var(--secondary-background);
color: var(--secondary-foreground);
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
// TODO: Need to override the button styles for this component due to container styles.
// Fix - @aks07
&__button {
margin-top: 12px;
color: var(--base-black);
background-color: var(--base-white);
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: var(--base-white);
color: var(--bg-robin-500);
}
}
}
}

View File

@@ -1,7 +1,7 @@
import { useState } from 'react';
import { Button, Typography } from 'antd';
import { Button } from '@signozhq/ui';
import classNames from 'classnames';
import { X } from 'lucide-react';
import { Check, X } from 'lucide-react';
import './AnnouncementTooltip.styles.scss';
@@ -46,13 +46,12 @@ function AnnouncementTooltip({
className={classNames('announcement-tooltip__container', className)}
style={{
top: position.top,
left: position.left + 30,
left: position.left + 20,
}}
>
<div className="announcement-tooltip__header">
<Typography.Text className="announcement-tooltip__title">
{title}
</Typography.Text>
<p className="announcement-tooltip__title">{title}</p>
<X
size={18}
onClick={closeTooltip}
@@ -61,7 +60,13 @@ function AnnouncementTooltip({
</div>
<p className="announcement-tooltip__message">{message}</p>
<div className="announcement-tooltip__footer">
<Button onClick={closeTooltip} className="announcement-tooltip__button">
<Button
variant="solid"
color="primary"
onClick={closeTooltip}
prefix={<Check size={16} />}
className="announcement-tooltip__footer__button"
>
Okay
</Button>
</div>

View File

@@ -22,7 +22,7 @@
.domain-detail-drawer {
border-left: 1px solid var(--l1-border);
background: var(--l2-background);
background: var(--l2-background) !important;
box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2);
.ant-drawer-header {
@@ -309,16 +309,12 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background-color: var(--l2-background);
cursor: pointer;
}
.ant-table-tbody > tr:hover > td:has(.endpoint-name-value) {
background: color-mix(
in srgb,
var(--l1-foreground) 4%,
color-mix(in srgb, var(--l3-background) 60%, transparent)
);
background-color: var(--l2-background);
}
.ant-table-cell:first-child {
@@ -359,10 +355,6 @@
background: none;
}
.table-row-dark {
background: var(--l3-background);
}
.endpoint-name-value {
display: flex;
align-items: center;
@@ -536,7 +528,7 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background: color-mix(in srgb, var(--l1-background) 4%, transparent);
}
.ant-table-tbody > tr:hover > td:has(.status-code-value) {
@@ -586,7 +578,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.endpoint-name-value {
@@ -768,6 +760,7 @@
.dependent-services-container {
border-radius: 3px;
border: 1px solid var(--l1-border);
.ant-table {
.ant-table-thead > tr > th {
padding: 12px;
@@ -797,7 +790,7 @@
}
.ant-table-cell {
padding: 12px;
padding: 0px;
font-size: 13px;
line-height: 20px;
color: var(--l1-foreground);
@@ -812,13 +805,11 @@
.ant-table-cell:has(.top-services-item-latency) {
text-align: center;
opacity: 0.8;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
}
.ant-table-cell:has(.top-services-item-latency-title) {
text-align: center;
opacity: 0.8;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
}
.ant-table-tbody > tr:hover > td {
@@ -853,7 +844,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.ant-table-content {
@@ -911,7 +902,6 @@
}
.top-services-item-progress-bar {
background-color: var(--l1-border);
border-radius: 2px;
height: 100%;
position: absolute;
@@ -1027,213 +1017,3 @@
overflow-wrap: break-word;
}
}
.lightMode {
.domain-navigate-cta {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.domain-detail-drawer {
.endpoint-details-card,
.status-code-table-container,
.endpoint-details-filters-container,
.endpoint-details-filters-container-dropdown,
.ant-radio-button-wrapper,
.views-tabs-container,
.ant-btn-default.tab,
.tab::before,
.endpoint-meta-data-pill,
.endpoint-meta-data-label,
.endpoints-table-container,
.group-by-label,
.ant-select-selector,
.ant-drawer-header {
border-color: var(--l1-border) !important;
}
.views-tabs .tab::before {
background: var(--l3-background);
}
.title {
color: var(--l2-foreground);
}
.domain-detail-drawer__endpoint {
.ant-typography {
color: var(--l2-foreground);
background: transparent;
}
}
.radio-button {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.views-tabs {
.tab {
background: var(--l3-background);
}
.selected_view {
background: var(--l3-background);
}
.selected_view::before {
background: var(--l3-background);
border-left: 1px solid var(--l1-border);
}
}
}
.round-metric-tag {
color: var(--l1-foreground);
}
.group-by-container {
.group-by-label {
color: var(--l2-foreground);
}
}
.endpoints-table-container {
.ant-table {
.ant-table-cell {
color: var(--l1-foreground);
}
.table-row-light {
background: none;
}
.table-row-dark {
background: none;
}
.round-metric-tag {
color: var(--l1-foreground);
}
}
}
.endpoint-meta-data {
.endpoint-meta-data-pill {
.endpoint-meta-data-label {
color: var(--l2-foreground);
}
.endpoint-meta-data-value {
color: var(--l2-foreground);
}
}
}
.status-code-table-container {
.ant-table {
.ant-table-cell {
color: var(--l1-foreground);
}
.table-row-light {
background: none;
}
.table-row-dark {
background: none;
}
.round-metric-tag {
color: var(--l1-foreground);
}
}
}
.top-services-content {
border-color: var(--l1-border);
}
.dependent-services-container {
border: none;
padding: 10px 12px;
.top-services-item {
display: flex;
justify-content: space-between;
align-items: center;
.top-services-item-progress {
display: flex;
gap: 12px;
height: 34px;
width: 100%;
color: var(--l1-foreground);
padding: 0 12px;
margin-right: 12px;
align-items: center;
position: relative;
.top-services-item-key {
color: var(--l2-foreground);
}
.top-services-item-count {
background-color: var(--l3-background);
color: var(--l2-foreground);
}
.top-services-item-progress-bar {
background-color: var(--l2-background);
border: 1px solid var(--l1-border);
}
}
}
.ant-table {
.ant-table-thead > tr > th {
color: var(--l2-foreground);
}
.ant-table-cell {
color: var(--l2-foreground);
}
.ant-table-tbody > tr:hover > td {
background: var(--l2-background);
}
.table-row-dark {
background: var(--l3-background);
}
}
.top-services-item-percentage {
color: var(--l2-foreground);
}
.top-services-load-more {
color: var(--l2-foreground);
}
}
.error-state-container {
.error-state-content-wrapper {
.refresh-cta {
color: var(--l2-foreground);
border: 1px solid var(--l1-border);
}
}
}
.end-point-details-zero-state-wrapper {
.end-point-details-zero-state-content-wrapper {
.end-point-details-zero-state-text-content {
.title {
color: var(--l2-foreground);
}
.description {
color: var(--l1-foreground);
}
}
}
}
// Add border-bottom to table cells when pagination is not present
.ant-spin-container:not(:has(.ant-pagination)) .ant-table-cell {
border-bottom: 1px solid var(--l1-border) !important;
}
}

View File

@@ -71,7 +71,7 @@
}
.ant-table-thead > tr > th:has(.domain-list-name-col-header) {
background: color-mix(in srgb, var(--l3-background) 60%, transparent);
background: var(--l2-background);
}
.ant-table-cell {
@@ -83,7 +83,7 @@
}
.ant-table-cell:has(.domain-list-name-col-value) {
background: color-mix(in srgb, var(--l3-background) 60%, transparent);
background: var(--l2-background);
}
.round-metric-tag {
@@ -107,7 +107,7 @@
background: color-mix(
in srgb,
var(--l1-foreground) 4%,
color-mix(in srgb, var(--l3-background) 60%, transparent)
var(--l2-background)
);
}
@@ -147,7 +147,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.expanded-clickable-row {

View File

@@ -196,12 +196,12 @@ describe('Dashboard landing page actions header tests', () => {
(useLocation as jest.Mock).mockReturnValue(mockLocation);
useDashboardStore.setState({
selectedDashboard: (getDashboardById.data as unknown) as Dashboard,
dashboardData: (getDashboardById.data as unknown) as Dashboard,
layouts: [],
panelMap: {},
setPanelMap: jest.fn(),
setLayouts: jest.fn(),
setSelectedDashboard: jest.fn(),
setDashboardData: jest.fn(),
columnWidths: {},
});

View File

@@ -78,12 +78,12 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
(s) => s.setIsPanelTypeSelectionModalOpen,
);
const {
selectedDashboard,
dashboardData,
panelMap,
setPanelMap,
layouts,
setLayouts,
setSelectedDashboard,
setDashboardData,
} = useDashboardStore();
const isDashboardLocked = useDashboardStore(selectIsDashboardLocked);
@@ -98,10 +98,10 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
const isPublicDashboardEnabled = isCloudUser || isEnterpriseSelfHostedUser;
const selectedData = selectedDashboard
const selectedData = dashboardData
? {
...selectedDashboard.data,
uuid: selectedDashboard.id,
...dashboardData.data,
uuid: dashboardData.id,
}
: ({} as DashboardData);
const { dashboardVariables } = useDashboardVariables();
@@ -133,8 +133,8 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
let isAuthor = false;
if (selectedDashboard && user && user.email) {
isAuthor = selectedDashboard?.createdBy === user?.email;
if (dashboardData && user && user.email) {
isAuthor = dashboardData?.createdBy === user?.email;
}
let permissions: ComponentTypes[] = ['add_panel'];
@@ -146,7 +146,7 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
const { notifications } = useNotifications();
const userRole: ROLES | null =
selectedDashboard?.createdBy === user?.email
dashboardData?.createdBy === user?.email
? (USER_ROLES.AUTHOR as ROLES)
: user.role;
@@ -155,9 +155,9 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
const onEmptyWidgetHandler = useCallback(() => {
setIsPanelTypeSelectionModalOpen(true);
logEvent('Dashboard Detail: Add new panel clicked', {
dashboardId: selectedDashboard?.id,
dashboardName: selectedDashboard?.data.title,
numberOfPanels: selectedDashboard?.data.widgets?.length,
dashboardId: dashboardData?.id,
dashboardName: dashboardData?.data.title,
numberOfPanels: dashboardData?.data.widgets?.length,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [setIsPanelTypeSelectionModalOpen]);
@@ -168,14 +168,14 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
};
const onNameChangeHandler = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const updatedDashboard: Props = {
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
title: updatedTitle,
},
};
@@ -186,7 +186,7 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
});
setIsRenameDashboardOpen(false);
if (updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
}
},
onError: () => {
@@ -203,10 +203,10 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
// the context value is sometimes not available during the initial render
// due to which the updatedTitle is set to some previous value
useEffect(() => {
if (selectedDashboard) {
setUpdatedTitle(selectedDashboard.data.title);
if (dashboardData) {
setUpdatedTitle(dashboardData.data.title);
}
}, [selectedDashboard]);
}, [dashboardData]);
useEffect(() => {
if (state.error) {
@@ -227,7 +227,7 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
}, [state.error, state.value, t, notifications]);
function handleAddRow(): void {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const id = uuid();
@@ -246,10 +246,10 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
}
const updatedDashboard: Props = {
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
layout: [
{
i: id,
@@ -265,7 +265,7 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
],
panelMap: { ...panelMap, [id]: newRowWidgetMap },
widgets: [
...(selectedDashboard.data.widgets || []),
...(dashboardData.data.widgets || []),
{
id,
title: sectionName,
@@ -282,7 +282,7 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
if (updatedDashboard.data.data.layout) {
setLayouts(sortLayout(updatedDashboard.data.data.layout));
}
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
setPanelMap(updatedDashboard.data?.data?.panelMap || {});
}
@@ -299,8 +299,8 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
error: errorPublicDashboardData,
isError: isErrorPublicDashboardData,
} = useGetPublicDashboardMeta(
selectedDashboard?.id || '',
!!selectedDashboard?.id && isPublicDashboardEnabled,
dashboardData?.id || '',
!!dashboardData?.id && isPublicDashboardEnabled,
);
useEffect(() => {
@@ -378,14 +378,14 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
{(isAuthor || user.role === USER_ROLES.ADMIN) && (
<Tooltip
title={
selectedDashboard?.createdBy === 'integration' &&
dashboardData?.createdBy === 'integration' &&
'Dashboards created by integrations cannot be unlocked'
}
>
<Button
type="text"
icon={<LockKeyhole size={14} />}
disabled={selectedDashboard?.createdBy === 'integration'}
disabled={dashboardData?.createdBy === 'integration'}
onClick={handleLockDashboardToggle}
data-testid="lock-unlock-dashboard"
>
@@ -457,9 +457,9 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
</section>
<section className="delete-dashboard">
<DeleteButton
createdBy={selectedDashboard?.createdBy || ''}
name={selectedDashboard?.data.title || ''}
id={String(selectedDashboard?.id) || ''}
createdBy={dashboardData?.createdBy || ''}
name={dashboardData?.data.title || ''}
id={String(dashboardData?.id) || ''}
isLocked={isDashboardLocked}
routeToListPage
/>

View File

@@ -239,7 +239,7 @@ function VariableItem({
const [selectedWidgets, setSelectedWidgets] = useState<string[]>([]);
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const widgetsByDynamicVariableId = useWidgetsByDynamicVariableId();
useEffect(() => {
@@ -248,7 +248,7 @@ function VariableItem({
} else if (dynamicVariablesSelectedValue?.name) {
const widgets = getWidgetsHavingDynamicVariableAttribute(
dynamicVariablesSelectedValue?.name,
(selectedDashboard?.data?.widgets?.filter(
(dashboardData?.data?.widgets?.filter(
(widget) => widget.panelTypes !== PANEL_GROUP_TYPES.ROW,
) || []) as Widgets[],
variableData.name,
@@ -257,7 +257,7 @@ function VariableItem({
}
}, [
dynamicVariablesSelectedValue?.name,
selectedDashboard,
dashboardData,
variableData.id,
variableData.name,
widgetsByDynamicVariableId,

View File

@@ -12,17 +12,17 @@ export function WidgetSelector({
selectedWidgets: string[];
setSelectedWidgets: (widgets: string[]) => void;
}): JSX.Element {
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
// Get layout IDs for cross-referencing
const layoutIds = new Set(
(selectedDashboard?.data?.layout || []).map((item) => item.i),
(dashboardData?.data?.layout || []).map((item) => item.i),
);
// Filter and deduplicate widgets by ID, keeping only those with layout entries
// and excluding row widgets since they are not panels that can have variables
const widgets = Object.values(
(selectedDashboard?.data?.widgets || []).reduce(
(dashboardData?.data?.widgets || []).reduce(
(acc: Record<string, WidgetRow | Widgets>, widget: WidgetRow | Widgets) => {
if (
widget.id &&

View File

@@ -87,7 +87,7 @@ function VariablesSettings({
const { t } = useTranslation(['dashboard']);
const { selectedDashboard, setSelectedDashboard } = useDashboardStore();
const { dashboardData, setDashboardData } = useDashboardStore();
const { dashboardVariables } = useDashboardVariables();
const { notifications } = useNotifications();
@@ -173,7 +173,7 @@ function VariablesSettings({
widgetIds?: string[],
applyToAll?: boolean,
): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
@@ -181,16 +181,16 @@ function VariablesSettings({
(currentRequestedId &&
updatedVariablesData[currentRequestedId || '']?.type === 'DYNAMIC' &&
addDynamicVariableToPanels(
selectedDashboard,
dashboardData,
updatedVariablesData[currentRequestedId || ''],
widgetIds,
applyToAll,
)) ||
selectedDashboard;
dashboardData;
updateMutation.mutateAsync(
{
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...newDashboard.data,
@@ -200,7 +200,7 @@ function VariablesSettings({
{
onSuccess: (updatedDashboard) => {
if (updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
notifications.success({
message: t('variable_updated_successfully'),
});

View File

@@ -15,11 +15,11 @@ import './GeneralSettings.styles.scss';
const { Option } = Select;
function GeneralDashboardSettings(): JSX.Element {
const { selectedDashboard, setSelectedDashboard } = useDashboardStore();
const { dashboardData, setDashboardData } = useDashboardStore();
const updateDashboardMutation = useUpdateDashboard();
const selectedData = selectedDashboard?.data;
const selectedData = dashboardData?.data;
const { title = '', tags = [], description = '', image = Base64Icons[0] } =
selectedData || {};
@@ -37,15 +37,15 @@ function GeneralDashboardSettings(): JSX.Element {
const { t } = useTranslation('common');
const onSaveHandler = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
updateDashboardMutation.mutate(
{
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
description: updatedDescription,
tags: updatedTags,
title: updatedTitle,
@@ -55,7 +55,7 @@ function GeneralDashboardSettings(): JSX.Element {
{
onSuccess: (updatedDashboard) => {
if (updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
}
},
onError: () => {},

View File

@@ -41,7 +41,7 @@ const DASHBOARD_VARIABLES_WARNING =
// Use wildcard pattern to match both relative and absolute URLs in MSW
const publicDashboardURL = `*/api/v1/dashboards/${MOCK_DASHBOARD_ID}/public`;
const mockSelectedDashboard = {
const mockDashboardData = {
id: MOCK_DASHBOARD_ID,
data: {
title: 'Test Dashboard',
@@ -70,7 +70,7 @@ beforeEach(() => {
// Mock useDashboardStore
mockUseDashboard.mockReturnValue(({
selectedDashboard: mockSelectedDashboard,
dashboardData: mockDashboardData,
} as unknown) as ReturnType<typeof useDashboardStore>);
// Mock useCopyToClipboard

View File

@@ -59,7 +59,7 @@ function PublicDashboardSetting(): JSX.Element {
const [defaultTimeRange, setDefaultTimeRange] = useState(DEFAULT_TIME_RANGE);
const [, setCopyPublicDashboardURL] = useCopyToClipboard();
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const { isCloudUser, isEnterpriseSelfHostedUser } = useGetTenantLicense();
@@ -84,8 +84,8 @@ function PublicDashboardSetting(): JSX.Element {
refetch: refetchPublicDashboard,
error: errorPublicDashboard,
} = useGetPublicDashboardMeta(
selectedDashboard?.id || '',
!!selectedDashboard?.id && isPublicDashboardEnabled,
dashboardData?.id || '',
!!dashboardData?.id && isPublicDashboardEnabled,
);
const isPublicDashboard = !!publicDashboardData?.publicPath;
@@ -154,36 +154,36 @@ function PublicDashboardSetting(): JSX.Element {
});
const handleCreatePublicDashboard = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
createPublicDashboard({
dashboardId: selectedDashboard.id,
dashboardId: dashboardData.id,
timeRangeEnabled,
defaultTimeRange,
});
};
const handleUpdatePublicDashboard = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
updatePublicDashboard({
dashboardId: selectedDashboard.id,
dashboardId: dashboardData.id,
timeRangeEnabled,
defaultTimeRange,
});
};
const handleRevokePublicDashboardAccess = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
revokePublicDashboardAccess({
id: selectedDashboard.id,
id: dashboardData.id,
});
};

View File

@@ -26,10 +26,10 @@ import VariableItem from './VariableItem';
import './DashboardVariableSelection.styles.scss';
function DashboardVariableSelection(): JSX.Element | null {
const { dashboardId, setSelectedDashboard } = useDashboardStore(
const { dashboardId, setDashboardData } = useDashboardStore(
useShallow((s) => ({
dashboardId: s.selectedDashboard?.id ?? '',
setSelectedDashboard: s.setSelectedDashboard,
dashboardId: s.dashboardData?.id ?? '',
setDashboardData: s.setDashboardData,
})),
);
@@ -99,7 +99,7 @@ function DashboardVariableSelection(): JSX.Element | null {
// Synchronously update the external store with the new variable value so that
// child variables see the updated parent value when they refetch, rather than
// waiting for setSelectedDashboard → useEffect → updateDashboardVariablesStore.
// waiting for setDashboardData → useEffect → updateDashboardVariablesStore.
const updatedVariables = { ...dashboardVariables };
if (updatedVariables[id]) {
updatedVariables[id] = {
@@ -119,7 +119,7 @@ function DashboardVariableSelection(): JSX.Element | null {
}
updateDashboardVariablesStore({ dashboardId, variables: updatedVariables });
setSelectedDashboard((prev) => {
setDashboardData((prev) => {
if (prev) {
const oldVariables = { ...prev?.data.variables };
// this is added to handle case where we have two different
@@ -157,7 +157,7 @@ function DashboardVariableSelection(): JSX.Element | null {
// Safe to call synchronously now that the store already has the updated value.
enqueueDescendantsOfVariable(name);
},
[dashboardId, dashboardVariables, updateUrlVariable, setSelectedDashboard],
[dashboardId, dashboardVariables, updateUrlVariable, setDashboardData],
);
return (

View File

@@ -30,11 +30,11 @@ const mockVariableItemCallbacks: {
} = {};
// Mock providers/Dashboard/Dashboard
const mockSetSelectedDashboard = jest.fn();
const mockSetDashboardData = jest.fn();
const mockUpdateLocalStorageDashboardVariables = jest.fn();
interface MockDashboardStoreState {
selectedDashboard?: { id: string };
setSelectedDashboard: typeof mockSetSelectedDashboard;
dashboardData?: { id: string };
setDashboardData: typeof mockSetDashboardData;
updateLocalStorageDashboardVariables: typeof mockUpdateLocalStorageDashboardVariables;
}
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
@@ -42,8 +42,8 @@ jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
selector?: (s: Record<string, unknown>) => MockDashboardStoreState,
): MockDashboardStoreState => {
const state = {
selectedDashboard: { id: 'dash-1' },
setSelectedDashboard: mockSetSelectedDashboard,
dashboardData: { id: 'dash-1' },
setDashboardData: mockSetDashboardData,
updateLocalStorageDashboardVariables: mockUpdateLocalStorageDashboardVariables,
};
return selector ? selector(state) : state;

View File

@@ -38,15 +38,11 @@ interface UseDashboardVariableUpdateReturn {
}
export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn => {
const {
dashboardId,
selectedDashboard,
setSelectedDashboard,
} = useDashboardStore(
const { dashboardId, dashboardData, setDashboardData } = useDashboardStore(
useShallow((s) => ({
dashboardId: s.selectedDashboard?.id ?? '',
selectedDashboard: s.selectedDashboard,
setSelectedDashboard: s.setSelectedDashboard,
dashboardId: s.dashboardData?.id ?? '',
dashboardData: s.dashboardData,
setDashboardData: s.setDashboardData,
})),
);
const addDynamicVariableToPanels = useAddDynamicVariableToPanels();
@@ -74,8 +70,8 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
isDynamic,
);
if (selectedDashboard) {
setSelectedDashboard((prev) => {
if (dashboardData) {
setDashboardData((prev) => {
if (prev) {
const oldVariables = prev?.data.variables;
// this is added to handle case where we have two different
@@ -110,7 +106,7 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
}
}
},
[dashboardId, selectedDashboard, setSelectedDashboard],
[dashboardId, dashboardData, setDashboardData],
);
const updateVariables = useCallback(
@@ -120,23 +116,23 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
widgetIds?: string[],
applyToAll?: boolean,
): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const newDashboard =
(currentRequestedId &&
addDynamicVariableToPanels(
selectedDashboard,
dashboardData,
updatedVariablesData[currentRequestedId || ''],
widgetIds,
applyToAll,
)) ||
selectedDashboard;
dashboardData;
updateMutation.mutateAsync(
{
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...newDashboard.data,
@@ -146,7 +142,7 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
{
onSuccess: (updatedDashboard) => {
if (updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
// notifications.success({
// message: t('variable_updated_successfully'),
// });
@@ -155,12 +151,7 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
},
);
},
[
selectedDashboard,
addDynamicVariableToPanels,
updateMutation,
setSelectedDashboard,
],
[dashboardData, addDynamicVariableToPanels, updateMutation, setDashboardData],
);
const createVariable = useCallback(
@@ -172,13 +163,13 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
source: 'logs' | 'traces' | 'metrics' | 'all sources' = 'all sources',
// widgetId?: string,
): void => {
if (!selectedDashboard) {
if (!dashboardData) {
console.warn('No dashboard selected for variable creation');
return;
}
// Get current dashboard variables
const currentVariables = selectedDashboard.data.variables || {};
const currentVariables = dashboardData.data.variables || {};
// Create tableRowData like Dashboard Settings does
const tableRowData = [];
@@ -234,7 +225,7 @@ export const useDashboardVariableUpdate = (): UseDashboardVariableUpdateReturn =
const updatedVariables = convertVariablesToDbFormat(tableRowData);
updateVariables(updatedVariables, newVariable.id, [], false);
},
[selectedDashboard, updateVariables],
[dashboardData, updateVariables],
);
return {

View File

@@ -47,12 +47,12 @@ const mockDashboard = {
};
// Mock the dashboard provider with stable functions to prevent infinite loops
const mockSetSelectedDashboard = jest.fn();
const mockSetDashboardData = jest.fn();
const mockUpdateLocalStorageDashboardVariables = jest.fn();
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): any => ({
selectedDashboard: mockDashboard,
setSelectedDashboard: mockSetSelectedDashboard,
dashboardData: mockDashboard,
setDashboardData: mockSetDashboardData,
updateLocalStorageDashboardVariables: mockUpdateLocalStorageDashboardVariables,
}),
}));

View File

@@ -58,7 +58,7 @@ const mockDashboard = {
// Mock dependencies
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): any => ({
selectedDashboard: mockDashboard,
dashboardData: mockDashboard,
}),
}));
@@ -154,7 +154,7 @@ describe('Panel Management Tests', () => {
// Temporarily mock the dashboard
jest.doMock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): any => ({
selectedDashboard: modifiedDashboard,
dashboardData: modifiedDashboard,
}),
}));

View File

@@ -13,13 +13,13 @@ import './DashboardBreadcrumbs.styles.scss';
function DashboardBreadcrumbs(): JSX.Element {
const { safeNavigate } = useSafeNavigate();
const { selectedDashboard } = useDashboardStore();
const updatedAtRef = useRef(selectedDashboard?.updatedAt);
const { dashboardData } = useDashboardStore();
const updatedAtRef = useRef(dashboardData?.updatedAt);
const selectedData = selectedDashboard
const selectedData = dashboardData
? {
...selectedDashboard.data,
uuid: selectedDashboard.id,
...dashboardData.data,
uuid: dashboardData.id,
}
: ({} as DashboardData);
@@ -31,7 +31,7 @@ function DashboardBreadcrumbs(): JSX.Element {
);
const hasDashboardBeenUpdated =
selectedDashboard?.updatedAt !== updatedAtRef.current;
dashboardData?.updatedAt !== updatedAtRef.current;
if (!hasDashboardBeenUpdated && dashboardsListQueryParamsString) {
safeNavigate({
pathname: ROUTES.ALL_DASHBOARD,
@@ -40,7 +40,7 @@ function DashboardBreadcrumbs(): JSX.Element {
} else {
safeNavigate(ROUTES.ALL_DASHBOARD);
}
}, [safeNavigate, selectedDashboard?.updatedAt]);
}, [safeNavigate, dashboardData?.updatedAt]);
return (
<div className="dashboard-breadcrumbs">

View File

@@ -35,15 +35,15 @@ jest.mock('lib/uPlotV2/hooks/useLegendsSync', () => ({
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (
selector?: (s: {
selectedDashboard: { locked: boolean } | undefined;
}) => { selectedDashboard: { locked: boolean } },
): { selectedDashboard: { locked: boolean } } => {
const mockState = { selectedDashboard: { locked: false } };
dashboardData: { locked: boolean } | undefined;
}) => { dashboardData: { locked: boolean } },
): { dashboardData: { locked: boolean } } => {
const mockState = { dashboardData: { locked: false } };
return selector ? selector(mockState) : mockState;
},
selectIsDashboardLocked: (s: {
selectedDashboard: { locked: boolean } | undefined;
}): boolean => s.selectedDashboard?.locked ?? false,
dashboardData: { locked: boolean } | undefined;
}): boolean => s.dashboardData?.locked ?? false,
}));
jest.mock('hooks/useNotifications', () => ({

View File

@@ -98,27 +98,6 @@
align-items: center;
gap: 8px;
button {
display: flex;
justify-content: center;
align-items: center;
border: none;
border: 1px solid var(--l1-border);
box-shadow: none !important;
&.ant-btn-round {
padding: 8px 12px 8px 10px;
font-weight: 500;
}
&.ant-btn-round:disabled {
background-color: rgba(209, 209, 209, 0.074);
color: var(--muted-foreground);
}
}
.ant-select-focused {
border-color: transparent !important;
@@ -140,6 +119,12 @@
.hidden {
display: none;
}
button {
display: flex;
align-items: center;
justify-content: center;
}
}
.app-content {
@@ -233,19 +218,6 @@
justify-content: flex-end;
padding: 16px 16px;
margin: 0;
> button {
display: flex;
align-items: center;
border-radius: 2px;
background-color: var(--primary-background) !important;
color: var(--l1-foreground) !important;
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 24px;
}
}
}
.title {
@@ -257,97 +229,3 @@
line-height: 20px;
}
}
.lightMode {
.explorer-options-container {
background: var(--l1-background);
}
.explorer-options {
background: transparent;
box-shadow: none;
border: 1px solid var(--l1-border);
backdrop-filter: blur(20px);
hr {
border-color: var(--l1-border);
}
.view-options,
.actions {
button {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
background-color: var(--l3-background);
}
.info-icon {
color: var(--l2-foreground);
}
}
}
.render-options {
color: var(--l2-foreground);
}
.explorer-update {
border: 1px solid var(--l1-border);
background: transparent;
box-shadow: 4px 4px 16px 4px rgba(255, 255, 255, 0.55);
backdrop-filter: blur(20px);
.action-icon {
border: 1px solid var(--l1-border);
background: var(--l3-background);
}
.ant-divider {
border-color: var(--l1-border);
}
}
.ant-tooltip-arrow {
border-top-color: var(--l1-border) !important;
}
.ant-tooltip-inner {
background-color: var(--l3-background);
color: var(--l2-foreground);
}
.save-view-modal {
.ant-modal-content {
background: var(--l2-background);
border-color: var(--l1-border);
.ant-modal-header {
background: var(--l2-background);
border-bottom: 1px solid var(--l1-border);
}
.ant-modal-body {
.ant-typography {
color: var(--l2-foreground);
}
.ant-color-picker-trigger {
border: 1px solid var(--l1-border);
background: var(--l1-background);
.ant-color-picker-color-block {
.ant-color-picker-color-block-inner {
svg {
fill: var(--l2-foreground);
}
}
}
}
}
}
.title {
color: var(--l2-foreground);
}
}
}

View File

@@ -24,9 +24,7 @@ function ExportPanelContainer({
}: ExportPanelProps): JSX.Element {
const { t } = useTranslation(['dashboard']);
const [selectedDashboardId, setSelectedDashboardId] = useState<string | null>(
null,
);
const [dashboardId, setDashboardId] = useState<string | null>(null);
const {
data,
@@ -55,17 +53,17 @@ function ExportPanelContainer({
const handleExportClick = useCallback((): void => {
const currentSelectedDashboard = data?.data?.find(
({ id }) => id === selectedDashboardId,
({ id }) => id === dashboardId,
);
onExport(currentSelectedDashboard || null, false);
}, [data, selectedDashboardId, onExport]);
}, [data, dashboardId, onExport]);
const handleSelect = useCallback(
(selectedDashboardValue: string): void => {
setSelectedDashboardId(selectedDashboardValue);
(selectedDashboardId: string): void => {
setDashboardId(selectedDashboardId);
},
[setSelectedDashboardId],
[setDashboardId],
);
const handleNewDashboard = useCallback(async () => {
@@ -85,10 +83,7 @@ function ExportPanelContainer({
const isDashboardLoading = isAllDashboardsLoading || createDashboardLoading;
const isDisabled =
isAllDashboardsLoading ||
!options?.length ||
!selectedDashboardId ||
isLoading;
isAllDashboardsLoading || !options?.length || !dashboardId || isLoading;
return (
<Wrapper direction="vertical">
@@ -101,7 +96,7 @@ function ExportPanelContainer({
showSearch
loading={isDashboardLoading}
disabled={isDashboardLoading}
value={selectedDashboardId}
value={dashboardId}
onSelect={handleSelect}
filterOption={filterOptions}
/>

View File

@@ -27,7 +27,7 @@ export default function DashboardEmptyState(): JSX.Element {
(s) => s.setIsPanelTypeSelectionModalOpen,
);
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const isDashboardLocked = useDashboardStore(selectIsDashboardLocked);
const variablesSettingsTabHandle = useRef<VariablesSettingsTab>(null);
@@ -43,7 +43,7 @@ export default function DashboardEmptyState(): JSX.Element {
}
const userRole: ROLES | null =
selectedDashboard?.createdBy === user?.email
dashboardData?.createdBy === user?.email
? (USER_ROLES.AUTHOR as ROLES)
: user.role;
@@ -52,9 +52,9 @@ export default function DashboardEmptyState(): JSX.Element {
const onEmptyWidgetHandler = useCallback(() => {
setIsPanelTypeSelectionModalOpen(true);
logEvent('Dashboard Detail: Add new panel clicked', {
dashboardId: selectedDashboard?.id,
dashboardName: selectedDashboard?.data.title,
numberOfPanels: selectedDashboard?.data.widgets?.length,
dashboardId: dashboardData?.id,
dashboardName: dashboardData?.data.title,
numberOfPanels: dashboardData?.data.widgets?.length,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [setIsPanelTypeSelectionModalOpen]);

View File

@@ -91,7 +91,7 @@ function FullView({
setCurrentGraphRef(fullViewRef);
}, [setCurrentGraphRef]);
const { selectedDashboard, setColumnWidths } = useDashboardStore();
const { dashboardData, setColumnWidths } = useDashboardStore();
const isDashboardLocked = useDashboardStore(selectIsDashboardLocked);
const onColumnWidthsChange = useCallback(
@@ -166,7 +166,7 @@ function FullView({
enableDrillDown,
widget,
setRequestData,
selectedDashboard,
dashboardData,
selectedPanelType,
});
@@ -344,7 +344,7 @@ function FullView({
<>
<QueryBuilderV2
panelType={selectedPanelType}
version={selectedDashboard?.data?.version || 'v3'}
version={dashboardData?.data?.version || 'v3'}
isListViewPanel={selectedPanelType === PANEL_TYPES.LIST}
signalSourceChangeEnabled
// filterConfigs={filterConfigs}

View File

@@ -19,7 +19,7 @@ export interface DrilldownQueryProps {
widget: Widgets;
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
enableDrillDown: boolean;
selectedDashboard: Dashboard | undefined;
dashboardData: Dashboard | undefined;
selectedPanelType: PANEL_TYPES;
}
@@ -34,7 +34,7 @@ const useDrilldown = ({
enableDrillDown,
widget,
setRequestData,
selectedDashboard,
dashboardData,
selectedPanelType,
}: DrilldownQueryProps): UseDrilldownReturn => {
const isMounted = useRef(false);
@@ -60,11 +60,11 @@ const useDrilldown = ({
isMounted.current = true;
}, [widget, enableDrillDown, compositeQuery, redirectWithQueryBuilderData]);
const dashboardEditView = selectedDashboard?.id
const dashboardEditView = dashboardData?.id
? generateExportToDashboardLink({
query: currentQuery,
panelType: selectedPanelType,
dashboardId: selectedDashboard?.id || '',
dashboardId: dashboardData?.id || '',
widgetId: widget.id,
})
: '';

View File

@@ -163,13 +163,13 @@ const mockProps: WidgetGraphComponentProps = {
// Mock useDashabord hook
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): any => ({
selectedDashboard: {
dashboardData: {
data: {
variables: [],
},
},
setLayouts: jest.fn(),
setSelectedDashboard: jest.fn(),
setDashboardData: jest.fn(),
setColumnWidths: jest.fn(),
}),
}));

View File

@@ -103,8 +103,8 @@ function WidgetGraphComponent({
const {
setLayouts,
selectedDashboard,
setSelectedDashboard,
dashboardData,
setDashboardData,
setColumnWidths,
} = useDashboardStore();
@@ -125,33 +125,33 @@ function WidgetGraphComponent({
const updateDashboardMutation = useUpdateDashboard();
const onDeleteHandler = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const updatedWidgets = selectedDashboard?.data?.widgets?.filter(
const updatedWidgets = dashboardData?.data?.widgets?.filter(
(e) => e.id !== widget.id,
);
const updatedLayout =
selectedDashboard.data.layout?.filter((e) => e.i !== widget.id) || [];
dashboardData.data.layout?.filter((e) => e.i !== widget.id) || [];
const updatedSelectedDashboard: Props = {
const updatedDashboardData: Props = {
data: {
...selectedDashboard.data,
...dashboardData.data,
widgets: updatedWidgets,
layout: updatedLayout,
},
id: selectedDashboard.id,
id: dashboardData.id,
};
updateDashboardMutation.mutateAsync(updatedSelectedDashboard, {
updateDashboardMutation.mutateAsync(updatedDashboardData, {
onSuccess: (updatedDashboard) => {
if (setLayouts) {
setLayouts(updatedDashboard.data?.data?.layout || []);
}
if (setSelectedDashboard && updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
if (setDashboardData && updatedDashboard.data) {
setDashboardData(updatedDashboard.data);
}
setDeleteModal(false);
},
@@ -159,35 +159,35 @@ function WidgetGraphComponent({
};
const onCloneHandler = async (): Promise<void> => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const uuid = v4();
// this is added to make sure the cloned panel is of the same dimensions as the original one
const originalPanelLayout = selectedDashboard.data.layout?.find(
const originalPanelLayout = dashboardData.data.layout?.find(
(l) => l.i === widget.id,
);
const newLayoutItem = placeWidgetAtBottom(
uuid,
selectedDashboard?.data.layout || [],
dashboardData?.data.layout || [],
originalPanelLayout?.w || 6,
originalPanelLayout?.h || 6,
);
const layout = [...(selectedDashboard.data.layout || []), newLayoutItem];
const layout = [...(dashboardData.data.layout || []), newLayoutItem];
updateDashboardMutation.mutateAsync(
{
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
layout,
widgets: [
...(selectedDashboard.data.widgets || []),
...(dashboardData.data.widgets || []),
{
...{
...widget,
@@ -202,8 +202,8 @@ function WidgetGraphComponent({
if (setLayouts) {
setLayouts(updatedDashboard.data?.data?.layout || []);
}
if (setSelectedDashboard && updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
if (setDashboardData && updatedDashboard.data) {
setDashboardData(updatedDashboard.data);
}
notifications.success({
message: 'Panel cloned successfully, redirecting to new copy.',

View File

@@ -70,16 +70,16 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
useIsFetching([REACT_QUERY_KEY.DASHBOARD_BY_ID]) > 0;
const {
selectedDashboard,
dashboardData,
layouts,
setLayouts,
panelMap,
setPanelMap,
setSelectedDashboard,
setDashboardData,
columnWidths,
} = useDashboardStore();
const isDashboardLocked = useDashboardStore(selectIsDashboardLocked);
const { data } = selectedDashboard || {};
const { data } = dashboardData || {};
const { pathname } = useLocation();
const dispatch = useDispatch();
@@ -124,7 +124,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
}
const userRole: ROLES | null =
selectedDashboard?.createdBy === user?.email
dashboardData?.createdBy === user?.email
? (USER_ROLES.AUTHOR as ROLES)
: user.role;
@@ -146,27 +146,27 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
useEffect(() => {
if (!logEventCalledRef.current && !isUndefined(data)) {
logEvent('Dashboard Detail: Opened', {
dashboardId: selectedDashboard?.id,
dashboardId: dashboardData?.id,
dashboardName: data.title,
numberOfPanels: data.widgets?.length,
numberOfVariables: Object.keys(dashboardVariables).length || 0,
});
logEventCalledRef.current = true;
}
}, [dashboardVariables, data, selectedDashboard?.id]);
}, [dashboardVariables, data, dashboardData?.id]);
const onSaveHandler = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const updatedDashboard: Props = {
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
panelMap: { ...currentPanelMap },
layout: dashboardLayout.filter((e) => e.i !== PANEL_TYPES.EMPTY_WIDGET),
widgets: selectedDashboard?.data?.widgets?.map((widget) => {
widgets: dashboardData?.data?.widgets?.map((widget) => {
if (columnWidths?.[widget.id]) {
return {
...widget,
@@ -184,7 +184,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
if (updatedDashboard.data.data.layout) {
setLayouts(sortLayout(updatedDashboard.data.data.layout));
}
setSelectedDashboard(updatedDashboard.data);
setDashboardData(updatedDashboard.data);
setPanelMap(updatedDashboard.data?.data?.panelMap || {});
}
},
@@ -243,7 +243,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
dashboardLayout &&
Array.isArray(dashboardLayout) &&
dashboardLayout.length > 0 &&
hasColumnWidthsChanged(columnWidths, selectedDashboard);
hasColumnWidthsChanged(columnWidths, dashboardData);
if (shouldSaveLayout || shouldSaveColumnWidths) {
onSaveHandler();
@@ -253,7 +253,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
const onSettingsModalSubmit = (): void => {
const newTitle = form.getFieldValue('title');
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
@@ -261,7 +261,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
return;
}
const currentWidget = selectedDashboard?.data?.widgets?.find(
const currentWidget = dashboardData?.data?.widgets?.find(
(e) => e.id === currentSelectRowId,
);
@@ -269,25 +269,25 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
return;
}
const updatedWidgets = selectedDashboard?.data?.widgets?.map((e) =>
const updatedWidgets = dashboardData?.data?.widgets?.map((e) =>
e.id === currentSelectRowId ? { ...e, title: newTitle } : e,
);
const updatedSelectedDashboard: Props = {
id: selectedDashboard.id,
const updatedDashboardData: Props = {
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
widgets: updatedWidgets,
},
};
updateDashboardMutation.mutateAsync(updatedSelectedDashboard, {
updateDashboardMutation.mutateAsync(updatedDashboardData, {
onSuccess: (updatedDashboard) => {
if (setLayouts) {
setLayouts(updatedDashboard.data?.data?.layout || []);
}
if (setSelectedDashboard && updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
if (setDashboardData && updatedDashboard.data) {
setDashboardData(updatedDashboard.data);
}
if (setPanelMap) {
setPanelMap(updatedDashboard.data?.data?.panelMap || {});
@@ -311,7 +311,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
}, [currentSelectRowId, form, widgets]);
const handleRowCollapse = (id: string): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const { updatedLayout, updatedPanelMap } = applyRowCollapse(
@@ -343,7 +343,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
};
const handleRowDelete = (): void => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
@@ -351,34 +351,33 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
return;
}
const updatedWidgets = selectedDashboard?.data?.widgets?.filter(
const updatedWidgets = dashboardData?.data?.widgets?.filter(
(e) => e.id !== currentSelectRowId,
);
const updatedLayout =
selectedDashboard.data.layout?.filter((e) => e.i !== currentSelectRowId) ||
[];
dashboardData.data.layout?.filter((e) => e.i !== currentSelectRowId) || [];
const updatedPanelMap = { ...currentPanelMap };
delete updatedPanelMap[currentSelectRowId];
const updatedSelectedDashboard: Props = {
id: selectedDashboard.id,
const updatedDashboardData: Props = {
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
widgets: updatedWidgets,
layout: updatedLayout,
panelMap: updatedPanelMap,
},
};
updateDashboardMutation.mutateAsync(updatedSelectedDashboard, {
updateDashboardMutation.mutateAsync(updatedDashboardData, {
onSuccess: (updatedDashboard) => {
if (setLayouts) {
setLayouts(updatedDashboard.data?.data?.layout || []);
}
if (setSelectedDashboard && updatedDashboard.data) {
setSelectedDashboard(updatedDashboard.data);
if (setDashboardData && updatedDashboard.data) {
setDashboardData(updatedDashboard.data);
}
if (setPanelMap) {
setPanelMap(updatedDashboard.data?.data?.panelMap || {});
@@ -390,10 +389,8 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
};
const isDashboardEmpty = useMemo(
() =>
selectedDashboard?.data.layout
? selectedDashboard?.data.layout?.length === 0
: true,
[selectedDashboard],
dashboardData?.data.layout ? dashboardData?.data.layout?.length === 0 : true,
[dashboardData],
);
let isDataAvailableInAnyWidget = false;
@@ -512,7 +509,7 @@ function GraphLayout(props: GraphLayoutProps): JSX.Element {
widget={(currentWidget as Widgets) || ({ id, query: {} } as Widgets)}
headerMenuList={widgetActions}
variables={dashboardVariables}
// version={selectedDashboard?.data?.version}
// version={dashboardData?.data?.version}
version={ENTITY_VERSION_V5}
onDragSelect={onDragSelect}
dataAvailable={checkIfDataExists}

View File

@@ -42,14 +42,14 @@ export function WidgetRowHeader(props: WidgetRowHeaderProps): JSX.Element {
(s) => s.setIsPanelTypeSelectionModalOpen,
);
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const isDashboardLocked = useDashboardStore(selectIsDashboardLocked);
const permissions: ComponentTypes[] = ['add_panel'];
const { user } = useAppContext();
const userRole: ROLES | null =
selectedDashboard?.createdBy === user?.email
dashboardData?.createdBy === user?.email
? (USER_ROLES.AUTHOR as ROLES)
: user.role;
const [addPanelPermission] = useComponentPermission(permissions, userRole);
@@ -87,11 +87,11 @@ export function WidgetRowHeader(props: WidgetRowHeaderProps): JSX.Element {
icon={<Plus size={14} />}
onClick={(): void => {
// TODO: @AshwinBhatkal Simplify this check in cleanup of https://github.com/SigNoz/engineering-pod/issues/3953
if (!selectedDashboard?.id) {
if (!dashboardData?.id) {
return;
}
setSelectedRowWidgetId(selectedDashboard.id, id);
setSelectedRowWidgetId(dashboardData.id, id);
setIsPanelTypeSelectionModalOpen(true);
}}
>

View File

@@ -121,7 +121,7 @@ function useNavigateToExplorerPages(): (
) => Promise<{
[queryName: string]: { filters: TagFilterItem[]; dataSource?: string };
}> {
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const { notifications } = useNotifications();
return useCallback(
@@ -143,7 +143,7 @@ function useNavigateToExplorerPages(): (
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectedDashboard, notifications],
[dashboardData, notifications],
);
}

View File

@@ -20,7 +20,7 @@ interface UseUpdatedQueryOptions {
panelTypes: PANEL_TYPES;
timePreferance: timePreferenceType;
};
selectedDashboard?: any;
dashboardData?: any;
}
interface UseUpdatedQueryResult {
@@ -44,7 +44,7 @@ function useUpdatedQuery(): UseUpdatedQueryResult {
const getUpdatedQuery = useCallback(
async ({
widgetConfig,
selectedDashboard,
dashboardData,
}: UseUpdatedQueryOptions): Promise<Query> => {
// Prepare query payload with resolved variables
const { queryPayload } = prepareQueryRangePayloadV5({
@@ -52,7 +52,7 @@ function useUpdatedQuery(): UseUpdatedQueryResult {
graphType: getGraphType(widgetConfig.panelTypes),
selectedTime: widgetConfig.timePreferance,
globalSelectedInterval,
variables: getDashboardVariables(selectedDashboard?.data?.variables),
variables: getDashboardVariables(dashboardData?.data?.variables),
originalGraphType: widgetConfig.panelTypes,
dynamicVariables: dashboardDynamicVariables,
});

View File

@@ -149,16 +149,16 @@ export function extractQueryNamesFromExpression(expression: string): string[] {
export const hasColumnWidthsChanged = (
columnWidths: Record<string, Record<string, number>>,
selectedDashboard?: Dashboard,
dashboardData?: Dashboard,
): boolean => {
// If no column widths stored, no changes
if (isEmpty(columnWidths) || !selectedDashboard) {
if (isEmpty(columnWidths) || !dashboardData) {
return false;
}
// Check each widget's column widths
return Object.keys(columnWidths).some((widgetId) => {
const dashboardWidget = selectedDashboard?.data?.widgets?.find(
const dashboardWidget = dashboardData?.data?.widgets?.find(
(widget) => widget.id === widgetId,
) as Widgets;

View File

@@ -50,7 +50,8 @@
.ant-collapse-header {
align-items: center;
border-radius: 2px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
background-color: var(--l3-background);
border: 1px solid var(--l3-border);
padding: 8px;
@@ -70,7 +71,7 @@
.ant-collapse-content {
padding: 0;
background: var(--l1-background);
background: var(--l2-background);
border-top: 1px solid var(--l1-border);
.ant-collapse-content-box {

View File

@@ -1,15 +1,8 @@
import { ReactNode, useState } from 'react';
import MEditor, { EditorProps, Monaco } from '@monaco-editor/react';
import { Color } from '@signozhq/design-tokens';
import {
Button,
Collapse,
Divider,
Input,
Switch,
Tag,
Typography,
} from 'antd';
import { Button } from '@signozhq/ui';
import { Collapse, Divider, Input, Switch, Tag, Typography } from 'antd';
import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { OptionsQuery } from 'container/OptionsMenu/types';
@@ -178,13 +171,17 @@ function Overview({
{isAttributesExpanded && (
<Button
variant="link"
color="none"
className="action-btn"
icon={<Search size={12} />}
prefix={<Search size={12} />}
onClick={(e): void => {
e.stopPropagation();
handleSearchVisible();
}}
/>
>
Search
</Button>
)}
</div>
),

View File

@@ -1,6 +1,6 @@
.attribute-table-container {
.ant-table {
background: var(--l1-background);
background: var(--l2-background);
.ant-table-row:hover {
.ant-table-cell {
@@ -19,6 +19,7 @@
.ant-table-cell {
border: 1px solid var(--l1-border);
background: var(--l2-background);
}
.attribute-name {
@@ -54,10 +55,10 @@
}
.value-field-container {
background: var(--l3-background);
background: var(--l2-background);
&.attribute-pin {
background: var(--l1-background);
background: var(--l2-background);
}
.value-field {

View File

@@ -93,8 +93,8 @@ jest.mock('hooks/useDarkMode', () => ({
}));
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): { selectedDashboard: undefined } => ({
selectedDashboard: undefined,
useDashboardStore: (): { dashboardData: undefined } => ({
dashboardData: undefined,
}),
}));

View File

@@ -17,6 +17,9 @@
&.is-resizing {
background: var(--l2-background-hover);
}
border: none !important;
background-color: var(--l2-background) !important;
}
.tanstack-header-content {

View File

@@ -106,7 +106,7 @@ describe('LogsPanelComponent', () => {
<PreferenceContextProvider>
<NewWidget
dashboardId=""
selectedDashboard={undefined}
dashboardData={undefined}
selectedGraph={PANEL_TYPES.LIST}
/>
</PreferenceContextProvider>

View File

@@ -30,7 +30,7 @@ function LeftContainer({
setRequestData,
setQueryResponse,
enableDrillDown = false,
selectedDashboard,
dashboardData,
isNewPanel = false,
}: WidgetGraphProps): JSX.Element {
const { stagedQuery } = useQueryBuilder();
@@ -79,8 +79,8 @@ function LeftContainer({
isLoadingQueries={queryResponse.isFetching}
selectedWidget={selectedWidget}
dashboardVersion={ENTITY_VERSION_V5}
dashboardId={selectedDashboard?.id}
dashboardName={selectedDashboard?.data.title}
dashboardId={dashboardData?.id}
dashboardName={dashboardData?.data.title}
isNewPanel={isNewPanel}
/>
{selectedGraph === PANEL_TYPES.LIST && (

View File

@@ -326,7 +326,7 @@ describe('Stacking bar in new panel', () => {
<PreferenceContextProvider>
<NewWidget
dashboardId=""
selectedDashboard={undefined}
dashboardData={undefined}
selectedGraph={PANEL_TYPES.BAR}
/>
</PreferenceContextProvider>
@@ -378,7 +378,7 @@ describe('when switching to BAR panel type', () => {
<DashboardBootstrapWrapper dashboardId="">
<NewWidget
dashboardId=""
selectedDashboard={undefined}
dashboardData={undefined}
selectedGraph={PANEL_TYPES.BAR}
/>
</DashboardBootstrapWrapper>,

View File

@@ -86,7 +86,7 @@ import {
import './NewWidget.styles.scss';
function NewWidget({
selectedDashboard,
dashboardData,
dashboardId,
selectedGraph,
enableDrillDown = false,
@@ -135,7 +135,7 @@ function NewWidget({
[selectedGraph, globalSelectedInterval, isLogsQuery],
);
const { widgets = [] } = selectedDashboard?.data || {};
const { widgets = [] } = dashboardData?.data || {};
const query = useUrlQuery();
@@ -154,9 +154,9 @@ function NewWidget({
if (!logEventCalledRef.current) {
logEvent('Panel Edit: Page visited', {
panelType: selectedWidget?.panelTypes,
dashboardId: selectedDashboard?.id,
dashboardId: dashboardData?.id,
widgetId: selectedWidget?.id,
dashboardName: selectedDashboard?.data.title,
dashboardName: dashboardData?.data.title,
isNewPanel: !!isWidgetNotPresent,
dataSource: currentQuery?.builder?.queryData?.[0]?.dataSource,
});
@@ -362,7 +362,7 @@ function NewWidget({
const updateDashboardMutation = useUpdateDashboard();
const { afterWidgets, preWidgets } = useMemo(() => {
if (!selectedDashboard) {
if (!dashboardData) {
return {
selectedWidget: {} as Widgets,
preWidgets: [],
@@ -372,21 +372,18 @@ function NewWidget({
const widgetId = query.get('widgetId');
const selectedWidgetIndex = getSelectedWidgetIndex(
selectedDashboard,
widgetId,
);
const selectedWidgetIndex = getSelectedWidgetIndex(dashboardData, widgetId);
const preWidgets = getPreviousWidgets(selectedDashboard, selectedWidgetIndex);
const preWidgets = getPreviousWidgets(dashboardData, selectedWidgetIndex);
const afterWidgets = getNextWidgets(selectedDashboard, selectedWidgetIndex);
const afterWidgets = getNextWidgets(dashboardData, selectedWidgetIndex);
const selectedWidget = (selectedDashboard.data.widgets || [])[
const selectedWidget = (dashboardData.data.widgets || [])[
selectedWidgetIndex || 0
];
return { selectedWidget, preWidgets, afterWidgets };
}, [selectedDashboard, query]);
}, [dashboardData, query]);
// this loading state is to take care of mismatch in the responses for table and other panels
// hence while changing the query contains the older value and the processing logic fails
@@ -483,12 +480,12 @@ function NewWidget({
}, [dashboardId, query, safeNavigate]);
const onClickSaveHandler = useCallback(() => {
if (!selectedDashboard) {
if (!dashboardData) {
return;
}
const widgetId = query.get('widgetId') || '';
let updatedLayout = selectedDashboard.data.layout || [];
let updatedLayout = dashboardData.data.layout || [];
const selectedRowWidgetId = getSelectedRowWidgetId(dashboardId);
@@ -522,10 +519,10 @@ function NewWidget({
const adjustedQueryForV5 = adjustQueryForV5(currentQuery);
const dashboard: Props = {
id: selectedDashboard.id,
id: dashboardData.id,
data: {
...selectedDashboard.data,
...dashboardData.data,
widgets: isNewDashboard
? [
...afterWidgets,
@@ -603,7 +600,7 @@ function NewWidget({
},
});
}, [
selectedDashboard,
dashboardData,
query,
isNewDashboard,
afterWidgets,
@@ -672,9 +669,9 @@ function NewWidget({
const onSaveDashboard = useCallback((): void => {
logEvent('Panel Edit: Save changes', {
panelType: selectedWidget.panelTypes,
dashboardId: selectedDashboard?.id,
dashboardId: dashboardData?.id,
widgetId: selectedWidget.id,
dashboardName: selectedDashboard?.data.title,
dashboardName: dashboardData?.data.title,
queryType: currentQuery.queryType,
isNewPanel,
dataSource: currentQuery?.builder?.queryData?.[0]?.dataSource,
@@ -869,7 +866,7 @@ function NewWidget({
<OverlayScrollbar>
{selectedWidget && (
<LeftContainer
selectedDashboard={selectedDashboard}
dashboardData={dashboardData}
selectedGraph={graphType}
selectedLogFields={selectedLogFields}
setSelectedLogFields={setSelectedLogFields}

View File

@@ -10,7 +10,7 @@ import { timePreferance } from './RightContainer/timeItems';
export interface NewWidgetProps {
dashboardId: string;
selectedDashboard: Dashboard | undefined;
dashboardData: Dashboard | undefined;
selectedGraph: PANEL_TYPES;
enableDrillDown?: boolean;
}
@@ -34,7 +34,7 @@ export interface WidgetGraphProps {
>
>;
enableDrillDown?: boolean;
selectedDashboard: Dashboard | undefined;
dashboardData: Dashboard | undefined;
isNewPanel?: boolean;
}

View File

@@ -240,7 +240,7 @@ describe('InviteTeamMembers', () => {
describe('Validation callout on Complete', () => {
it('shows the correct callout message for each combination of email/role validity', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
const user = userEvent.setup({ pointerEventsCheck: 0, delay: null });
renderComponent();
const removeButtons = screen.getAllByRole('button', {
@@ -302,10 +302,10 @@ describe('InviteTeamMembers', () => {
screen.queryByText(/please enter valid emails and select roles/i),
).not.toBeInTheDocument();
});
});
}, 15000);
it('treats whitespace as untouched, clears the callout on fix-and-resubmit, and clears role error on role select', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
const user = userEvent.setup({ pointerEventsCheck: 0, delay: null });
renderComponent();
const removeButtons = screen.getAllByRole('button', {
@@ -365,7 +365,7 @@ describe('InviteTeamMembers', () => {
await waitFor(() => expect(mockOnNext).toHaveBeenCalledTimes(1), {
timeout: 1200,
});
});
}, 15000);
it('disables the Send Invites button when all rows are untouched (empty)', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });

View File

@@ -46,18 +46,16 @@ describe('CreateEdit Modal', () => {
// Tooltip mouseEnterDelay timers it triggers on the Configure button.
fireEvent.click(configureButtons[0]);
await waitFor(() => {
expect(screen.getByText(/edit google authentication/i)).toBeInTheDocument();
});
expect(
await screen.findByText(/edit google authentication/i),
).toBeInTheDocument();
const backButton = screen.getByRole('button', { name: /back/i });
fireEvent.click(backButton);
await waitFor(() => {
expect(
screen.getByText(/configure authentication method/i),
).toBeInTheDocument();
});
expect(
await screen.findByText(/configure authentication method/i),
).toBeInTheDocument();
});
});

View File

@@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next';
import { Form, Input } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { FormLabelStyle } from '../styles';
function DescriptionTextArea({
fieldData,
@@ -13,7 +12,7 @@ function DescriptionTextArea({
<Form.Item
required={false}
name={fieldData.name}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
>
<Input.TextArea rows={3} placeholder={t(fieldData.placeholder)} />

View File

@@ -8,7 +8,6 @@ import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { ProcessorFormField } from '../../../AddNewProcessor/config';
import { formValidationRules } from '../../../config';
import LogsFilterPreview from '../../../Preview/LogsFilterPreview';
import { FormLabelStyle } from '../../styles';
import './styles.scss';
@@ -68,7 +67,7 @@ function FilterInput({ fieldData }: FilterInputProps): JSX.Element {
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
rules={formValidationRules}
name={fieldData.name}

View File

@@ -3,7 +3,6 @@ import { Form, Input } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';
import { FormLabelStyle } from '../styles';
function NameInput({ fieldData }: NameInputProps): JSX.Element {
const { t } = useTranslation('pipeline');
@@ -11,7 +10,7 @@ function NameInput({ fieldData }: NameInputProps): JSX.Element {
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
rules={formValidationRules}
name={fieldData.name}

View File

@@ -3,7 +3,6 @@ import { Form } from 'antd';
import TagInput from 'container/PipelinePage/components/TagInput';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { FormLabelStyle } from '../styles';
function ProcessorTags({
fieldData,
@@ -15,7 +14,7 @@ function ProcessorTags({
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
name={fieldData.name}
>

View File

@@ -1,11 +1,12 @@
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Divider, Form, FormInstance, Modal } from 'antd';
import { Button } from '@signozhq/ui';
import { Form, FormInstance, Modal } from 'antd';
import { useAppContext } from 'providers/App/App';
import { ActionMode, ActionType, PipelineData } from 'types/api/pipeline/def';
import { v4 } from 'uuid';
import { ModalButtonWrapper, ModalTitle } from '../styles';
import { ModalButtonWrapper } from '../styles';
import { getEditedDataSource, getRecordIndex } from '../utils';
import { renderPipelineForm } from './utils';
@@ -90,34 +91,39 @@ function AddNewPipeline({
return (
<Modal
title={<ModalTitle level={4}>{modalTitle}</ModalTitle>}
title={modalTitle}
centered
open={isOpen}
width={800}
footer={null}
onCancel={onCancelModalHandler}
>
<Divider plain />
<Form
name="add-new-pipeline"
layout="vertical"
onFinish={onFinish}
autoComplete="off"
form={form}
className="add-new-pipeline-form"
>
{renderPipelineForm()}
<Divider plain />
<Form.Item>
<ModalButtonWrapper>
<Button
key="submit"
type="primary"
htmlType="submit"
variant="solid"
color="primary"
onClick={onOkModalHandler}
>
{isEdit ? t('update') : t('create')}
</Button>
<Button key="cancel" onClick={onCancelModalHandler}>
<Button
key="cancel"
variant="solid"
color="secondary"
onClick={onCancelModalHandler}
>
{t('cancel')}
</Button>
</ModalButtonWrapper>

View File

@@ -1,7 +0,0 @@
import styled from 'styled-components';
export const FormLabelStyle = styled.span`
font-size: 0.75rem;
font-weight: 400;
line-height: 1.25rem;
`;

View File

@@ -66,7 +66,7 @@ const useBaseAggregateOptions = ({
getUpdatedQuery,
isLoading: isResolveQueryLoading,
} = useUpdatedQuery();
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
useEffect(() => {
if (!aggregateData) {
@@ -79,7 +79,7 @@ const useBaseAggregateOptions = ({
panelTypes: panelType || PANEL_TYPES.TIME_SERIES,
timePreferance: 'GLOBAL_TIME',
},
selectedDashboard,
dashboardData,
});
setResolvedQuery(updatedQuery);
};

View File

@@ -14,7 +14,7 @@ jest.mock('react-router-dom', () => ({
// Mock useDashabord hook
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): any => ({
selectedDashboard: {
dashboardData: {
data: {
variables: [],
},

View File

@@ -97,6 +97,7 @@
}
.steps-content {
padding: 0 16px;
max-height: 500px;
}
}

View File

@@ -48,7 +48,7 @@ export function useDashboardBootstrap(
);
const {
setSelectedDashboard,
setDashboardData,
setLayouts,
setPanelMap,
resetDashboardStore,
@@ -65,7 +65,7 @@ export function useDashboardBootstrap(
transformDashboardVariables,
} = useTransformDashboardVariables(dashboardId);
// Keep the external variables store in sync with selectedDashboard
// Keep the external variables store in sync with dashboardData
useDashboardVariablesSync(dashboardId);
const dashboardQuery = useDashboardQuery(dashboardId);
@@ -88,7 +88,7 @@ export function useDashboardBootstrap(
if (variables) {
initializeDefaultVariables(variables, getUrlVariables, updateUrlVariable);
}
setSelectedDashboard(updatedDashboardData);
setDashboardData(updatedDashboardData);
dashboardRef.current = updatedDashboardData;
setLayouts(sortLayout(getUpdatedLayout(updatedDashboardData?.data.layout)));
setPanelMap(defaultTo(updatedDashboardData?.data?.panelMap, {}));
@@ -107,7 +107,7 @@ export function useDashboardBootstrap(
title: t('dashboard_has_been_updated'),
content: t('do_you_want_to_refresh_the_dashboard'),
onOk() {
setSelectedDashboard(updatedDashboardData);
setDashboardData(updatedDashboardData);
const { maxTime, minTime } = getMinMaxForSelectedTime(
globalTime.selectedTime,

View File

@@ -13,21 +13,21 @@ import { useDashboardVariablesSelector } from './useDashboardVariables';
/**
* Keeps the external variables store in sync with the zustand dashboard store.
* When selectedDashboard changes, propagates variable updates to the variables store.
* When dashboardData changes, propagates variable updates to the variables store.
*/
export function useDashboardVariablesSync(dashboardId: string): void {
const dashboardVariables = useDashboardVariablesSelector((s) => s.variables);
const savedDashboardId = useDashboardVariablesSelector((s) => s.dashboardId);
const selectedDashboard = useDashboardStore(
(s: DashboardStore) => s.selectedDashboard,
const dashboardData = useDashboardStore(
(s: DashboardStore) => s.dashboardData,
);
useEffect(() => {
const updatedVariables = selectedDashboard?.data.variables || {};
const updatedVariables = dashboardData?.data.variables || {};
if (savedDashboardId !== dashboardId) {
setDashboardVariablesStore({ dashboardId, variables: updatedVariables });
} else if (!isEqual(dashboardVariables, updatedVariables)) {
updateDashboardVariablesStore({ dashboardId, variables: updatedVariables });
}
}, [selectedDashboard]); // eslint-disable-line react-hooks/exhaustive-deps
}, [dashboardData]); // eslint-disable-line react-hooks/exhaustive-deps
}

View File

@@ -1,7 +1,7 @@
import { useMutation } from 'react-query';
import locked from 'api/v1/dashboards/id/lock';
import {
getSelectedDashboard,
getDashboardData,
useDashboardStore,
} from 'providers/Dashboard/store/useDashboardStore';
import { useErrorModal } from 'providers/ErrorModalProvider';
@@ -13,13 +13,11 @@ import APIError from 'types/api/error';
*/
export function useLockDashboard(): (value: boolean) => Promise<void> {
const { showErrorModal } = useErrorModal();
const { setSelectedDashboard } = useDashboardStore();
const { setDashboardData } = useDashboardStore();
const { mutate: lockDashboard } = useMutation(locked, {
onSuccess: (_, props) => {
setSelectedDashboard((prev) =>
prev ? { ...prev, locked: props.lock } : prev,
);
setDashboardData((prev) => (prev ? { ...prev, locked: props.lock } : prev));
},
onError: (error) => {
showErrorModal(error as APIError);
@@ -27,11 +25,11 @@ export function useLockDashboard(): (value: boolean) => Promise<void> {
});
return async (value: boolean): Promise<void> => {
const selectedDashboard = getSelectedDashboard();
if (selectedDashboard) {
const dashboardData = getDashboardData();
if (dashboardData) {
try {
await lockDashboard({
id: selectedDashboard.id,
id: dashboardData.id,
lock: value,
});
} catch (error) {

View File

@@ -12,11 +12,11 @@ import { useDashboardVariablesByType } from './useDashboardVariablesByType';
*/
export function useWidgetsByDynamicVariableId(): Record<string, string[]> {
const dynamicVariables = useDashboardVariablesByType('DYNAMIC', 'values');
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
return useMemo(() => {
const widgets =
selectedDashboard?.data?.widgets?.filter(
dashboardData?.data?.widgets?.filter(
(widget) => widget.panelTypes !== PANEL_GROUP_TYPES.ROW,
) || [];
@@ -24,5 +24,5 @@ export function useWidgetsByDynamicVariableId(): Record<string, string[]> {
dynamicVariables,
widgets as Widgets[],
);
}, [selectedDashboard, dynamicVariables]);
}, [dashboardData, dynamicVariables]);
}

View File

@@ -56,7 +56,7 @@ jest.mock('lib/dashboardVariables/getDashboardVariables', () => ({
}));
jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
useDashboardStore: (): unknown => ({ selectedDashboard: undefined }),
useDashboardStore: (): unknown => ({ dashboardData: undefined }),
}));
jest.mock('utils/getGraphType', () => ({

View File

@@ -33,7 +33,7 @@ const useCreateAlerts = (widget?: Widgets, caller?: string): VoidFunction => {
const { notifications } = useNotifications();
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const { dashboardVariables } = useDashboardVariables();
const dashboardDynamicVariables = useDashboardVariablesByType(
@@ -49,8 +49,8 @@ const useCreateAlerts = (widget?: Widgets, caller?: string): VoidFunction => {
if (caller === 'panelView') {
logEvent('Panel Edit: Create alert', {
panelType: widget.panelTypes,
dashboardName: selectedDashboard?.data?.title,
dashboardId: selectedDashboard?.id,
dashboardName: dashboardData?.data?.title,
dashboardId: dashboardData?.id,
widgetId: widget.id,
queryType: widget.query.queryType,
});
@@ -58,8 +58,8 @@ const useCreateAlerts = (widget?: Widgets, caller?: string): VoidFunction => {
logEvent('Dashboard Detail: Panel action', {
action: MenuItemKeys.CreateAlerts,
panelType: widget.panelTypes,
dashboardName: selectedDashboard?.data?.title,
dashboardId: selectedDashboard?.id,
dashboardName: dashboardData?.data?.title,
dashboardId: dashboardData?.id,
widgetId: widget.id,
queryType: widget.query.queryType,
});

View File

@@ -139,6 +139,7 @@
.legend-marker {
border-width: 2px;
border-style: solid;
border-radius: 50%;
min-width: 11px;
min-height: 11px;

View File

@@ -53,7 +53,8 @@
// horizontal offset when the scroller has padding or transform applied.
div[data-viewport-type='element'] {
left: 0;
padding: 4px 8px 4px 16px;
box-sizing: border-box;
padding: 4px 12px 4px 16px;
}
&::-webkit-scrollbar {

View File

@@ -21,9 +21,7 @@ function DashboardPage(): JSX.Element {
error,
} = useDashboardBootstrap(dashboardId, { confirm: onModal.confirm });
const dashboardTitle = useDashboardStore(
(s) => s.selectedDashboard?.data.title,
);
const dashboardTitle = useDashboardStore((s) => s.dashboardData?.data.title);
useEffect(() => {
document.title = dashboardTitle || document.title;

View File

@@ -62,9 +62,9 @@ function DashboardWidgetInternal({
widgetId: string;
graphType: PANEL_TYPES;
}): JSX.Element | null {
const [selectedDashboard, setSelectedDashboard] = useState<
Dashboard | undefined
>(undefined);
const [dashboardData, setDashboardData] = useState<Dashboard | undefined>(
undefined,
);
const { transformDashboardVariables } = useTransformDashboardVariables(
dashboardId,
@@ -83,7 +83,7 @@ function DashboardWidgetInternal({
cacheTime: DASHBOARD_CACHE_TIME,
onSuccess: (response) => {
const updatedDashboardData = transformDashboardVariables(response.data);
setSelectedDashboard(updatedDashboardData);
setDashboardData(updatedDashboardData);
setDashboardVariablesStore({
dashboardId,
variables: updatedDashboardData.data.variables,
@@ -108,7 +108,7 @@ function DashboardWidgetInternal({
dashboardId={dashboardId}
selectedGraph={graphType}
enableDrillDown={isDrilldownEnabled()}
selectedDashboard={selectedDashboard}
dashboardData={dashboardData}
/>
);
}

View File

@@ -218,30 +218,9 @@
.ant-modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
padding: 16px 16px;
margin: 0;
.cancel-btn {
display: flex;
align-items: center;
border: none;
border-radius: 2px;
background: var(--l1-border);
}
.delete-btn {
display: flex;
align-items: center;
border: none;
border-radius: 2px;
background: var(--danger-background);
margin-left: 12px;
}
.delete-btn:hover {
color: var(--l1-foreground);
background: var(--bg-cherry-600);
}
}
}
.title {
@@ -252,98 +231,3 @@
line-height: 20px; /* 142.857% */
}
}
.lightMode {
.save-view-container {
.save-view-content {
.title {
color: var(--l1-foreground);
}
.ant-table-row {
.ant-table-cell {
background: var(--l2-background);
}
&:hover {
.ant-table-cell {
background: var(--l2-background) !important;
}
}
.column-render {
border: 1px solid var(--l1-border);
background: var(--l1-background);
.title-with-action {
.save-view-title {
.ant-typography {
color: var(--l1-foreground);
}
}
.action-btn {
.ant-typography {
color: var(--l1-foreground);
}
}
}
.view-details {
.view-tag {
background: var(--l2-background);
.tag-text {
color: var(--l1-foreground);
}
}
.view-created-by {
color: var(--l1-foreground);
}
.view-created-at {
.ant-typography {
color: var(--l1-foreground);
}
}
}
}
}
}
}
.delete-view-modal {
.ant-modal-content {
border: 1px solid var(--l1-border);
background: var(--card);
.ant-modal-header {
background: var(--card);
.title {
color: var(--l1-foreground);
}
}
.ant-modal-body {
.ant-typography {
color: var(--l1-foreground);
}
.save-view-input {
.ant-input {
background: var(--l1-background);
color: var(--l1-foreground);
}
}
}
.ant-modal-footer {
.cancel-btn {
background: var(--l3-background);
color: var(--l2-foreground);
}
}
}
}
}

View File

@@ -2,15 +2,8 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import {
Button,
ColorPicker,
Input,
Modal,
Table,
TableProps,
Typography,
} from 'antd';
import { Button } from '@signozhq/ui';
import { ColorPicker, Input, Modal, Table, TableProps, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import {
getViewDetailsUsingViewKey,
@@ -348,15 +341,19 @@ function SaveView(): JSX.Element {
footer={[
<Button
key="cancel"
variant="solid"
color="secondary"
onClick={hideDeleteViewModal}
className="cancel-btn"
icon={<X size={16} />}
prefix={<X size={16} />}
>
Cancel
</Button>,
<Button
key="submit"
icon={<Trash2 size={16} />}
variant="solid"
color="destructive"
prefix={<Trash2 size={16} />}
onClick={onDeleteHandler}
className="delete-btn"
disabled={isDeleteLoading}
@@ -382,7 +379,9 @@ function SaveView(): JSX.Element {
footer={[
<Button
key="submit"
icon={<Check size={16} color={Color.BG_VANILLA_100} />}
variant="solid"
color="primary"
prefix={<Check size={16} color={Color.BG_VANILLA_100} />}
onClick={onUpdateQueryHandler}
disabled={isViewUpdating}
data-testid="save-view"

View File

@@ -149,62 +149,3 @@
}
}
}
.lightMode {
.traces-module-container {
.trace-module {
.ant-tabs-tab {
.tab-item {
color: var(--l2-foreground);
}
}
.ant-tabs-tab-active {
.tab-item {
color: var(--l1-foreground);
}
}
.ant-tabs-nav::before {
border-bottom: 1px solid var(--l1-border) !important;
}
}
.old-switch {
color: var(--l2-foreground);
}
.trace-layout {
.flamegraph-waterfall-toggle {
color: var(--l2-foreground);
}
.span-list-toggle {
color: var(--l2-foreground);
}
.trace-visualisation-tabs {
.ant-tabs-tab {
background: var(--l3-background);
border: 1px solid var(--l1-border);
}
.ant-tabs-tab-active {
background-color: var(--l1-background);
.ant-btn {
color: var(--l1-foreground) !important;
}
}
.ant-tabs-ink-bar {
height: 1px !important;
background: var(--l1-background) !important;
}
.ant-tabs-nav::before {
border-bottom: 1px solid var(--l1-border);
}
}
}
}
}

View File

@@ -699,17 +699,17 @@ describe('TracesExplorer - ', () => {
});
it('select a view options - assert and save this view', async () => {
jest.useFakeTimers();
const { container } = renderWithTracesExplorerRouter(<TracesExplorer />, [
'/traces-explorer/?panelType=list&selectedExplorerView=list',
]);
const viewSearchInput = container.querySelector(
'.view-options .ant-select-selection-search-input',
) as HTMLElement;
expect(viewSearchInput).toBeInTheDocument();
const viewSearchInput = await waitFor(() => {
const el = container.querySelector(
'.view-options .ant-select-selection-search-input',
) as HTMLElement;
expect(el).toBeInTheDocument();
return el;
});
fireEvent.mouseDown(viewSearchInput);
@@ -718,17 +718,18 @@ describe('TracesExplorer - ', () => {
).toBeInTheDocument();
// save this view
fireEvent.click(screen.getByText('Save this view'));
fireEvent.click(await screen.findByText('Save this view'));
const saveViewModalInput = await screen.findByPlaceholderText(
'e.g. External http method view',
);
expect(saveViewModalInput).toBeInTheDocument();
const saveViewModal = document.querySelector(
'.ant-modal-content',
) as HTMLElement;
expect(saveViewModal).toBeInTheDocument();
const saveViewModal = await waitFor(() => {
const el = document.querySelector('.ant-modal-content') as HTMLElement;
expect(el).toBeInTheDocument();
return el;
});
await act(async () =>
fireEvent.change(saveViewModalInput, { target: { value: 'test view' } }),
@@ -739,18 +740,19 @@ describe('TracesExplorer - ', () => {
fireEvent.click(within(saveViewModal).getByTestId('save-view-btn'));
});
expect(successNotification).toHaveBeenCalledWith({
message: 'View Saved Successfully',
await waitFor(() => {
expect(successNotification).toHaveBeenCalledWith({
message: 'View Saved Successfully',
});
});
});
}, 15000);
it('create a dashboard btn assert', async () => {
const { getByText } = renderWithTracesExplorerRouter(<TracesExplorer />, [
renderWithTracesExplorerRouter(<TracesExplorer />, [
'/traces-explorer/?panelType=list&selectedExplorerView=list',
]);
await screen.findByText(FILTER_SERVICE_NAME);
const createDashboardBtn = getByText('Add to Dashboard');
const createDashboardBtn = await screen.findByText('Add to Dashboard');
expect(createDashboardBtn).toBeInTheDocument();
fireEvent.click(createDashboardBtn);
@@ -771,12 +773,11 @@ describe('TracesExplorer - ', () => {
});
it('create an alert btn assert', async () => {
const { getByText } = renderWithTracesExplorerRouter(<TracesExplorer />, [
renderWithTracesExplorerRouter(<TracesExplorer />, [
'/traces-explorer/?panelType=list&selectedExplorerView=list',
]);
await screen.findByText(FILTER_SERVICE_NAME);
const createAlertBtn = getByText('Create an Alert');
const createAlertBtn = await screen.findByText('Create an Alert');
expect(createAlertBtn).toBeInTheDocument();
fireEvent.click(createAlertBtn);

View File

@@ -87,49 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
background: var(--l1-foreground);
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -87,52 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__ok-btn {
background: var(--primary-background) !important;
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -87,48 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -6,7 +6,7 @@
}
li:first-of-type {
.funnel-breadcrumb__title {
color: var(--l2-foreground);
color: var(--l1-foreground);
}
}
.ant-breadcrumb-separator {
@@ -24,15 +24,3 @@
line-height: 20px; /* 142.857% */
}
}
.lightMode {
.funnel-breadcrumb__title,
.ant-breadcrumb-separator {
color: var(--l2-foreground);
}
li:first-of-type {
.funnel-breadcrumb__title {
color: var(--l2-foreground);
}
}
}

View File

@@ -107,6 +107,7 @@ function FunnelConfiguration({
)}
<div className="funnel-configuration__steps">
{!isTraceDetailsPage && <StepsHeader />}
<StepsContent isTraceDetailsPage={isTraceDetailsPage} span={span} />
</div>
</>

View File

@@ -112,6 +112,7 @@
gap: 6px;
padding: 16px;
padding-left: 12px;
.ant-form-item {
margin: 0;
width: 100%;
@@ -121,6 +122,8 @@
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
.ant-select-selector {
background: var(--l3-background);
border: 1px solid var(--l1-border);
@@ -129,15 +132,23 @@
line-height: 16px;
}
}
&__service-and-span {
display: flex;
align-items: center;
gap: 12px;
.service,
.span {
flex: 1;
}
.ant-select-selection-placeholder {
color: var(--l2-foreground);
}
.ant-select {
width: 239px;
width: 100%;
}
}
&__where-filter {

View File

@@ -1,4 +1,6 @@
.steps-content {
padding: 0 16px;
.ant-btn {
box-shadow: none;
&-icon {
@@ -110,29 +112,3 @@
}
}
}
// Light mode styles
.lightMode {
.steps-content {
.ant-steps-item-process .ant-steps-item-icon,
.ant-steps-item-icon {
background-color: var(--l3-background) !important;
& > .ant-steps-icon {
color: var(--l1-foreground);
}
}
.ant-steps-item-tail {
&::after {
background-color: var(--l1-border) !important;
}
}
.latency-step-marker {
&::before {
background-color: var(--l3-background);
}
}
}
}

View File

@@ -52,29 +52,3 @@
}
}
}
.lightMode {
.steps-footer {
border-top: 1px solid var(--l1-border);
background: var(--l2-background);
&__left {
color: var(--l2-background);
}
&__valid-traces {
&--none {
color: var(--text-amber-600);
}
}
&__button {
&--save {
background: var(--l3-background);
}
&--run {
background-color: var(--bg-robin-400);
}
}
}
}

View File

@@ -1,10 +1,14 @@
.steps-header {
display: flex;
align-items: center;
justify-content: center;
align-items: flex-start;
gap: 6px;
padding: 16px;
margin-bottom: 16px;
margin-top: 16px;
flex-wrap: wrap;
&__label {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-size: 12px;
font-weight: 600;
line-height: 18px;
@@ -12,6 +16,7 @@
text-transform: uppercase;
flex-shrink: 0;
}
&__divider {
width: 100%;
.ant-divider {
@@ -19,8 +24,9 @@
border-color: var(--l1-border);
}
}
&__time-range {
min-width: 192px;
width: 100%;
height: 32px;
flex-shrink: 0;
.timeSelection-input {
@@ -29,23 +35,9 @@
}
&,
input {
background: var(--l3-background);
background: var(--l2-background);
font-size: 12px;
}
}
}
}
.lightMode {
.steps-header {
&__label {
color: var(--l2-foreground);
}
.timeSelection-input {
&,
input {
background: unset;
}
}
}
}

View File

@@ -1,4 +1,3 @@
import { Divider } from 'antd';
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
import './StepsHeader.styles.scss';
@@ -7,14 +6,12 @@ function StepsHeader(): JSX.Element {
return (
<div className="steps-header">
<div className="steps-header__label">FUNNEL STEPS</div>
<div className="steps-header__divider">
<Divider dashed />
</div>
<div className="steps-header__time-range">
<DateTimeSelectionV2
showAutoRefresh={false}
showRefreshText={false}
hideShareModal
showRecentlyUsed={false}
/>
</div>
</div>

View File

@@ -28,15 +28,3 @@
margin-top: 8px;
}
}
.lightMode {
.empty-funnel-results {
&__title {
color: var(--l1-foreground);
}
&__description {
color: var(--l2-foreground);
}
}
}

View File

@@ -79,44 +79,3 @@
}
}
}
.lightMode {
.funnel-metrics {
background: var(--l1-foreground);
border: 1px solid var(--l1-border);
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.05);
&__header {
border-bottom: 1px solid var(--l1-border);
}
&__title {
color: var(--l2-foreground);
}
&__subtitle {
&-label {
color: var(--l2-foreground);
}
&-value {
color: var(--l1-foreground);
}
}
&__item {
&:not(:last-child) {
border-right: 1px solid var(--l1-border);
}
&-title {
color: var(--l1-foreground);
}
&-value,
&-unit {
color: var(--l2-foreground);
}
}
}
}

View File

@@ -115,39 +115,3 @@
}
}
}
.lightMode {
.funnel-table {
border-color: var(--l1-border);
.ant-table {
.ant-table-thead > tr > th {
background: var(--l1-foreground);
color: var(--l2-foreground);
}
.ant-table-cell {
background: var(--l1-foreground);
color: var(--l1-background);
}
.ant-table-tbody > tr:hover > td {
background: rgba(0, 0, 0, 0.04);
}
.table-row-light {
background: none;
color: var(--l1-background);
}
.table-row-dark {
background: none;
color: var(--l1-background);
}
}
&__header {
background: var(--l1-foreground);
color: var(--l2-foreground);
}
}
}

View File

@@ -2,6 +2,7 @@
display: flex;
flex-direction: column;
gap: 20px;
&__steps-selector {
display: flex;
justify-content: center;
@@ -13,26 +14,3 @@
gap: 16px;
}
}
.lightMode {
.steps-transition-results {
&__steps-selector {
.views-tabs {
.tab {
background: var(--l1-foreground);
}
.selected_view {
background: var(--l3-background);
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.selected_view::before {
background: var(--l3-background);
border-left: 1px solid var(--l1-border);
}
}
}
}
}

View File

@@ -2,10 +2,11 @@
@use 'components/SearchBar/SearchBar.styles.scss';
.traces-funnels {
margin-top: 113px;
padding: 64px 0;
display: flex;
justify-content: center;
width: 100%;
.ant-btn-icon {
margin: 0 !important;
}

View File

@@ -17,9 +17,3 @@
padding-bottom: 24px;
}
}
.lightMode {
.delete-funnel-modal-content {
color: var(--l2-foreground) !important;
}
}

View File

@@ -60,23 +60,3 @@
}
}
}
.lightMode {
.funnels-empty {
&__content {
border: 1px dashed var(--l2-foreground);
}
&__icon {
color: var(--l1-background);
}
&__title {
color: var(--l1-background);
}
&__subtitle {
color: var(--l2-background);
}
}
}

View File

@@ -12,7 +12,7 @@
&,
input {
font-family: Inter;
background: var(--l3-background);
background: var(--l2-background);
font-size: 14px;
line-height: 18px;
font-style: normal;

View File

@@ -69,17 +69,17 @@ jest.mock('react-redux', () => ({
jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid') }));
function TestComponent(): JSX.Element {
const { selectedDashboard } = useDashboardStore();
const { dashboardData } = useDashboardStore();
const { dashboardVariables } = useDashboardVariables();
return (
<div>
<div data-testid="dashboard-id">{selectedDashboard?.id}</div>
<div data-testid="dashboard-id">{dashboardData?.id}</div>
<div data-testid="dashboard-variables">
{dashboardVariables ? JSON.stringify(dashboardVariables) : 'null'}
</div>
<div data-testid="dashboard-data">
{selectedDashboard?.data?.title || 'No Title'}
{dashboardData?.data?.title || 'No Title'}
</div>
</div>
);

View File

@@ -9,8 +9,8 @@ export type WidgetColumnWidths = {
export interface DashboardUISlice {
//
selectedDashboard: Dashboard | undefined;
setSelectedDashboard: (
dashboardData: Dashboard | undefined;
setDashboardData: (
updater:
| Dashboard
| undefined
@@ -26,7 +26,7 @@ export interface DashboardUISlice {
}
export const initialDashboardUIState = {
selectedDashboard: undefined as Dashboard | undefined,
dashboardData: undefined as Dashboard | undefined,
columnWidths: {} as WidgetColumnWidths,
};
@@ -38,10 +38,10 @@ export const createDashboardUISlice: StateCreator<
> = (set) => ({
...initialDashboardUIState,
setSelectedDashboard: (updater): void =>
setDashboardData: (updater): void =>
set((state: DashboardUISlice): void => {
state.selectedDashboard =
typeof updater === 'function' ? updater(state.selectedDashboard) : updater;
state.dashboardData =
typeof updater === 'function' ? updater(state.dashboardData) : updater;
}),
setColumnWidths: (updater): void =>

Some files were not shown because too many files have changed in this diff Show More