diff --git a/dashboard/src/actions/tableOfContentActions.js b/dashboard/src/actions/tableOfContentActions.js deleted file mode 100644 index d844e1a5f2..0000000000 --- a/dashboard/src/actions/tableOfContentActions.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as TYPES from "./types"; - -import API from "../utils/axiosInstance"; -import { DANGER } from "assets/constants/toastConstants"; -import { showToast } from "./toastActions"; -import { uriTemplate } from "../utils/helper"; - -export const fetchTOC = - (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, - }); - const response = await API.get(uri); - if (response.status === 200 && response.data) { - dispatch({ - type: callForSubData ? "GET_SUB_DIR_DATA" : "GET_TOC_DATA", - payload: response.data, - }); - } - } catch (error) { - const msg = error.response?.data?.message; - dispatch(showToast(DANGER, msg ?? `Error response: ${error}`)); - } - dispatch({ type: TYPES.COMPLETED }); - }; - -export const updateTableData = (data) => ({ - type: TYPES.UPDATE_TABLE_DATA, - payload: data, -}); - -export const updateContentData = (data) => ({ - type: TYPES.UPDATE_CONTENT_DATA, - payload: data, -}); - -export const updateSearchSpace = (data) => ({ - type: TYPES.UPDATE_SEARCH_SPACE, - payload: data, -}); - -export const updateStack = (length) => ({ - type: TYPES.UPDATE_STACK, - payload: length, -}); - -export const updateCurrData = (data) => ({ - type: TYPES.UPDATE_CURR_DATA, - payload: data, -}); diff --git a/dashboard/src/actions/tocActions.js b/dashboard/src/actions/tocActions.js new file mode 100644 index 0000000000..546a540876 --- /dev/null +++ b/dashboard/src/actions/tocActions.js @@ -0,0 +1,133 @@ +import * as TYPES from "./types"; + +import API from "utils/axiosInstance"; +import { DANGER } from "assets/constants/toastConstants"; +import { showToast } from "./toastActions"; +import { uriTemplate } from "utils/helper"; + +/** + * Function to fetch contents data + * @function + * @param {String} datasetId - Dataset ID + * @param {String} path - Path to the file/directory + * @param {String} item - Active item + * @param {Boolean} isSubDir - To identify sub-directory expansion + * @return {Function} - dispatch the action and update the state + */ +export const fetchTOC = + (datasetId, path, item, isSubDir) => async (dispatch, getState) => { + try { + dispatch({ type: TYPES.LOADING }); + const endpoints = getState().apiEndpoint.endpoints; + + const uri = uriTemplate(endpoints, "datasets_contents", { + dataset: datasetId, + target: path, + }); + const response = await API.get(uri); + if (response.status === 200 && response.data) { + if (!isSubDir) { + const inventoryLink = uriTemplate(endpoints, "datasets_inventory", { + dataset: datasetId, + target: path, + }); + dispatch({ + type: TYPES.SET_INVENTORY_LINK, + payload: inventoryLink, + }); + } + dispatch(parseToTreeView(response.data, item, isSubDir, path)); + } + } catch (error) { + const msg = error.response?.data?.message; + dispatch(showToast(DANGER, msg ?? `Error response: ${error}`)); + } + dispatch({ type: TYPES.COMPLETED }); + }; + +const makeOptions = (data, isParent, keyPath, isDirectory) => { + const options = data.map((item) => { + const option = { + name: item.name, + id: isParent ? `${keyPath}*${item.name}` : item.name, + isDirectory, + uri: item.uri, + }; + if (isDirectory) { + option.children = []; + } else { + option.size = item.size; + } + return option; + }); + return options; +}; +/** + * Function to parse contents data totree view + * @function + * @param {Object} contentData - Contentdata to parse + * @param {Object} activeItem - Active item + * @param {Boolean} isSubDir - To identify sub-directory expansion + * @param {String} parent - Parent Name to set the id + * @return {Function} - dispatch the action and update the state + */ +export const parseToTreeView = + (contentData, activeItem, isSubDir, parent) => (dispatch, getState) => { + const keyPath = parent.replaceAll("/", "*"); + const drillMenuData = [...getState().toc.drillMenuData]; + const directories = makeOptions( + contentData.directories, + parent, + keyPath, + true + ); + const files = makeOptions(contentData.files, parent, keyPath, false); + const treeOptions = [...directories, ...files]; + if (isSubDir) { + if (activeItem.includes("*")) { + updateActiveItemChildren(drillMenuData, keyPath, treeOptions); + } else { + const itemName = activeItem.split("*").pop(); + const itemOptions = drillMenuData.find((i) => i.name === itemName); + if (itemOptions) { + itemOptions["children"] = treeOptions; + } + } + } + dispatch({ + type: TYPES.SET_DRILL_MENU_DATA, + payload: isSubDir ? drillMenuData : treeOptions, + }); + }; + +/** + * Function to find the actual key from key path and update it's children + * @function + * @param {Object} arr - Drill down menu + * @param {String} key - key path + * @param {Array} childrenToUpdate - Active item children obtained through API request + * @return {Array} - updated children + */ +const updateActiveItemChildren = (arr, key, childrenToUpdate) => { + // if children are undefined + if (!arr) return; + + // loop over each entry and its children to find + // entry with passed key + arr.forEach((entry) => { + if (entry.id === key) { + entry.children = childrenToUpdate; + } + // recursive call to traverse children + else { + updateActiveItemChildren(entry.children, key, childrenToUpdate); + } + }); + + return arr; +}; + +export const setActiveFileContent = (item) => ({ + type: TYPES.SET_ACTIVE_FILE, + payload: item, +}); diff --git a/dashboard/src/actions/types.js b/dashboard/src/actions/types.js index 751bb07cdd..727e4b4ed5 100644 --- a/dashboard/src/actions/types.js +++ b/dashboard/src/actions/types.js @@ -49,13 +49,9 @@ export const SET_TREE_DATA = "SET_TREE_DATA"; export const SET_METADATA_CHECKED_KEYS = "SET_METADATA_CHECKED_KEYS"; /* TABLE OF CONTENT */ -export const GET_TOC_DATA = "GET_TOC_DATA"; -export const GET_SUB_DIR_DATA = "GET_SUB_DIR_DATA"; -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_CONTENT_DATA = "UPDATE_CONTENT_DATA"; +export const SET_INVENTORY_LINK = "SET_INVENTORY_LINK"; +export const SET_DRILL_MENU_DATA = "SET_DRILL_MENU_DATA"; +export const SET_ACTIVE_FILE = "SET_ACTIVE_FILE"; /* SIDEBAR */ export const SET_ACTIVE_MENU_ITEM = "SET_ACTIVE_MENU_ITEM"; diff --git a/dashboard/src/modules/components/TableComponent/index.jsx b/dashboard/src/modules/components/TableComponent/index.jsx index 9a4bb70a19..e3921a84ff 100644 --- a/dashboard/src/modules/components/TableComponent/index.jsx +++ b/dashboard/src/modules/components/TableComponent/index.jsx @@ -29,6 +29,7 @@ import DatePickerWidget from "../DatePickerComponent"; import { RenderPagination } from "../OverviewComponent/common-component"; import TablePagination from "../PaginationComponent"; import { ViewOptions } from "../ComparisonComponent/common-components"; +import { uid } from "utils/helper"; import { useKeycloak } from "@react-keycloak/web"; import { useNavigate } from "react-router"; @@ -204,31 +205,37 @@ const TableWithFavorite = () => {
{selectedArray.length > 0 ? ( - selectedArray.map((repo, rowIndex) => ( -