mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-23 21:04:27 +08:00
[Feat]: Dynamic columns in tables (#3809)
* feat: added dropdown in alert list table * refactor: done with combining actions * feat: done with label and dynamic table * feat: dynamic column in table * chore: show all label on hover * refactor: create to created timestamp - highlighted action * refactor: storing the column data in localstorage
This commit is contained in:
parent
b34eafcab1
commit
fc49833c9f
7
frontend/src/components/DropDown/DropDown.styles.scss
Normal file
7
frontend/src/components/DropDown/DropDown.styles.scss
Normal file
@ -0,0 +1,7 @@
|
||||
.Dropdown-button {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.Dropdown-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
29
frontend/src/components/DropDown/DropDown.tsx
Normal file
29
frontend/src/components/DropDown/DropDown.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import './DropDown.styles.scss';
|
||||
|
||||
import { EllipsisOutlined } from '@ant-design/icons';
|
||||
import { Button, Dropdown, MenuProps, Space } from 'antd';
|
||||
|
||||
function DropDown({ element }: { element: JSX.Element[] }): JSX.Element {
|
||||
const items: MenuProps['items'] = element.map(
|
||||
(e: JSX.Element, index: number) => ({
|
||||
label: e,
|
||||
key: index,
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown menu={{ items }} className="Dropdown-container">
|
||||
<Button
|
||||
type="link"
|
||||
className="Dropdown-button"
|
||||
onClick={(e): void => e.preventDefault()}
|
||||
>
|
||||
<Space>
|
||||
<EllipsisOutlined className="Dropdown-icon" />
|
||||
</Space>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropDown;
|
@ -0,0 +1,17 @@
|
||||
.DynamicColumnTable {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.dynamicColumnTable-button {
|
||||
align-self: flex-end;
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dynamicColumnsTable-items {
|
||||
display: flex;
|
||||
width: 10.625rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
116
frontend/src/components/ResizeTable/DynamicColumnTable.tsx
Normal file
116
frontend/src/components/ResizeTable/DynamicColumnTable.tsx
Normal file
@ -0,0 +1,116 @@
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
import './DynamicColumnTable.syles.scss';
|
||||
|
||||
import { SettingOutlined } from '@ant-design/icons';
|
||||
import { Button, Dropdown, MenuProps, Switch } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import ResizeTable from './ResizeTable';
|
||||
import { DynamicColumnTableProps } from './types';
|
||||
import { getVisibleColumns, setVisibleColumns } from './unit';
|
||||
|
||||
function DynamicColumnTable({
|
||||
tablesource,
|
||||
columns,
|
||||
dynamicColumns,
|
||||
onDragColumn,
|
||||
...restProps
|
||||
}: DynamicColumnTableProps): JSX.Element {
|
||||
const [columnsData, setColumnsData] = useState<ColumnsType | undefined>(
|
||||
columns,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const visibleColumns = getVisibleColumns({
|
||||
tablesource,
|
||||
columnsData: columns,
|
||||
dynamicColumns,
|
||||
});
|
||||
setColumnsData((prevColumns) =>
|
||||
prevColumns
|
||||
? [
|
||||
...prevColumns.slice(0, prevColumns.length - 1),
|
||||
...visibleColumns,
|
||||
prevColumns[prevColumns.length - 1],
|
||||
]
|
||||
: undefined,
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const onToggleHandler = (index: number) => (
|
||||
checked: boolean,
|
||||
event: React.MouseEvent<HTMLButtonElement>,
|
||||
): void => {
|
||||
event.stopPropagation();
|
||||
setVisibleColumns({
|
||||
tablesource,
|
||||
dynamicColumns,
|
||||
index,
|
||||
checked,
|
||||
});
|
||||
setColumnsData((prevColumns) => {
|
||||
if (checked && dynamicColumns) {
|
||||
return prevColumns
|
||||
? [
|
||||
...prevColumns.slice(0, prevColumns.length - 1),
|
||||
dynamicColumns[index],
|
||||
prevColumns[prevColumns.length - 1],
|
||||
]
|
||||
: undefined;
|
||||
}
|
||||
return prevColumns && dynamicColumns
|
||||
? prevColumns.filter(
|
||||
(column) => dynamicColumns[index].title !== column.title,
|
||||
)
|
||||
: undefined;
|
||||
});
|
||||
};
|
||||
|
||||
const items: MenuProps['items'] =
|
||||
dynamicColumns?.map((column, index) => ({
|
||||
label: (
|
||||
<div className="dynamicColumnsTable-items">
|
||||
<div>{column.title?.toString()}</div>
|
||||
<Switch
|
||||
checked={columnsData?.findIndex((c) => c.key === column.key) !== -1}
|
||||
onChange={onToggleHandler(index)}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
key: index,
|
||||
type: 'checkbox',
|
||||
})) || [];
|
||||
|
||||
return (
|
||||
<div className="DynamicColumnTable">
|
||||
{dynamicColumns && (
|
||||
<Dropdown
|
||||
getPopupContainer={popupContainer}
|
||||
menu={{ items }}
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button
|
||||
className="dynamicColumnTable-button"
|
||||
size="middle"
|
||||
icon={<SettingOutlined />}
|
||||
/>
|
||||
</Dropdown>
|
||||
)}
|
||||
|
||||
<ResizeTable
|
||||
columns={columnsData}
|
||||
onDragColumn={onDragColumn}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
DynamicColumnTable.defaultProps = {
|
||||
onDragColumn: undefined,
|
||||
};
|
||||
|
||||
export default memo(DynamicColumnTable);
|
23
frontend/src/components/ResizeTable/TableComponent/Date.tsx
Normal file
23
frontend/src/components/ResizeTable/TableComponent/Date.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { Typography } from 'antd';
|
||||
import convertDateToAmAndPm from 'lib/convertDateToAmAndPm';
|
||||
import getFormattedDate from 'lib/getFormatedDate';
|
||||
|
||||
function DateComponent(
|
||||
CreatedOrUpdateTime: string | number | Date,
|
||||
): JSX.Element {
|
||||
const time = new Date(CreatedOrUpdateTime);
|
||||
|
||||
const date = getFormattedDate(time);
|
||||
|
||||
const timeString = `${date} ${convertDateToAmAndPm(time)}`;
|
||||
|
||||
if (CreatedOrUpdateTime === null) {
|
||||
return <Typography> - </Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography className="DateComponent-container">{timeString}</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
export default DateComponent;
|
11
frontend/src/components/ResizeTable/contants.ts
Normal file
11
frontend/src/components/ResizeTable/contants.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const TableDataSource = {
|
||||
Alert: 'alert',
|
||||
Dashboard: 'dashboard',
|
||||
} as const;
|
||||
|
||||
export const DynamicColumnsKey = {
|
||||
CreatedAt: 'createdAt',
|
||||
CreatedBy: 'createdBy',
|
||||
UpdatedAt: 'updatedAt',
|
||||
UpdatedBy: 'updatedBy',
|
||||
};
|
@ -1,6 +1,32 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { TableProps } from 'antd';
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import { ColumnGroupType, ColumnType } from 'antd/lib/table';
|
||||
|
||||
import { TableDataSource } from './contants';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export interface ResizeTableProps extends TableProps<any> {
|
||||
onDragColumn?: (fromIndex: number, toIndex: number) => void;
|
||||
}
|
||||
export interface DynamicColumnTableProps extends TableProps<any> {
|
||||
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
|
||||
dynamicColumns: TableProps<any>['columns'];
|
||||
onDragColumn?: (fromIndex: number, toIndex: number) => void;
|
||||
}
|
||||
|
||||
export type GetVisibleColumnsFunction = (
|
||||
props: GetVisibleColumnProps,
|
||||
) => (ColumnGroupType<any> | ColumnType<any>)[];
|
||||
|
||||
export type GetVisibleColumnProps = {
|
||||
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
|
||||
dynamicColumns?: ColumnsType<any>;
|
||||
columnsData?: ColumnsType;
|
||||
};
|
||||
|
||||
export type SetVisibleColumnsProps = {
|
||||
checked: boolean;
|
||||
index: number;
|
||||
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
|
||||
dynamicColumns?: ColumnsType<any>;
|
||||
};
|
||||
|
57
frontend/src/components/ResizeTable/unit.ts
Normal file
57
frontend/src/components/ResizeTable/unit.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { DynamicColumnsKey } from './contants';
|
||||
import {
|
||||
GetVisibleColumnProps,
|
||||
GetVisibleColumnsFunction,
|
||||
SetVisibleColumnsProps,
|
||||
} from './types';
|
||||
|
||||
export const getVisibleColumns: GetVisibleColumnsFunction = ({
|
||||
tablesource,
|
||||
dynamicColumns,
|
||||
columnsData,
|
||||
}: GetVisibleColumnProps) => {
|
||||
let columnVisibilityData: { [key: string]: boolean };
|
||||
try {
|
||||
const storedData = localStorage.getItem(tablesource);
|
||||
if (typeof storedData === 'string' && dynamicColumns) {
|
||||
columnVisibilityData = JSON.parse(storedData);
|
||||
return dynamicColumns.filter((column) => {
|
||||
if (column.key && !columnsData?.find((c) => c.key === column.key)) {
|
||||
return columnVisibilityData[column.key];
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
const initialColumnVisibility: Record<string, boolean> = {};
|
||||
Object.values(DynamicColumnsKey).forEach((key) => {
|
||||
initialColumnVisibility[key] = false;
|
||||
});
|
||||
|
||||
localStorage.setItem(tablesource, JSON.stringify(initialColumnVisibility));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const setVisibleColumns = ({
|
||||
checked,
|
||||
index,
|
||||
tablesource,
|
||||
dynamicColumns,
|
||||
}: SetVisibleColumnsProps): void => {
|
||||
try {
|
||||
const storedData = localStorage.getItem(tablesource);
|
||||
if (typeof storedData === 'string' && dynamicColumns) {
|
||||
const columnVisibilityData = JSON.parse(storedData);
|
||||
const { key } = dynamicColumns[index];
|
||||
if (key) {
|
||||
columnVisibilityData[key] = checked;
|
||||
}
|
||||
localStorage.setItem(tablesource, JSON.stringify(columnVisibilityData));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
@ -0,0 +1,9 @@
|
||||
.LabelColumn {
|
||||
.LabelColumn-label-tag {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
}
|
||||
.labelColumn-popover {
|
||||
margin: 0.5rem 0;
|
||||
}
|
67
frontend/src/components/TableRenderer/LabelColumn.tsx
Normal file
67
frontend/src/components/TableRenderer/LabelColumn.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import './LabelColumn.styles.scss';
|
||||
|
||||
import { Popover, Tag, Tooltip } from 'antd';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { LabelColumnProps } from './TableRenderer.types';
|
||||
import { getLabelRenderingValue } from './utils';
|
||||
|
||||
function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element {
|
||||
const newLabels = labels.length > 3 ? labels.slice(0, 3) : labels;
|
||||
const remainingLabels = labels.length > 3 ? labels.slice(3) : [];
|
||||
|
||||
return (
|
||||
<div className="LabelColumn">
|
||||
{newLabels.map(
|
||||
(label: string): JSX.Element => {
|
||||
const tooltipTitle =
|
||||
value && value[label] ? `${label}: ${value[label]}` : label;
|
||||
return (
|
||||
<Tooltip title={tooltipTitle} key={label}>
|
||||
<Tag className="LabelColumn-label-tag" color={color}>
|
||||
{getLabelRenderingValue(label, value && value[label])}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
)}
|
||||
{remainingLabels.length > 0 && (
|
||||
<Popover
|
||||
getPopupContainer={popupContainer}
|
||||
placement="bottomRight"
|
||||
showArrow={false}
|
||||
content={
|
||||
<div>
|
||||
{labels.map(
|
||||
(label: string): JSX.Element => {
|
||||
const tooltipTitle =
|
||||
value && value[label] ? `${label}: ${value[label]}` : label;
|
||||
return (
|
||||
<div className="labelColumn-popover" key={label}>
|
||||
<Tooltip title={tooltipTitle}>
|
||||
<Tag className="LabelColumn-label-tag" color={color}>
|
||||
{getLabelRenderingValue(label, value && value[label])}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
trigger="hover"
|
||||
>
|
||||
<Tag className="LabelColumn-label-tag" color={color}>
|
||||
+{remainingLabels.length}
|
||||
</Tag>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
LabelColumn.defaultProps = {
|
||||
value: {},
|
||||
};
|
||||
|
||||
export default LabelColumn;
|
@ -0,0 +1,5 @@
|
||||
export type LabelColumnProps = {
|
||||
labels: string[];
|
||||
color?: string;
|
||||
value?: { [key: string]: string };
|
||||
};
|
@ -16,6 +16,28 @@ export const generatorResizeTableColumns = <T>({
|
||||
};
|
||||
});
|
||||
|
||||
export const getLabelRenderingValue = (
|
||||
label: string,
|
||||
value?: string,
|
||||
): string => {
|
||||
const maxLength = 20;
|
||||
|
||||
if (label.length > maxLength) {
|
||||
return `${label.slice(0, maxLength)}...`;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
const remainingSpace = maxLength - label.length;
|
||||
let newValue = value;
|
||||
if (value.length > remainingSpace) {
|
||||
newValue = `${value.slice(0, remainingSpace)}...`;
|
||||
}
|
||||
return `${label}: ${newValue}`;
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
interface GeneratorResizeTableColumnsProp<T> {
|
||||
baseColumnOptions: ColumnsType<T>;
|
||||
dynamicColumnOption: { key: string; columnOption: ColumnType<T> }[];
|
||||
|
@ -3,7 +3,14 @@ import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import saveAlertApi from 'api/alerts/save';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import DropDown from 'components/DropDown/DropDown';
|
||||
import {
|
||||
DynamicColumnsKey,
|
||||
TableDataSource,
|
||||
} from 'components/ResizeTable/contants';
|
||||
import DynamicColumnTable from 'components/ResizeTable/DynamicColumnTable';
|
||||
import DateComponent from 'components/ResizeTable/TableComponent/Date';
|
||||
import LabelColumn from 'components/TableRenderer/LabelColumn';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
@ -22,7 +29,7 @@ import { GettableAlert } from 'types/api/alerts/get';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import DeleteAlert from './DeleteAlert';
|
||||
import { Button, ButtonContainer, ColumnButton, StyledTag } from './styles';
|
||||
import { Button, ButtonContainer, ColumnButton } from './styles';
|
||||
import Status from './TableComponents/Status';
|
||||
import ToggleAlertState from './ToggleAlertState';
|
||||
|
||||
@ -121,6 +128,53 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
}
|
||||
};
|
||||
|
||||
const dynamicColumns: ColumnsType<GettableAlert> = [
|
||||
{
|
||||
title: 'Created At',
|
||||
dataIndex: 'createAt',
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.CreatedAt,
|
||||
align: 'center',
|
||||
sorter: (a: GettableAlert, b: GettableAlert): number => {
|
||||
const prev = new Date(a.createAt).getTime();
|
||||
const next = new Date(b.createAt).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: DateComponent,
|
||||
},
|
||||
{
|
||||
title: 'Created By',
|
||||
dataIndex: 'createBy',
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.CreatedBy,
|
||||
align: 'center',
|
||||
render: (value): JSX.Element => <div>{value}</div>,
|
||||
},
|
||||
{
|
||||
title: 'Updated At',
|
||||
dataIndex: 'updateAt',
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.UpdatedAt,
|
||||
align: 'center',
|
||||
sorter: (a: GettableAlert, b: GettableAlert): number => {
|
||||
const prev = new Date(a.updateAt).getTime();
|
||||
const next = new Date(b.updateAt).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: DateComponent,
|
||||
},
|
||||
{
|
||||
title: 'Updated By',
|
||||
dataIndex: 'updateBy',
|
||||
width: 80,
|
||||
key: DynamicColumnsKey.UpdatedBy,
|
||||
align: 'center',
|
||||
render: (value): JSX.Element => <div>{value}</div>,
|
||||
},
|
||||
];
|
||||
|
||||
const columns: ColumnsType<GettableAlert> = [
|
||||
{
|
||||
title: 'Status',
|
||||
@ -178,13 +232,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{withOutSeverityKeys.map((e) => (
|
||||
<StyledTag key={e} color="magenta">
|
||||
{e}: {value[e]}
|
||||
</StyledTag>
|
||||
))}
|
||||
</>
|
||||
<LabelColumn labels={withOutSeverityKeys} value={value} color="magenta" />
|
||||
);
|
||||
},
|
||||
},
|
||||
@ -195,20 +243,30 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
title: 'Action',
|
||||
dataIndex: 'id',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
width: 10,
|
||||
render: (id: GettableAlert['id'], record): JSX.Element => (
|
||||
<>
|
||||
<ToggleAlertState disabled={record.disabled} setData={setData} id={id} />
|
||||
|
||||
<ColumnButton onClick={onEditHandler(record)} type="link">
|
||||
Edit
|
||||
</ColumnButton>
|
||||
<ColumnButton onClick={onCloneHandler(record)} type="link">
|
||||
Clone
|
||||
</ColumnButton>
|
||||
|
||||
<DeleteAlert notifications={notificationsApi} setData={setData} id={id} />
|
||||
</>
|
||||
<DropDown
|
||||
element={[
|
||||
<ToggleAlertState
|
||||
key="1"
|
||||
disabled={record.disabled}
|
||||
setData={setData}
|
||||
id={id}
|
||||
/>,
|
||||
<ColumnButton key="2" onClick={onEditHandler(record)} type="link">
|
||||
Edit
|
||||
</ColumnButton>,
|
||||
<ColumnButton key="3" onClick={onCloneHandler(record)} type="link">
|
||||
Clone
|
||||
</ColumnButton>,
|
||||
<DeleteAlert
|
||||
key="4"
|
||||
notifications={notificationsApi}
|
||||
setData={setData}
|
||||
id={id}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
@ -229,7 +287,13 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
</Button>
|
||||
)}
|
||||
</ButtonContainer>
|
||||
<ResizeTable columns={columns} rowKey="id" dataSource={data} />
|
||||
<DynamicColumnTable
|
||||
tablesource={TableDataSource.Alert}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data}
|
||||
dynamicColumns={dynamicColumns}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Button as ButtonComponent, Tag } from 'antd';
|
||||
import { Button as ButtonComponent } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const ButtonContainer = styled.div`
|
||||
@ -23,9 +23,3 @@ export const ColumnButton = styled(ButtonComponent)`
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledTag = styled(Tag)`
|
||||
&&& {
|
||||
white-space: normal;
|
||||
}
|
||||
`;
|
||||
|
@ -10,6 +10,8 @@ describe('executeSearchQueries', () => {
|
||||
uuid: uuid(),
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
created_by: '',
|
||||
updated_by: '',
|
||||
data: {
|
||||
title: 'first dashboard',
|
||||
variables: {},
|
||||
@ -20,6 +22,8 @@ describe('executeSearchQueries', () => {
|
||||
uuid: uuid(),
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
created_by: '',
|
||||
updated_by: '',
|
||||
data: {
|
||||
title: 'second dashboard',
|
||||
variables: {},
|
||||
@ -30,6 +34,8 @@ describe('executeSearchQueries', () => {
|
||||
uuid: uuid(),
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
created_by: '',
|
||||
updated_by: '',
|
||||
data: {
|
||||
title: 'third dashboard (with special characters +?\\)',
|
||||
variables: {},
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { Typography } from 'antd';
|
||||
import convertDateToAmAndPm from 'lib/convertDateToAmAndPm';
|
||||
import getFormattedDate from 'lib/getFormatedDate';
|
||||
|
||||
import { Data } from '..';
|
||||
|
||||
function DateComponent(lastUpdatedTime: Data['lastUpdatedTime']): JSX.Element {
|
||||
const time = new Date(lastUpdatedTime);
|
||||
|
||||
const date = getFormattedDate(time);
|
||||
|
||||
const timeString = `${date} ${convertDateToAmAndPm(time)}`;
|
||||
|
||||
return <Typography>{timeString}</Typography>;
|
||||
}
|
||||
|
||||
export default DateComponent;
|
@ -45,18 +45,30 @@ function DeleteButton({ id }: Data): JSX.Element {
|
||||
|
||||
// This is to avoid the type collision
|
||||
function Wrapper(props: Data): JSX.Element {
|
||||
const { createdBy, description, id, key, lastUpdatedTime, name, tags } = props;
|
||||
const {
|
||||
createdAt,
|
||||
description,
|
||||
id,
|
||||
key,
|
||||
lastUpdatedTime,
|
||||
name,
|
||||
tags,
|
||||
createdBy,
|
||||
lastUpdatedBy,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<DeleteButton
|
||||
{...{
|
||||
createdBy,
|
||||
createdAt,
|
||||
description,
|
||||
id,
|
||||
key,
|
||||
lastUpdatedTime,
|
||||
name,
|
||||
tags,
|
||||
createdBy,
|
||||
lastUpdatedBy,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -10,7 +10,12 @@ import {
|
||||
import { ItemType } from 'antd/es/menu/hooks/useItems';
|
||||
import createDashboard from 'api/dashboard/create';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import {
|
||||
DynamicColumnsKey,
|
||||
TableDataSource,
|
||||
} from 'components/ResizeTable/contants';
|
||||
import DynamicColumnTable from 'components/ResizeTable/DynamicColumnTable';
|
||||
import LabelColumn from 'components/TableRenderer/LabelColumn';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
import ROUTES from 'constants/routes';
|
||||
import SearchFilter from 'container/ListOfDashboard/SearchFilter';
|
||||
@ -26,13 +31,11 @@ import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import DateComponent from '../../components/ResizeTable/TableComponent/Date';
|
||||
import ImportJSON from './ImportJSON';
|
||||
import { ButtonContainer, NewDashboardButton, TableContainer } from './styles';
|
||||
import Createdby from './TableComponents/CreatedBy';
|
||||
import DateComponent from './TableComponents/Date';
|
||||
import DeleteButton from './TableComponents/DeleteButton';
|
||||
import Name from './TableComponents/Name';
|
||||
import Tags from './TableComponents/Tags';
|
||||
|
||||
function ListOfAllDashboard(): JSX.Element {
|
||||
const {
|
||||
@ -71,48 +74,68 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
errorMessage: '',
|
||||
});
|
||||
|
||||
const dynamicColumns: TableColumnProps<Data>[] = [
|
||||
{
|
||||
title: 'Created At',
|
||||
dataIndex: 'createdAt',
|
||||
width: 30,
|
||||
key: DynamicColumnsKey.CreatedAt,
|
||||
sorter: (a: Data, b: Data): number => {
|
||||
console.log({ a });
|
||||
const prev = new Date(a.createdAt).getTime();
|
||||
const next = new Date(b.createdAt).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: DateComponent,
|
||||
},
|
||||
{
|
||||
title: 'Created By',
|
||||
dataIndex: 'createdBy',
|
||||
width: 30,
|
||||
key: DynamicColumnsKey.CreatedBy,
|
||||
render: (value): JSX.Element => <div>{value}</div>,
|
||||
},
|
||||
{
|
||||
title: 'Last Updated Time',
|
||||
width: 30,
|
||||
dataIndex: 'lastUpdatedTime',
|
||||
key: DynamicColumnsKey.UpdatedAt,
|
||||
sorter: (a: Data, b: Data): number => {
|
||||
const prev = new Date(a.lastUpdatedTime).getTime();
|
||||
const next = new Date(b.lastUpdatedTime).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: DateComponent,
|
||||
},
|
||||
{
|
||||
title: 'Last Updated By',
|
||||
dataIndex: 'lastUpdatedBy',
|
||||
width: 30,
|
||||
key: DynamicColumnsKey.UpdatedBy,
|
||||
render: (value): JSX.Element => <div>{value}</div>,
|
||||
},
|
||||
];
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const tableColumns: TableColumnProps<Data>[] = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
width: 40,
|
||||
render: Name,
|
||||
},
|
||||
{
|
||||
title: 'Description',
|
||||
width: 100,
|
||||
width: 50,
|
||||
dataIndex: 'description',
|
||||
},
|
||||
{
|
||||
title: 'Tags (can be multiple)',
|
||||
dataIndex: 'tags',
|
||||
width: 80,
|
||||
render: Tags,
|
||||
},
|
||||
{
|
||||
title: 'Created At',
|
||||
dataIndex: 'createdBy',
|
||||
width: 80,
|
||||
sorter: (a: Data, b: Data): number => {
|
||||
const prev = new Date(a.createdBy).getTime();
|
||||
const next = new Date(b.createdBy).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: Createdby,
|
||||
},
|
||||
{
|
||||
title: 'Last Updated Time',
|
||||
width: 90,
|
||||
dataIndex: 'lastUpdatedTime',
|
||||
sorter: (a: Data, b: Data): number => {
|
||||
const prev = new Date(a.lastUpdatedTime).getTime();
|
||||
const next = new Date(b.lastUpdatedTime).getTime();
|
||||
|
||||
return prev - next;
|
||||
},
|
||||
render: DateComponent,
|
||||
width: 50,
|
||||
render: (value): JSX.Element => <LabelColumn labels={value} />,
|
||||
},
|
||||
];
|
||||
|
||||
@ -130,13 +153,15 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
|
||||
const data: Data[] =
|
||||
filteredDashboards?.map((e) => ({
|
||||
createdBy: e.created_at,
|
||||
createdAt: e.created_at,
|
||||
description: e.data.description || '',
|
||||
id: e.uuid,
|
||||
lastUpdatedTime: e.updated_at,
|
||||
name: e.data.title,
|
||||
tags: e.data.tags || [],
|
||||
key: e.uuid,
|
||||
createdBy: e.created_by,
|
||||
lastUpdatedBy: e.updated_by,
|
||||
refetchDashboardList,
|
||||
})) || [];
|
||||
|
||||
@ -290,7 +315,9 @@ function ListOfAllDashboard(): JSX.Element {
|
||||
uploadedGrafana={uploadedGrafana}
|
||||
onModalHandler={(): void => onModalHandler(false)}
|
||||
/>
|
||||
<ResizeTable
|
||||
<DynamicColumnTable
|
||||
tablesource={TableDataSource.Dashboard}
|
||||
dynamicColumns={dynamicColumns}
|
||||
columns={columns}
|
||||
pagination={{
|
||||
pageSize: 9,
|
||||
@ -314,7 +341,9 @@ export interface Data {
|
||||
description: string;
|
||||
tags: string[];
|
||||
createdBy: string;
|
||||
createdAt: string;
|
||||
lastUpdatedTime: string;
|
||||
lastUpdatedBy: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,10 @@ export interface GettableAlert extends AlertDef {
|
||||
alert: string;
|
||||
state: string;
|
||||
disabled: boolean;
|
||||
createAt: string;
|
||||
createBy: string;
|
||||
updateAt: string;
|
||||
updateBy: string;
|
||||
}
|
||||
|
||||
export type PayloadProps = {
|
||||
|
@ -42,6 +42,8 @@ export interface Dashboard {
|
||||
uuid: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: string;
|
||||
updated_by: string;
|
||||
data: DashboardData;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user