feat: all dashboard is migrated to useQuery and action is removed (#3384)

* feat: all dashboard is migrated to useQuery and action is removed

* chore: delete functionality is updated

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
Himanshu Gupta 2023-09-11 10:51:10 +05:30 committed by GitHub
parent dfd94f67bd
commit 41f7a7993d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 124 deletions

View File

@ -1,24 +1,8 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/dashboard/getAll';
import { ApiResponse } from 'types/api';
import { Dashboard } from 'types/api/dashboard/getAll';
const getAll = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get('/dashboards');
return {
statusCode: 200,
error: null,
message: response.data.message,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getAll;
export const getAllDashboardList = (): Promise<Dashboard[]> =>
axios
.get<ApiResponse<Dashboard[]>>('/dashboards')
.then((res) => res.data.data);

View File

@ -44,10 +44,10 @@ function ExportPanel({ isLoading, onExport }: ExportPanelProps): JSX.Element {
onError: handleError,
});
const options = useMemo(() => getSelectOptions(data?.payload || []), [data]);
const options = useMemo(() => getSelectOptions(data || []), [data]);
const handleExportClick = useCallback((): void => {
const currentSelectedDashboard = data?.payload?.find(
const currentSelectedDashboard = data?.find(
({ uuid }) => uuid === selectedDashboardId,
);

View File

@ -10,7 +10,11 @@ import AppActions from 'types/actions';
import { Data } from '../index';
import { TableLinkText } from './styles';
function DeleteButton({ deleteDashboard, id }: DeleteButtonProps): JSX.Element {
function DeleteButton({
deleteDashboard,
id,
refetchDashboardList,
}: DeleteButtonProps): JSX.Element {
const [modal, contextHolder] = Modal.useModal();
const openConfirmationDialog = useCallback((): void => {
@ -20,13 +24,14 @@ function DeleteButton({ deleteDashboard, id }: DeleteButtonProps): JSX.Element {
onOk() {
deleteDashboard({
uuid: id,
refetch: refetchDashboardList,
});
},
okText: 'Delete',
okButtonProps: { danger: true },
centered: true,
});
}, [id, modal, deleteDashboard]);
}, [modal, deleteDashboard, id, refetchDashboardList]);
return (
<>
@ -51,13 +56,22 @@ const mapDispatchToProps = (
deleteDashboard: bindActionCreators(DeleteDashboard, dispatch),
});
type DeleteButtonProps = Data & DispatchProps;
export type DeleteButtonProps = Data & DispatchProps;
const WrapperDeleteButton = connect(null, mapDispatchToProps)(DeleteButton);
// This is to avoid the type collision
function Wrapper(props: Data): JSX.Element {
const { createdBy, description, id, key, lastUpdatedTime, name, tags } = props;
const {
createdBy,
description,
id,
key,
refetchDashboardList,
lastUpdatedTime,
name,
tags,
} = props;
return (
<WrapperDeleteButton
@ -69,6 +83,7 @@ function Wrapper(props: Data): JSX.Element {
lastUpdatedTime,
name,
tags,
refetchDashboardList,
}}
/>
);

View File

@ -14,6 +14,7 @@ import { ResizeTable } from 'components/ResizeTable';
import TextToolTip from 'components/TextToolTip';
import ROUTES from 'constants/routes';
import SearchFilter from 'container/ListOfDashboard/SearchFilter';
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
import useComponentPermission from 'hooks/useComponentPermission';
import history from 'lib/history';
import {
@ -25,6 +26,7 @@ import {
useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { UseQueryResult } from 'react-query';
import { useDispatch, useSelector } from 'react-redux';
import { generatePath } from 'react-router-dom';
import { AppState } from 'store/reducers';
@ -32,20 +34,24 @@ import AppActions from 'types/actions';
import { GET_ALL_DASHBOARD_SUCCESS } from 'types/actions/dashboard';
import { Dashboard } from 'types/api/dashboard/getAll';
import AppReducer from 'types/reducer/app';
import DashboardReducer from 'types/reducer/dashboards';
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 DeleteButton, {
DeleteButtonProps,
} from './TableComponents/DeleteButton';
import Name from './TableComponents/Name';
import Tags from './TableComponents/Tags';
function ListOfAllDashboard(): JSX.Element {
const { dashboards, loading } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
);
const {
data: dashboardListResponse = [],
isLoading: isDashboardListLoading,
refetch: refetchDashboardList,
} = useGetAllDashboard();
const dispatch = useDispatch<Dispatch<AppActions>>();
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
@ -66,8 +72,10 @@ function ListOfAllDashboard(): JSX.Element {
const [filteredDashboards, setFilteredDashboards] = useState<Dashboard[]>();
useEffect(() => {
setFilteredDashboards(dashboards);
}, [dashboards]);
if (dashboardListResponse.length) {
setFilteredDashboards(dashboardListResponse);
}
}, [dashboardListResponse]);
const [newDashboardState, setNewDashboardState] = useState({
loading: false,
@ -125,22 +133,43 @@ function ListOfAllDashboard(): JSX.Element {
title: 'Action',
dataIndex: '',
width: 40,
render: DeleteButton,
render: ({
createdBy,
description,
id,
key,
lastUpdatedTime,
name,
tags,
}: DeleteButtonProps) => (
<DeleteButton
description={description}
id={id}
key={key}
lastUpdatedTime={lastUpdatedTime}
name={name}
tags={tags}
createdBy={createdBy}
refetchDashboardList={refetchDashboardList}
/>
),
});
}
return tableColumns;
}, [action]);
}, [action, refetchDashboardList]);
const data: Data[] = (filteredDashboards || dashboards).map((e) => ({
createdBy: 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,
}));
const data: Data[] =
filteredDashboards?.map((e) => ({
createdBy: 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,
refetchDashboardList,
})) || [];
const onNewDashboardHandler = useCallback(async () => {
try {
@ -209,7 +238,7 @@ function ListOfAllDashboard(): JSX.Element {
menuItems.push({
key: t('create_dashboard').toString(),
label: t('create_dashboard'),
disabled: loading,
disabled: isDashboardListLoading,
onClick: onNewDashboardHandler,
});
}
@ -228,7 +257,7 @@ function ListOfAllDashboard(): JSX.Element {
});
return menuItems;
}, [createNewDashboard, loading, onNewDashboardHandler, t]);
}, [createNewDashboard, isDashboardListLoading, onNewDashboardHandler, t]);
const menu: MenuProps = useMemo(
() => ({
@ -250,7 +279,11 @@ function ListOfAllDashboard(): JSX.Element {
}}
/>
{newDashboard && (
<Dropdown disabled={loading} trigger={['click']} menu={menu}>
<Dropdown
disabled={isDashboardListLoading}
trigger={['click']}
menu={menu}
>
<NewDashboardButton
icon={<PlusOutlined />}
type="primary"
@ -266,7 +299,7 @@ function ListOfAllDashboard(): JSX.Element {
),
[
newDashboard,
loading,
isDashboardListLoading,
menu,
newDashboardState.loading,
newDashboardState.error,
@ -278,9 +311,9 @@ function ListOfAllDashboard(): JSX.Element {
<Card>
{GetHeader}
{!loading && (
{!isDashboardListLoading && (
<SearchFilter
searchData={dashboards}
searchData={dashboardListResponse}
filterDashboards={setFilteredDashboards}
/>
)}
@ -300,7 +333,7 @@ function ListOfAllDashboard(): JSX.Element {
showHeader
bordered
sticky
loading={loading}
loading={isDashboardListLoading}
dataSource={data}
showSorterTooltip
/>
@ -317,6 +350,7 @@ export interface Data {
createdBy: string;
lastUpdatedTime: string;
id: string;
refetchDashboardList: UseQueryResult['refetch'];
}
export default ListOfAllDashboard;

View File

@ -1,16 +1,10 @@
import getAll from 'api/dashboard/getAll';
import { getAllDashboardList } from 'api/dashboard/getAll';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useQuery, UseQueryResult } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/dashboard/getAll';
import { Dashboard } from 'types/api/dashboard/getAll';
export const useGetAllDashboard = (): DashboardProps =>
useQuery({
queryFn: getAll,
export const useGetAllDashboard = (): UseQueryResult<Dashboard[], unknown> =>
useQuery<Dashboard[]>({
queryFn: getAllDashboardList,
queryKey: REACT_QUERY_KEY.GET_ALL_DASHBOARDS,
});
type DashboardProps = UseQueryResult<
SuccessResponse<PayloadProps> | ErrorResponse,
unknown
>;

View File

@ -1,19 +1,10 @@
import { Space } from 'antd';
import ReleaseNote from 'components/ReleaseNote';
import ListOfAllDashboard from 'container/ListOfDashboard';
import { useEffect } from 'react';
import { connect } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import { GetAllDashboards } from 'store/actions';
import AppActions from 'types/actions';
function Dashboard({ getAllDashboards }: DashboardProps): JSX.Element {
function Dashboard(): JSX.Element {
const location = useLocation();
useEffect(() => {
getAllDashboards();
}, [getAllDashboards]);
return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
@ -23,16 +14,4 @@ function Dashboard({ getAllDashboards }: DashboardProps): JSX.Element {
);
}
interface DispatchProps {
getAllDashboards: () => void;
}
const mapDispatchToProps = (
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
): DispatchProps => ({
getAllDashboards: bindActionCreators(GetAllDashboards, dispatch),
});
type DashboardProps = DispatchProps;
export default connect(null, mapDispatchToProps)(Dashboard);
export default Dashboard;

View File

@ -1,10 +1,12 @@
import deleteDashboardApi from 'api/dashboard/delete';
import { UseQueryResult } from 'react-query';
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
import { Dashboard } from 'types/api/dashboard/getAll';
export const DeleteDashboard = ({
uuid,
refetch,
}: DeleteDashboardProps): ((dispatch: Dispatch<AppActions>) => void) => async (
dispatch: Dispatch<AppActions>,
): Promise<void> => {
@ -14,6 +16,8 @@ export const DeleteDashboard = ({
});
if (response.statusCode === 200) {
refetch();
dispatch({
type: 'DELETE_DASHBOARD_SUCCESS',
payload: {
@ -41,4 +45,5 @@ export const DeleteDashboard = ({
export interface DeleteDashboardProps {
uuid: Dashboard['uuid'];
refetch: UseQueryResult['refetch'];
}

View File

@ -1,36 +0,0 @@
import getAll from 'api/dashboard/getAll';
import { AxiosError } from 'axios';
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
export const GetAllDashboards = (): ((
dispatch: Dispatch<AppActions>,
) => void) => async (dispatch: Dispatch<AppActions>): Promise<void> => {
try {
dispatch({
type: 'GET_ALL_DASHBOARD_LOADING_START',
});
const response = await getAll();
if (response.statusCode === 200) {
dispatch({
type: 'GET_ALL_DASHBOARD_SUCCESS',
payload: response.payload,
});
} else {
dispatch({
type: 'GET_ALL_DASHBOARD_ERROR',
payload: {
errorMessage: response.error || 'Something went wrong',
},
});
}
} catch (error) {
dispatch({
type: 'GET_ALL_DASHBOARD_ERROR',
payload: {
errorMessage: (error as AxiosError).toString() || 'Something went wrong',
},
});
}
};

View File

@ -1,7 +1,6 @@
export * from './applySettingsToPanel';
export * from './deleteDashboard';
export * from './deleteQuery';
export * from './getAllDashboard';
export * from './getDashboard';
export * from './toggleEditMode';
export * from './updateDashboardTitle';

View File

@ -1,5 +1,7 @@
import { ErrorStatusCode, SuccessStatusCode } from 'types/common';
export type ApiResponse<T> = { data: T };
export interface ErrorResponse {
statusCode: ErrorStatusCode;
payload: null;