mirror of
https://github.com/SigNoz/signoz.git
synced 2026-06-11 11:20:32 +01:00
Compare commits
1 Commits
feat/dashb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfcd58b341 |
53
frontend/src/pages/DashboardPage/DashboardPage.tsx
Normal file
53
frontend/src/pages/DashboardPage/DashboardPage.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Modal } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { AxiosError } from 'axios';
|
||||
import NotFound from 'components/NotFound';
|
||||
import Spinner from 'components/Spinner';
|
||||
import DashboardContainer from 'container/DashboardContainer';
|
||||
import { useDashboardBootstrap } from 'hooks/dashboard/useDashboardBootstrap';
|
||||
import { useDashboardStore } from 'providers/Dashboard/store/useDashboardStore';
|
||||
import { ErrorType } from 'types/common';
|
||||
|
||||
function DashboardPage(): JSX.Element {
|
||||
const { dashboardId } = useParams<{ dashboardId: string }>();
|
||||
|
||||
const [onModal, Content] = Modal.useModal();
|
||||
|
||||
const { isLoading, isError, isFetching, error } = useDashboardBootstrap(
|
||||
dashboardId,
|
||||
{ confirm: onModal.confirm },
|
||||
);
|
||||
|
||||
const dashboardTitle = useDashboardStore((s) => s.dashboardData?.data.title);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = dashboardTitle || document.title;
|
||||
}, [dashboardTitle]);
|
||||
|
||||
const errorMessage = isError
|
||||
? (error as AxiosError<{ errorType: string }>)?.response?.data?.errorType
|
||||
: 'Something went wrong';
|
||||
|
||||
if (isError && !isFetching && errorMessage === ErrorType.NotFound) {
|
||||
return <NotFound />;
|
||||
}
|
||||
|
||||
if (isError && errorMessage) {
|
||||
return <Typography>{errorMessage}</Typography>;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner tip="Loading.." />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{Content}
|
||||
<DashboardContainer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default DashboardPage;
|
||||
@@ -1,53 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Modal } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { AxiosError } from 'axios';
|
||||
import NotFound from 'components/NotFound';
|
||||
import Spinner from 'components/Spinner';
|
||||
import DashboardContainer from 'container/DashboardContainer';
|
||||
import { useDashboardBootstrap } from 'hooks/dashboard/useDashboardBootstrap';
|
||||
import { useDashboardStore } from 'providers/Dashboard/store/useDashboardStore';
|
||||
import { ErrorType } from 'types/common';
|
||||
import { useIsDashboardV2 } from 'hooks/useIsDashboardV2';
|
||||
import DashboardPageV2 from 'pages/DashboardPageV2';
|
||||
|
||||
function DashboardPage(): JSX.Element {
|
||||
const { dashboardId } = useParams<{ dashboardId: string }>();
|
||||
import DashboardPage from './DashboardPage';
|
||||
|
||||
const [onModal, Content] = Modal.useModal();
|
||||
// Serves the V2 dashboard detail page when the `use_dashboard_v2` flag is active;
|
||||
// otherwise the existing V1 page. Lets V2 dark-ship behind the flag without
|
||||
// changing route definitions.
|
||||
function DashboardPageEntry(): JSX.Element {
|
||||
const isDashboardV2 = useIsDashboardV2();
|
||||
|
||||
const { isLoading, isError, isFetching, error } = useDashboardBootstrap(
|
||||
dashboardId,
|
||||
{ confirm: onModal.confirm },
|
||||
);
|
||||
|
||||
const dashboardTitle = useDashboardStore((s) => s.dashboardData?.data.title);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = dashboardTitle || document.title;
|
||||
}, [dashboardTitle]);
|
||||
|
||||
const errorMessage = isError
|
||||
? (error as AxiosError<{ errorType: string }>)?.response?.data?.errorType
|
||||
: 'Something went wrong';
|
||||
|
||||
if (isError && !isFetching && errorMessage === ErrorType.NotFound) {
|
||||
return <NotFound />;
|
||||
}
|
||||
|
||||
if (isError && errorMessage) {
|
||||
return <Typography>{errorMessage}</Typography>;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner tip="Loading.." />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{Content}
|
||||
<DashboardContainer />
|
||||
</>
|
||||
);
|
||||
return isDashboardV2 ? <DashboardPageV2 /> : <DashboardPage />;
|
||||
}
|
||||
|
||||
export default DashboardPage;
|
||||
export default DashboardPageEntry;
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
DashboardtypesLayoutDTO,
|
||||
DashboardtypesPanelDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { DashboardtypesJSONPatchOperationDTOOp } from 'api/generated/services/sigNoz.schemas';
|
||||
import { DashboardtypesPatchOpDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
import type { GridItem } from './utils';
|
||||
|
||||
@@ -16,7 +16,7 @@ import type { GridItem } from './utils';
|
||||
* patches in DashboardSettings/General and DashboardDescription).
|
||||
*/
|
||||
|
||||
const { add, replace, remove } = DashboardtypesJSONPatchOperationDTOOp;
|
||||
const { add, replace, remove } = DashboardtypesPatchOpDTO;
|
||||
|
||||
const PANEL_REF_PREFIX = '#/spec/panels/';
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
import { useIsDashboardV2 } from 'hooks/useIsDashboardV2';
|
||||
import DashboardsListPageV2 from 'pages/DashboardsListPageV2';
|
||||
|
||||
import DashboardsListPage from './DashboardsListPage';
|
||||
|
||||
export default DashboardsListPage;
|
||||
// Serves the V2 dashboards list when the `use_dashboard_v2` flag is active;
|
||||
// otherwise the existing V1 list. Lets V2 dark-ship behind the flag without
|
||||
// changing route definitions.
|
||||
function DashboardsListPageEntry(): JSX.Element {
|
||||
const isDashboardV2 = useIsDashboardV2();
|
||||
|
||||
return isDashboardV2 ? <DashboardsListPageV2 /> : <DashboardsListPage />;
|
||||
}
|
||||
|
||||
export default DashboardsListPageEntry;
|
||||
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
createDashboardV2,
|
||||
useListDashboardsV2,
|
||||
} from 'api/generated/services/dashboard';
|
||||
import {
|
||||
DashboardtypesListOrderDTO,
|
||||
DashboardtypesListSortDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { RequestDashboardBtn } from 'container/ListOfDashboard/RequestDashboardBtn';
|
||||
import useComponentPermission from 'hooks/useComponentPermission';
|
||||
@@ -24,8 +28,6 @@ import {
|
||||
useSearch,
|
||||
useSortColumn,
|
||||
useSortOrder,
|
||||
type SortColumn,
|
||||
type SortOrder,
|
||||
} from '../../hooks/useDashboardsListQueryParams';
|
||||
import type { DashboardListItem } from '../../utils';
|
||||
import ConfigureMetadataModal from '../ConfigureMetadataModal/ConfigureMetadataModal';
|
||||
@@ -150,7 +152,7 @@ function DashboardsList(): JSX.Element {
|
||||
}, []);
|
||||
|
||||
const onSortChange = useCallback(
|
||||
(column: SortColumn): void => {
|
||||
(column: DashboardtypesListSortDTO): void => {
|
||||
void setSortColumn(column);
|
||||
void setPage(1);
|
||||
},
|
||||
@@ -158,7 +160,7 @@ function DashboardsList(): JSX.Element {
|
||||
);
|
||||
|
||||
const onOrderChange = useCallback(
|
||||
(order: SortOrder): void => {
|
||||
(order: DashboardtypesListOrderDTO): void => {
|
||||
void setSortOrder(order);
|
||||
void setPage(1);
|
||||
},
|
||||
|
||||
@@ -7,18 +7,18 @@ import {
|
||||
HdmiPort,
|
||||
} from '@signozhq/icons';
|
||||
|
||||
import type {
|
||||
SortColumn,
|
||||
SortOrder,
|
||||
} from '../../hooks/useDashboardsListQueryParams';
|
||||
import {
|
||||
DashboardtypesListOrderDTO,
|
||||
DashboardtypesListSortDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
import styles from './ListHeader.module.scss';
|
||||
|
||||
interface Props {
|
||||
sortColumn: SortColumn;
|
||||
onSortChange: (column: SortColumn) => void;
|
||||
sortOrder: SortOrder;
|
||||
onOrderChange: (order: SortOrder) => void;
|
||||
sortColumn: DashboardtypesListSortDTO;
|
||||
onSortChange: (column: DashboardtypesListSortDTO) => void;
|
||||
sortOrder: DashboardtypesListOrderDTO;
|
||||
onOrderChange: (order: DashboardtypesListOrderDTO) => void;
|
||||
onConfigureMetadata: () => void;
|
||||
}
|
||||
|
||||
@@ -44,49 +44,57 @@ function ListHeader({
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.sortButton}
|
||||
onClick={(): void => onSortChange('name')}
|
||||
onClick={(): void => onSortChange(DashboardtypesListSortDTO.name)}
|
||||
data-testid="sort-by-name"
|
||||
>
|
||||
Name
|
||||
{sortColumn === 'name' && <Check size={14} />}
|
||||
{sortColumn === DashboardtypesListSortDTO.name && <Check size={14} />}
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.sortButton}
|
||||
onClick={(): void => onSortChange('created_at')}
|
||||
onClick={(): void =>
|
||||
onSortChange(DashboardtypesListSortDTO.created_at)
|
||||
}
|
||||
data-testid="sort-by-last-created"
|
||||
>
|
||||
Last created
|
||||
{sortColumn === 'created_at' && <Check size={14} />}
|
||||
{sortColumn === DashboardtypesListSortDTO.created_at && (
|
||||
<Check size={14} />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.sortButton}
|
||||
onClick={(): void => onSortChange('updated_at')}
|
||||
onClick={(): void =>
|
||||
onSortChange(DashboardtypesListSortDTO.updated_at)
|
||||
}
|
||||
data-testid="sort-by-last-updated"
|
||||
>
|
||||
Last updated
|
||||
{sortColumn === 'updated_at' && <Check size={14} />}
|
||||
{sortColumn === DashboardtypesListSortDTO.updated_at && (
|
||||
<Check size={14} />
|
||||
)}
|
||||
</Button>
|
||||
<div className={styles.sortDivider} />
|
||||
<Typography.Text className={styles.sortHeading}>Order</Typography.Text>
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.sortButton}
|
||||
onClick={(): void => onOrderChange('asc')}
|
||||
onClick={(): void => onOrderChange(DashboardtypesListOrderDTO.asc)}
|
||||
data-testid="sort-order-asc"
|
||||
>
|
||||
Ascending
|
||||
{sortOrder === 'asc' && <Check size={14} />}
|
||||
{sortOrder === DashboardtypesListOrderDTO.asc && <Check size={14} />}
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.sortButton}
|
||||
onClick={(): void => onOrderChange('desc')}
|
||||
onClick={(): void => onOrderChange(DashboardtypesListOrderDTO.desc)}
|
||||
data-testid="sort-order-desc"
|
||||
>
|
||||
Descending
|
||||
{sortOrder === 'desc' && <Check size={14} />}
|
||||
{sortOrder === DashboardtypesListOrderDTO.desc && <Check size={14} />}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Shared building blocks for the dashboards-list view states.
|
||||
// Composed via CSS-modules `composes:` from each state's own SCSS.
|
||||
/* Shared building blocks for the dashboards-list view states. */
|
||||
/* Composed via CSS-modules `composes:` from each state's own SCSS. */
|
||||
|
||||
.cardWrapper {
|
||||
display: flex;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
DashboardtypesListOrderDTO,
|
||||
DashboardtypesListSortDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import {
|
||||
parseAsInteger,
|
||||
parseAsString,
|
||||
@@ -7,26 +11,31 @@ import {
|
||||
type UseQueryStateReturn,
|
||||
} from 'nuqs';
|
||||
|
||||
export const SORT_COLUMNS = ['updated_at', 'created_at', 'name'] as const;
|
||||
export type SortColumn = (typeof SORT_COLUMNS)[number];
|
||||
|
||||
export const SORT_ORDERS = ['asc', 'desc'] as const;
|
||||
export type SortOrder = (typeof SORT_ORDERS)[number];
|
||||
export const SORT_COLUMNS = Object.values(DashboardtypesListSortDTO);
|
||||
export const SORT_ORDERS = Object.values(DashboardtypesListOrderDTO);
|
||||
|
||||
const opts: Options = { history: 'push' };
|
||||
|
||||
export const useSortColumn = (): UseQueryStateReturn<SortColumn, SortColumn> =>
|
||||
export const useSortColumn = (): UseQueryStateReturn<
|
||||
DashboardtypesListSortDTO,
|
||||
DashboardtypesListSortDTO
|
||||
> =>
|
||||
useQueryState(
|
||||
'sort',
|
||||
parseAsStringLiteral(SORT_COLUMNS)
|
||||
.withDefault('updated_at')
|
||||
.withDefault(DashboardtypesListSortDTO.updated_at)
|
||||
.withOptions(opts),
|
||||
);
|
||||
|
||||
export const useSortOrder = (): UseQueryStateReturn<SortOrder, SortOrder> =>
|
||||
export const useSortOrder = (): UseQueryStateReturn<
|
||||
DashboardtypesListOrderDTO,
|
||||
DashboardtypesListOrderDTO
|
||||
> =>
|
||||
useQueryState(
|
||||
'order',
|
||||
parseAsStringLiteral(SORT_ORDERS).withDefault('desc').withOptions(opts),
|
||||
parseAsStringLiteral(SORT_ORDERS)
|
||||
.withDefault(DashboardtypesListOrderDTO.desc)
|
||||
.withOptions(opts),
|
||||
);
|
||||
|
||||
export const usePage = (): UseQueryStateReturn<number, number> =>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import type { DashboardtypesGettableDashboardWithPinDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import type { DashboardtypesListedDashboardV2DTO } from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
export type DashboardListItem = DashboardtypesGettableDashboardWithPinDTO;
|
||||
export type DashboardListItem = DashboardtypesListedDashboardV2DTO;
|
||||
|
||||
export const tagsToStrings = (
|
||||
tags: { key: string; value: string }[] | null | undefined,
|
||||
|
||||
@@ -48,9 +48,7 @@
|
||||
"node_modules",
|
||||
"src/parser/*.ts",
|
||||
"src/parser/TraceOperatorParser/*.ts",
|
||||
"orval.config.ts",
|
||||
"src/pages/DashboardsListPageV2/**/*",
|
||||
"src/pages/DashboardPageV2/**/*"
|
||||
"orval.config.ts"
|
||||
],
|
||||
"include": [
|
||||
"./src",
|
||||
|
||||
Reference in New Issue
Block a user