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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ApiResponse } from 'types/api';
import { AxiosError } from 'axios'; import { Dashboard } from 'types/api/dashboard/getAll';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/dashboard/getAll';
const getAll = async (): Promise< export const getAllDashboardList = (): Promise<Dashboard[]> =>
SuccessResponse<PayloadProps> | ErrorResponse axios
> => { .get<ApiResponse<Dashboard[]>>('/dashboards')
try { .then((res) => res.data.data);
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;

View File

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

View File

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

View File

@ -14,6 +14,7 @@ import { ResizeTable } from 'components/ResizeTable';
import TextToolTip from 'components/TextToolTip'; import TextToolTip from 'components/TextToolTip';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import SearchFilter from 'container/ListOfDashboard/SearchFilter'; import SearchFilter from 'container/ListOfDashboard/SearchFilter';
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
import useComponentPermission from 'hooks/useComponentPermission'; import useComponentPermission from 'hooks/useComponentPermission';
import history from 'lib/history'; import history from 'lib/history';
import { import {
@ -25,6 +26,7 @@ import {
useState, useState,
} from 'react'; } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { UseQueryResult } from 'react-query';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { generatePath } from 'react-router-dom'; import { generatePath } from 'react-router-dom';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
@ -32,20 +34,24 @@ import AppActions from 'types/actions';
import { GET_ALL_DASHBOARD_SUCCESS } from 'types/actions/dashboard'; import { GET_ALL_DASHBOARD_SUCCESS } from 'types/actions/dashboard';
import { Dashboard } from 'types/api/dashboard/getAll'; import { Dashboard } from 'types/api/dashboard/getAll';
import AppReducer from 'types/reducer/app'; import AppReducer from 'types/reducer/app';
import DashboardReducer from 'types/reducer/dashboards';
import ImportJSON from './ImportJSON'; import ImportJSON from './ImportJSON';
import { ButtonContainer, NewDashboardButton, TableContainer } from './styles'; import { ButtonContainer, NewDashboardButton, TableContainer } from './styles';
import Createdby from './TableComponents/CreatedBy'; import Createdby from './TableComponents/CreatedBy';
import DateComponent from './TableComponents/Date'; import DateComponent from './TableComponents/Date';
import DeleteButton from './TableComponents/DeleteButton'; import DeleteButton, {
DeleteButtonProps,
} from './TableComponents/DeleteButton';
import Name from './TableComponents/Name'; import Name from './TableComponents/Name';
import Tags from './TableComponents/Tags'; import Tags from './TableComponents/Tags';
function ListOfAllDashboard(): JSX.Element { function ListOfAllDashboard(): JSX.Element {
const { dashboards, loading } = useSelector<AppState, DashboardReducer>( const {
(state) => state.dashboards, data: dashboardListResponse = [],
); isLoading: isDashboardListLoading,
refetch: refetchDashboardList,
} = useGetAllDashboard();
const dispatch = useDispatch<Dispatch<AppActions>>(); const dispatch = useDispatch<Dispatch<AppActions>>();
const { role } = useSelector<AppState, AppReducer>((state) => state.app); const { role } = useSelector<AppState, AppReducer>((state) => state.app);
@ -66,8 +72,10 @@ function ListOfAllDashboard(): JSX.Element {
const [filteredDashboards, setFilteredDashboards] = useState<Dashboard[]>(); const [filteredDashboards, setFilteredDashboards] = useState<Dashboard[]>();
useEffect(() => { useEffect(() => {
setFilteredDashboards(dashboards); if (dashboardListResponse.length) {
}, [dashboards]); setFilteredDashboards(dashboardListResponse);
}
}, [dashboardListResponse]);
const [newDashboardState, setNewDashboardState] = useState({ const [newDashboardState, setNewDashboardState] = useState({
loading: false, loading: false,
@ -125,14 +133,34 @@ function ListOfAllDashboard(): JSX.Element {
title: 'Action', title: 'Action',
dataIndex: '', dataIndex: '',
width: 40, 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; return tableColumns;
}, [action]); }, [action, refetchDashboardList]);
const data: Data[] = (filteredDashboards || dashboards).map((e) => ({ const data: Data[] =
filteredDashboards?.map((e) => ({
createdBy: e.created_at, createdBy: e.created_at,
description: e.data.description || '', description: e.data.description || '',
id: e.uuid, id: e.uuid,
@ -140,7 +168,8 @@ function ListOfAllDashboard(): JSX.Element {
name: e.data.title, name: e.data.title,
tags: e.data.tags || [], tags: e.data.tags || [],
key: e.uuid, key: e.uuid,
})); refetchDashboardList,
})) || [];
const onNewDashboardHandler = useCallback(async () => { const onNewDashboardHandler = useCallback(async () => {
try { try {
@ -209,7 +238,7 @@ function ListOfAllDashboard(): JSX.Element {
menuItems.push({ menuItems.push({
key: t('create_dashboard').toString(), key: t('create_dashboard').toString(),
label: t('create_dashboard'), label: t('create_dashboard'),
disabled: loading, disabled: isDashboardListLoading,
onClick: onNewDashboardHandler, onClick: onNewDashboardHandler,
}); });
} }
@ -228,7 +257,7 @@ function ListOfAllDashboard(): JSX.Element {
}); });
return menuItems; return menuItems;
}, [createNewDashboard, loading, onNewDashboardHandler, t]); }, [createNewDashboard, isDashboardListLoading, onNewDashboardHandler, t]);
const menu: MenuProps = useMemo( const menu: MenuProps = useMemo(
() => ({ () => ({
@ -250,7 +279,11 @@ function ListOfAllDashboard(): JSX.Element {
}} }}
/> />
{newDashboard && ( {newDashboard && (
<Dropdown disabled={loading} trigger={['click']} menu={menu}> <Dropdown
disabled={isDashboardListLoading}
trigger={['click']}
menu={menu}
>
<NewDashboardButton <NewDashboardButton
icon={<PlusOutlined />} icon={<PlusOutlined />}
type="primary" type="primary"
@ -266,7 +299,7 @@ function ListOfAllDashboard(): JSX.Element {
), ),
[ [
newDashboard, newDashboard,
loading, isDashboardListLoading,
menu, menu,
newDashboardState.loading, newDashboardState.loading,
newDashboardState.error, newDashboardState.error,
@ -278,9 +311,9 @@ function ListOfAllDashboard(): JSX.Element {
<Card> <Card>
{GetHeader} {GetHeader}
{!loading && ( {!isDashboardListLoading && (
<SearchFilter <SearchFilter
searchData={dashboards} searchData={dashboardListResponse}
filterDashboards={setFilteredDashboards} filterDashboards={setFilteredDashboards}
/> />
)} )}
@ -300,7 +333,7 @@ function ListOfAllDashboard(): JSX.Element {
showHeader showHeader
bordered bordered
sticky sticky
loading={loading} loading={isDashboardListLoading}
dataSource={data} dataSource={data}
showSorterTooltip showSorterTooltip
/> />
@ -317,6 +350,7 @@ export interface Data {
createdBy: string; createdBy: string;
lastUpdatedTime: string; lastUpdatedTime: string;
id: string; id: string;
refetchDashboardList: UseQueryResult['refetch'];
} }
export default ListOfAllDashboard; 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 { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useQuery, UseQueryResult } from 'react-query'; import { useQuery, UseQueryResult } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { Dashboard } from 'types/api/dashboard/getAll';
import { PayloadProps } from 'types/api/dashboard/getAll';
export const useGetAllDashboard = (): DashboardProps => export const useGetAllDashboard = (): UseQueryResult<Dashboard[], unknown> =>
useQuery({ useQuery<Dashboard[]>({
queryFn: getAll, queryFn: getAllDashboardList,
queryKey: REACT_QUERY_KEY.GET_ALL_DASHBOARDS, 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 { Space } from 'antd';
import ReleaseNote from 'components/ReleaseNote'; import ReleaseNote from 'components/ReleaseNote';
import ListOfAllDashboard from 'container/ListOfDashboard'; import ListOfAllDashboard from 'container/ListOfDashboard';
import { useEffect } from 'react';
import { connect } from 'react-redux';
import { useLocation } from 'react-router-dom'; 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(); const location = useLocation();
useEffect(() => {
getAllDashboards();
}, [getAllDashboards]);
return ( return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}> <Space direction="vertical" size="middle" style={{ width: '100%' }}>
@ -23,16 +14,4 @@ function Dashboard({ getAllDashboards }: DashboardProps): JSX.Element {
); );
} }
interface DispatchProps { export default Dashboard;
getAllDashboards: () => void;
}
const mapDispatchToProps = (
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
): DispatchProps => ({
getAllDashboards: bindActionCreators(GetAllDashboards, dispatch),
});
type DashboardProps = DispatchProps;
export default connect(null, mapDispatchToProps)(Dashboard);

View File

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

View File

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