From a549c24ecfd7db2afa96c01df9496bf155685cc2 Mon Sep 17 00:00:00 2001 From: MVarshini Date: Wed, 9 Aug 2023 00:18:53 +0530 Subject: [PATCH] Dashboard TOC view (#3511) * PBENCH-1217 Fix the TOC page and add a download link for regular files --- .../src/actions/tableOfContentActions.js | 60 ++- dashboard/src/actions/types.js | 2 +- .../assets/constants/navigationConstants.js | 1 - .../components/TableComponent/index.jsx | 5 +- .../components/TableOfContent/index.jsx | 390 +++++++++--------- .../components/TableOfContent/index.less | 26 +- .../src/reducers/tableOfContentReducer.js | 17 +- dashboard/src/utils/routeConstants.js | 1 + 8 files changed, 248 insertions(+), 254 deletions(-) delete mode 100644 dashboard/src/assets/constants/navigationConstants.js diff --git a/dashboard/src/actions/tableOfContentActions.js b/dashboard/src/actions/tableOfContentActions.js index 6f941ebdf6..d844e1a5f2 100644 --- a/dashboard/src/actions/tableOfContentActions.js +++ b/dashboard/src/actions/tableOfContentActions.js @@ -1,13 +1,16 @@ import * as TYPES from "./types"; + import API from "../utils/axiosInstance"; -import { uriTemplate } from "../utils/helper"; -import { showToast } from "./toastActions"; import { DANGER } from "assets/constants/toastConstants"; +import { showToast } from "./toastActions"; +import { uriTemplate } from "../utils/helper"; export const fetchTOC = - (param, parent, callForSubData) => async (dispatch, getState) => { + (param, dataUri, callForSubData) => async (dispatch, getState) => { try { + dispatch({ type: TYPES.LOADING }); const endpoints = getState().apiEndpoint.endpoints; + const parent = dataUri?.split("contents/").pop(); const uri = uriTemplate(endpoints, "datasets_contents", { dataset: param, target: parent, @@ -23,39 +26,30 @@ export const fetchTOC = const msg = error.response?.data?.message; dispatch(showToast(DANGER, msg ?? `Error response: ${error}`)); } + dispatch({ type: TYPES.COMPLETED }); }; -export const updateTableData = (data) => { - return { - type: TYPES.UPDATE_TABLE_DATA, - payload: data, - }; -}; +export const updateTableData = (data) => ({ + type: TYPES.UPDATE_TABLE_DATA, + payload: data, +}); -export const updateSearchSpace = (data) => { - return { - type: TYPES.UPDATE_SEARCH_SPACE, - payload: data, - }; -}; +export const updateContentData = (data) => ({ + type: TYPES.UPDATE_CONTENT_DATA, + payload: data, +}); -export const updateStack = (length) => { - return { - type: TYPES.UPDATE_STACK, - payload: length, - }; -}; +export const updateSearchSpace = (data) => ({ + type: TYPES.UPDATE_SEARCH_SPACE, + payload: data, +}); -export const updateCurrData = (data) => { - return { - type: TYPES.UPDATE_CURR_DATA, - payload: data, - }; -}; +export const updateStack = (length) => ({ + type: TYPES.UPDATE_STACK, + payload: length, +}); -export const updateTOCLoader = (data) => { - return { - type: TYPES.UPDATE_TOC_LOADING, - payload: data, - }; -}; +export const updateCurrData = (data) => ({ + type: TYPES.UPDATE_CURR_DATA, + payload: data, +}); diff --git a/dashboard/src/actions/types.js b/dashboard/src/actions/types.js index a9cc6a9d98..67080e4323 100644 --- a/dashboard/src/actions/types.js +++ b/dashboard/src/actions/types.js @@ -50,7 +50,7 @@ export const UPDATE_TABLE_DATA = "UPDATE_TABLE_DATA"; export const UPDATE_SEARCH_SPACE = "UPDATE_SEARCH_SPACE"; export const UPDATE_STACK = "UPDATE_STACK"; export const UPDATE_CURR_DATA = "UPDATE_CURR_DATA"; -export const UPDATE_TOC_LOADING = "UPDATE_TOC_LOADING"; +export const UPDATE_CONTENT_DATA = "UPDATE_CONTENT_DATA"; /* SIDEBAR */ export const SET_ACTIVE_MENU_ITEM = "SET_ACTIVE_MENU_ITEM"; diff --git a/dashboard/src/assets/constants/navigationConstants.js b/dashboard/src/assets/constants/navigationConstants.js deleted file mode 100644 index 8eb398c9e6..0000000000 --- a/dashboard/src/assets/constants/navigationConstants.js +++ /dev/null @@ -1 +0,0 @@ -export const TOC = "toc"; diff --git a/dashboard/src/modules/components/TableComponent/index.jsx b/dashboard/src/modules/components/TableComponent/index.jsx index 6dcb0cce2d..b2f4163977 100644 --- a/dashboard/src/modules/components/TableComponent/index.jsx +++ b/dashboard/src/modules/components/TableComponent/index.jsx @@ -4,6 +4,7 @@ import * as APP_ROUTES from "utils/routeConstants"; import * as CONSTANTS from "assets/constants/browsingPageConstants"; import { EmptyTable, Heading, LoginHint, SearchBox } from "./common-components"; +import { HOME, TOC } from "utils/routeConstants"; import { InnerScrollContainer, OuterScrollContainer, @@ -27,7 +28,6 @@ import { DATASET_UPLOADED } from "assets/constants/overviewConstants"; import DatePickerWidget from "../DatePickerComponent"; import PathBreadCrumb from "../BreadCrumbComponent"; import { RenderPagination } from "../OverviewComponent/common-component"; -import { TOC } from "assets/constants/navigationConstants"; import TablePagination from "../PaginationComponent"; import { useKeycloak } from "@react-keycloak/web"; import { useNavigate } from "react-router"; @@ -52,7 +52,6 @@ const TableWithFavorite = () => { const [page, setPage] = useState(CONSTANTS.START_PAGE_NUMBER); const navigate = useNavigate(); - const dispatch = useDispatch(); useEffect(() => { @@ -209,7 +208,7 @@ const TableWithFavorite = () => { - navigate(`${TOC}/${repo?.resource_id}`) + navigate(`/${HOME}${TOC}/${repo?.resource_id}`) } > {repo?.name} diff --git a/dashboard/src/modules/components/TableOfContent/index.jsx b/dashboard/src/modules/components/TableOfContent/index.jsx index 0d5ee7345c..de969f3bfe 100644 --- a/dashboard/src/modules/components/TableOfContent/index.jsx +++ b/dashboard/src/modules/components/TableOfContent/index.jsx @@ -1,11 +1,15 @@ -import React, { useState, useEffect } from "react"; -import { useParams } from "react-router"; import "./index.less"; + +import { + AngleLeftIcon, + DownloadIcon, + FolderIcon, +} from "@patternfly/react-icons"; import { BadgeToggle, Breadcrumb, - BreadcrumbItem, BreadcrumbHeading, + BreadcrumbItem, Divider, DrilldownMenu, Dropdown, @@ -15,9 +19,8 @@ import { MenuContent, MenuItem, MenuList, - Page, - Spinner, } from "@patternfly/react-core"; +import React, { useEffect, useState } from "react"; import { TableComposable, Tbody, @@ -26,29 +29,29 @@ import { Thead, Tr, } from "@patternfly/react-table"; -import AngleLeftIcon from "@patternfly/react-icons/dist/esm/icons/angle-left-icon"; -import FolderIcon from "@patternfly/react-icons/dist/esm/icons/folder-icon"; -import NavbarDrawer from "../NavbarDrawerComponent"; -import Sidebar from "../SidebarComponent"; -import TablePagination from "../PaginationComponent"; -import { SearchTOC } from "./common-components"; -import { EmptyTable } from "../TableComponent/common-components"; -import { fetchTOC } from "actions/tableOfContentActions"; +import { + fetchTOC, + updateContentData, + updateCurrData, + updateSearchSpace, + updateStack, + updateTableData, +} from "actions/tableOfContentActions"; import { useDispatch, useSelector } from "react-redux"; -import { updateTableData } from "actions/tableOfContentActions"; -import { updateSearchSpace } from "actions/tableOfContentActions"; -import { updateStack } from "actions/tableOfContentActions"; -import { updateCurrData } from "actions/tableOfContentActions"; -import { updateTOCLoader } from "actions/tableOfContentActions"; + import { DEFAULT_PER_PAGE } from "assets/constants/paginationConstants"; +import { EmptyTable } from "../TableComponent/common-components"; +import { SearchTOC } from "./common-components"; +import TablePagination from "../PaginationComponent"; +import { useParams } from "react-router"; const TableOfContent = () => { const { endpoints } = useSelector((state) => state.apiEndpoint); const [menuDrilledIn, setMenuDrilledIn] = useState([]); const [drilldownPath, setDrillDownPath] = useState([]); const [activeMenu, setActiveMenu] = useState("rootMenu"); - const [breadCrumb, setBreadCrumb] = useState(undefined); - const [activeFile, setActiveFile] = useState(undefined); + const [breadCrumb, setBreadCrumb] = useState(null); + const [activeFile, setActiveFile] = useState(null); const [breadCrumbLabels, setBreadCrumbLabels] = useState([]); const [param, setParam] = useState(""); const [page, setPage] = useState(1); @@ -61,11 +64,15 @@ const TableOfContent = () => { if (Object.keys(endpoints).length > 0) dispatch(fetchTOC(params["dataset_id"], "", false)); }, [dispatch, endpoints, params]); - const { stack, searchSpace, tableData, contentData, currData, isLoading } = - useSelector((state) => state.tableOfContent); + const { stack, searchSpace, tableData, contentData, currData } = useSelector( + (state) => state.tableOfContent + ); const setTableData = (data) => { dispatch(updateTableData(data)); }; + const setContnetData = (data) => { + dispatch(updateContentData(data)); + }; const setSearchSpace = (data) => { dispatch(updateSearchSpace(data)); }; @@ -75,9 +82,7 @@ const TableOfContent = () => { const setCurrData = (data) => { dispatch(updateCurrData(data)); }; - const setIsLoading = (data) => { - dispatch(updateTOCLoader(data)); - }; + const onToggle = (isOpen, key, moreBreadCrumbs) => { if (key === "app") { setBreadCrumb(appGroupingBreadcrumb(isOpen, moreBreadCrumbs)); @@ -87,7 +92,7 @@ const TableOfContent = () => { const visibleTableFiles = tableData ? tableData.slice((page - 1) * perPage, page * perPage) : []; - const drillOut = (toMenuId, fromPathId, breadcrumb) => { + const drillOut = (toMenuId, fromPathId, newBreadCrumb) => { const indexOfMenuId = menuDrilledIn.indexOf(toMenuId); const menuDrilledInSansLast = menuDrilledIn.slice(0, indexOfMenuId); const indexOfMenuIdPath = drilldownPath.indexOf(fromPathId); @@ -95,7 +100,7 @@ const TableOfContent = () => { setMenuDrilledIn(menuDrilledInSansLast); setDrillDownPath(pathSansLast); setActiveMenu(toMenuId); - setBreadCrumb(breadCrumb); + setBreadCrumb(newBreadCrumb); }; const drillIn = (fromMenuId, toMenuId, pathId) => { setMenuDrilledIn([...menuDrilledIn, fromMenuId]); @@ -176,11 +181,11 @@ const TableOfContent = () => { ); }; const getMyBreadCrumbClick = () => { - drillOut("rootMenu", "group:start_rollout", null); + drillOut("rootMenu", "group:start_rollout", initialBreadcrumb([])); setStack(1); setTableData(stack[0].files); + setContnetData(stack[0]); setSearchSpace(stack[0].files); - setBreadCrumb(initialBreadcrumb([])); setParam(""); setBreadCrumbLabels([]); }; @@ -188,17 +193,16 @@ const TableOfContent = () => { dispatch(fetchTOC(params["dataset_id"], data, true)); }; const attachBreadCrumbs = (data, firstHierarchyLevel) => { - breadCrumbLabels.push(data); - setBreadCrumbLabels(breadCrumbLabels); + setBreadCrumbLabels([...breadCrumbLabels, data.name]); + setBreadCrumb( firstHierarchyLevel ? initialBreadcrumb(breadCrumbLabels) : appGroupingBreadcrumb(false, breadCrumbLabels) ); - const dirPath = param.concat(firstHierarchyLevel ? "" : "/", data); + const dirPath = param.concat(firstHierarchyLevel ? "" : "/", data.name); setParam(dirPath); - setIsLoading(true); - getSubFolderData(dirPath); + getSubFolderData(data.uri); }; const updateHighlightedRow = (index) => { const newPage = Math.floor(index / perPage); @@ -207,171 +211,173 @@ const TableOfContent = () => { } setActiveFile(index); }; + return ( <> - } sidebar={}> -
-
+
+ + {breadCrumb && ( + <> + {breadCrumb} + + + )} - - {breadCrumb && ( - <> - {breadCrumb} - - - )} - {isLoading ? ( - - ) : ( - - - {contentData?.directories?.map((data, index) => { - return ( - { - attachBreadCrumbs(data.name, true); - }} - drilldownMenu={ - - {currData?.directories?.map((data, index) => { - if (dirCount < currData.directories.length) { - dirCount = dirCount + 1; - return ( - { - attachBreadCrumbs(data.name, false); - }} - > - - {data.name} - - ); - } else { - return <>; - } - })} + + + {contentData?.directories?.map((data, index) => { + return ( + } + direction="down" + onClick={() => { + attachBreadCrumbs(data, true); + }} + drilldownMenu={ + + {currData?.directories?.map((data, index) => { + if (dirCount < currData.directories.length) { + dirCount = dirCount + 1; + return ( + } + onClick={() => { + attachBreadCrumbs(data, false); + }} + > + {data.name} + + ); + } else { + return <>; + } + })} - {currData?.files?.map((data, index) => { - if (fileCount < currData.files.length) { - fileCount = fileCount + 1; - return ( - { - updateHighlightedRow(index); - }} - > - {data.name} - - ); - } else { - return <>; - } - })} - - } - > - - {data.name} - - ); - })} - {contentData?.files?.map((data, index) => { - return ( - { - updateHighlightedRow(index); - }} - > - {data.name} - - ); - })} - - - )} - -
-
- -
- - {isLoading ? ( - - ) : ( - <> - - - name - mtime - size - mode - type - - - - {visibleTableFiles.length > 0 ? ( - visibleTableFiles?.map((file, index) => ( - { + if (fileCount < currData.files.length) { + fileCount = fileCount + 1; + return ( + } + onClick={() => { + updateHighlightedRow(index); + }} + > + {data.name} + + ); + } else { + return <>; } - > - {file.name} - {file.mtime} - {file.size} - {file.mode} - {file.type} - - )) - ) : ( - - - - - - )} - - - )} - - + })} + + } + > + {data.name} + + ); + })} + {contentData?.files?.map((data, index) => { + return ( + { + updateHighlightedRow(index); + }} + > + {data.name} + + ); + })} + + +
+
+
+
+ + <> + + + Name + mtime + Size + Mode + Type + + + + + {visibleTableFiles.length > 0 ? ( + visibleTableFiles?.map((file, index) => ( + + {file.name} + {file.mtime} + {file.size} + {file.mode} + {file.type} + + + + + + + )) + ) : ( + + + + + + )} + + + +
- +
); }; diff --git a/dashboard/src/modules/components/TableOfContent/index.less b/dashboard/src/modules/components/TableOfContent/index.less index e47988ab02..b306b8111a 100644 --- a/dashboard/src/modules/components/TableOfContent/index.less +++ b/dashboard/src/modules/components/TableOfContent/index.less @@ -2,16 +2,16 @@ width: 500px; height: 100%; box-shadow: none; - border-right: 2px solid black; - border-bottom: 2px solid black; + border-right: 2px solid #d2d2d2; } .toc { display: flex; + height: 100%; } .active { - background-color: #b3cde0; + background-color: #efefef; } .dropDown { @@ -23,13 +23,16 @@ .tableTOC { display: flex; flex-direction: column; - width: 60%; - margin-left: 2vw; + width: 100%; + padding: 2vh; + .download-icon { + color: #6a6e73; + } } .searchTOCContainer { display: flex; - flex-flow: row-reverse; + justify-content: flex-end; } .tocBody { @@ -40,11 +43,8 @@ width: 25vw !important; } -.spinner { - position: absolute; - top: 25%; - left: 50%; - height: 100%; - width: 100%; - color: aqua; +#d_down_parent { + svg { + fill: #6a6e73; + } } diff --git a/dashboard/src/reducers/tableOfContentReducer.js b/dashboard/src/reducers/tableOfContentReducer.js index 0346568470..2769c7e526 100644 --- a/dashboard/src/reducers/tableOfContentReducer.js +++ b/dashboard/src/reducers/tableOfContentReducer.js @@ -1,11 +1,11 @@ import { GET_SUB_DIR_DATA, GET_TOC_DATA, + UPDATE_CONTENT_DATA, UPDATE_CURR_DATA, UPDATE_SEARCH_SPACE, UPDATE_STACK, UPDATE_TABLE_DATA, - UPDATE_TOC_LOADING, } from "actions/types"; const initialState = { @@ -14,7 +14,6 @@ const initialState = { tableData: [], contentData: [], currData: [], - isLoading: true, }; const TableOfContentReducer = (state = initialState, action = {}) => { @@ -27,7 +26,6 @@ const TableOfContentReducer = (state = initialState, action = {}) => { searchSpace: payload.files, tableData: payload.files, contentData: payload, - isLoading: false, }; case GET_SUB_DIR_DATA: @@ -37,7 +35,6 @@ const TableOfContentReducer = (state = initialState, action = {}) => { searchSpace: payload.files, tableData: payload.files, contentData: payload, - isLoading: false, }; case UPDATE_TABLE_DATA: @@ -45,7 +42,11 @@ const TableOfContentReducer = (state = initialState, action = {}) => { ...state, tableData: payload, }; - + case UPDATE_CONTENT_DATA: + return { + ...state, + contentData: payload, + }; case UPDATE_SEARCH_SPACE: return { ...state, @@ -63,12 +64,6 @@ const TableOfContentReducer = (state = initialState, action = {}) => { ...state, currData: payload, }; - - case UPDATE_TOC_LOADING: - return { - ...state, - isLoading: payload, - }; default: return state; } diff --git a/dashboard/src/utils/routeConstants.js b/dashboard/src/utils/routeConstants.js index 4c5b080de1..241b239408 100644 --- a/dashboard/src/utils/routeConstants.js +++ b/dashboard/src/utils/routeConstants.js @@ -4,6 +4,7 @@ export const AUTH = "auth"; export const AUTH_LOGIN = "login"; export const AUTH_SIGNUP = "signup"; export const OVERVIEW = "overview"; +export const TOC = "toc"; export const TABLE_OF_CONTENT = "toc/:dataset_id"; export const USER_PROFILE = "user-profile"; export const ANALYSIS = "analysis";