import { PlusOutlined } from '@ant-design/icons'; import { Card, Col, Dropdown, Input, MenuProps, Row, TableColumnProps, } from 'antd'; import { ItemType } from 'antd/es/menu/hooks/useItems'; import createDashboard from 'api/dashboard/create'; import { AxiosError } from 'axios'; 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 { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard'; import useComponentPermission from 'hooks/useComponentPermission'; import useDebouncedFn from 'hooks/useDebouncedFunction'; import history from 'lib/history'; import { Key, useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { generatePath } from 'react-router-dom'; import { AppState } from 'store/reducers'; import { Dashboard } from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import { popupContainer } from 'utils/selectPopupContainer'; import DateComponent from '../../components/ResizeTable/TableComponent/DateComponent'; import ImportJSON from './ImportJSON'; import { ButtonContainer, NewDashboardButton, TableContainer } from './styles'; import DeleteButton from './TableComponents/DeleteButton'; import Name from './TableComponents/Name'; function ListOfAllDashboard(): JSX.Element { const { Search } = Input; const { data: dashboardListResponse = [], isLoading: isDashboardListLoading, refetch: refetchDashboardList, } = useGetAllDashboard(); const { role } = useSelector((state) => state.app); const [action, createNewDashboard, newDashboard] = useComponentPermission( ['action', 'create_new_dashboards', 'new_dashboard'], role, ); const { t } = useTranslation('dashboard'); const [ isImportJSONModalVisible, setIsImportJSONModalVisible, ] = useState(false); const [uploadedGrafana, setUploadedGrafana] = useState(false); const [isFilteringDashboards, setIsFilteringDashboards] = useState(false); const [dashboards, setDashboards] = useState(); const sortDashboardsByCreatedAt = (dashboards: Dashboard[]): void => { const sortedDashboards = dashboards.sort( (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime(), ); setDashboards(sortedDashboards); }; useEffect(() => { if (dashboardListResponse.length) { sortDashboardsByCreatedAt(dashboardListResponse); } }, [dashboardListResponse]); const [newDashboardState, setNewDashboardState] = useState({ loading: false, error: false, errorMessage: '', }); const dynamicColumns: TableColumnProps[] = [ { 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, }, { 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, }, ]; const columns = useMemo(() => { const tableColumns: TableColumnProps[] = [ { title: 'Name', dataIndex: 'name', width: 40, render: Name, }, { title: 'Description', width: 50, dataIndex: 'description', }, { title: 'Tags', dataIndex: 'tags', width: 50, render: (value): JSX.Element => , }, ]; if (action) { tableColumns.push({ title: 'Action', dataIndex: '', width: 40, render: DeleteButton, }); } return tableColumns; }, [action]); const data: Data[] = dashboards?.map((e) => ({ 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, isLocked: !!e.isLocked || false, lastUpdatedBy: e.updated_by, refetchDashboardList, })) || []; const onNewDashboardHandler = useCallback(async () => { try { setNewDashboardState({ ...newDashboardState, loading: true, }); const response = await createDashboard({ title: t('new_dashboard_title', { ns: 'dashboard', }), uploadedGrafana: false, }); if (response.statusCode === 200) { history.push( generatePath(ROUTES.DASHBOARD, { dashboardId: response.payload.uuid, }), ); } else { setNewDashboardState({ ...newDashboardState, loading: false, error: true, errorMessage: response.error || 'Something went wrong', }); } } catch (error) { setNewDashboardState({ ...newDashboardState, error: true, errorMessage: (error as AxiosError).toString() || 'Something went Wrong', }); } }, [newDashboardState, t]); const getText = useCallback(() => { if (!newDashboardState.error && !newDashboardState.loading) { return 'New Dashboard'; } if (newDashboardState.loading) { return 'Loading'; } return newDashboardState.errorMessage; }, [ newDashboardState.error, newDashboardState.errorMessage, newDashboardState.loading, ]); const onModalHandler = (uploadedGrafana: boolean): void => { setIsImportJSONModalVisible((state) => !state); setUploadedGrafana(uploadedGrafana); }; const getMenuItems = useMemo(() => { const menuItems: ItemType[] = []; if (createNewDashboard) { menuItems.push({ key: t('create_dashboard').toString(), label: t('create_dashboard'), disabled: isDashboardListLoading, onClick: onNewDashboardHandler, }); } menuItems.push({ key: t('import_json').toString(), label: t('import_json'), onClick: (): void => onModalHandler(false), }); menuItems.push({ key: t('import_grafana_json').toString(), label: t('import_grafana_json'), onClick: (): void => onModalHandler(true), disabled: true, }); return menuItems; }, [createNewDashboard, isDashboardListLoading, onNewDashboardHandler, t]); const menu: MenuProps = useMemo( () => ({ items: getMenuItems, }), [getMenuItems], ); const searchArrayOfObjects = (searchValue: string): any[] => { // Convert the searchValue to lowercase for case-insensitive search const searchValueLowerCase = searchValue.toLowerCase(); // Use the filter method to find matching objects return dashboardListResponse.filter((item: any) => { // Convert each property value to lowercase for case-insensitive search const itemValues = Object.values(item?.data).map((value: any) => value.toString().toLowerCase(), ); // Check if any property value contains the searchValue return itemValues.some((value) => value.includes(searchValueLowerCase)); }); }; const handleSearch = useDebouncedFn((event: unknown): void => { setIsFilteringDashboards(true); const searchText = (event as React.BaseSyntheticEvent)?.target?.value || ''; const filteredDashboards = searchArrayOfObjects(searchText); setDashboards(filteredDashboards); setIsFilteringDashboards(false); }, 500); const GetHeader = useMemo( () => ( {newDashboard && ( } type="primary" data-testid="create-new-dashboard" loading={newDashboardState.loading} danger={newDashboardState.error} > {getText()} )} ), [ Search, isDashboardListLoading, handleSearch, isFilteringDashboards, newDashboard, menu, newDashboardState.loading, newDashboardState.error, getText, ], ); return ( {GetHeader} onModalHandler(false)} /> ); } export interface Data { key: Key; name: string; description: string; tags: string[]; createdBy: string; createdAt: string; lastUpdatedTime: string; lastUpdatedBy: string; isLocked: boolean; id: string; } export default ListOfAllDashboard;