From 446a9d6788f3b82ac3a46574ec5406747ccf7287 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Tue, 27 Feb 2024 11:56:26 -0500 Subject: [PATCH 1/3] Fixing feed operations --- src/components/Feeds/FeedListView.tsx | 2 +- src/components/IconContainer/index.tsx | 276 +++++++++++++------------ 2 files changed, 143 insertions(+), 135 deletions(-) diff --git a/src/components/Feeds/FeedListView.tsx b/src/components/Feeds/FeedListView.tsx index 7a07b5a7f..8ba628f06 100644 --- a/src/components/Feeds/FeedListView.tsx +++ b/src/components/Feeds/FeedListView.tsx @@ -237,7 +237,7 @@ const TableSelectable: React.FunctionComponent = () => { search={search} /> - {feedsToDisplay && } + {feedsToDisplay && } {isLoading || isFetching || diff --git a/src/components/IconContainer/index.tsx b/src/components/IconContainer/index.tsx index 7c22f480c..6fc276d7b 100644 --- a/src/components/IconContainer/index.tsx +++ b/src/components/IconContainer/index.tsx @@ -1,31 +1,30 @@ -import React, { ReactElement } from "react"; +import { Feed } from "@fnndsc/chrisapi"; import { - ToggleGroup, - ToggleGroupItem, - Tooltip, - Modal, - ModalVariant, + Button, + Checkbox, Form, FormGroup, + Modal, + ModalVariant, TextInput, - Button, - Checkbox, + ToggleGroup, + ToggleGroupItem, + Tooltip, } from "@patternfly/react-core"; -import { Alert } from "antd"; -import { cujs } from "chris-utility"; +import MdCallSplit from "@patternfly/react-icons/dist/esm/icons/code-branch-icon"; import FaDownload from "@patternfly/react-icons/dist/esm/icons/download-icon"; -import FaTrash from "@patternfly/react-icons/dist/esm/icons/trash-icon"; - -import { ShareButtonIcon } from "../../icons"; import MdIosShare from "@patternfly/react-icons/dist/esm/icons/share-icon"; -import MdCallSplit from "@patternfly/react-icons/dist/esm/icons/code-branch-icon"; +import FaTrash from "@patternfly/react-icons/dist/esm/icons/trash-icon"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { Alert } from "antd"; +import { cujs } from "chris-utility"; +import React, { ReactElement } from "react"; import { useDispatch } from "react-redux"; +import ChrisAPIClient from "../../api/chrisapiclient"; +import { ShareButtonIcon } from "../../icons"; import { setBulkSelect } from "../../store/feed/actions"; import { useTypedSelector } from "../../store/hooks"; -import { Feed } from "@fnndsc/chrisapi"; - -import ChrisAPIClient from "../../api/chrisapiclient"; -import { useQueryClient } from "@tanstack/react-query"; +import { catchError } from "../../api/common"; function capitalizeFirstLetter(stringLetter: string) { return stringLetter.charAt(0).toUpperCase() + stringLetter.slice(1); @@ -36,7 +35,7 @@ interface ModalState { feedName: string; currentAction: string; modalDescription: string; - errorHandling: Record; + errorHandling: string; sharePublically: boolean; } @@ -46,12 +45,12 @@ const getInitialState = () => { feedName: "", currentAction: "", modalDescription: "", - errorHandling: {}, + errorHandling: "", sharePublically: false, }; }; -const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { +const IconContainer = () => { const queryClient = useQueryClient(); const { bulkSelect } = useTypedSelector((state) => { return state.feed; @@ -60,7 +59,8 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { const [modalState, setModalState] = React.useState(getInitialState); - const { currentAction, isOpen, errorHandling, feedName } = modalState; + const { currentAction, isOpen, errorHandling, sharePublically, feedName } = + modalState; const getDefaultName = (bulkSelect: Feed[], action: string) => { if (bulkSelect.length > 0) { @@ -70,9 +70,9 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { : "Enter a name for your new feed (optional)"; let prefix = ""; - if (action == "merge") { + if (action === "merge") { prefix = "Merge of "; - } else if (action == "download") { + } else if (action === "download") { prefix = "archive-"; } else { prefix = ""; @@ -85,11 +85,11 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { newFeedName = feedNames.toString().replace(/[, ]+/g, "_"); newFeedName = prefix + newFeedName; newFeedName = newFeedName.substring(0, 100); - if (action == "duplicate") { + if (action === "duplicate") { if (bulkSelect.length > 1) { newFeedName = "duplicate-"; } else { - newFeedName = "duplicate-" + bulkSelect[0].data.name; + newFeedName = `duplicate-${bulkSelect[0].data.name}`; } } } @@ -113,9 +113,7 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { } else { setModalState({ ...modalState, - errorHandling: { - value: ["Please select a feed for this operation"], - }, + errorHandling: "Please select a feed for this operation", isOpen: value, }); } @@ -131,153 +129,165 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { }); }; - const handleDelete = async (bulkSelect: Feed[]) => { - if (bulkSelect && allFeeds) { + const deleteFeedMutation = useMutation({ + mutationFn: async (bulkSelect: Feed[]) => { for (const feed of bulkSelect) { try { await feed.delete(); - } catch (error: any) { - const errorMessage = error.response - ? error.response.data - : error.message; - handleError(errorMessage); + } catch (e: any) { + throw new Error(e.message); } } - + }, + onSuccess: () => { dispatch(setBulkSelect([], false)); queryClient.invalidateQueries({ queryKey: ["feeds"], }); handleModalToggle(false); - } - }; + }, + onError: (error: { message: string }) => { + handleError(error.message); + }, + }); - const handleShare = async (bulkSelect: Feed[]) => { - try { - if (modalState.sharePublically) { - bulkSelect.map(async (feed) => { + const shareFeedMutation = useMutation({ + mutationFn: async (data: { + bulkSelect: Feed[]; + sharePublically: boolean; + feedName: string; + }) => { + const { bulkSelect, sharePublically, feedName } = data; + for (const feed of bulkSelect) { + try { await feed.put({ //@ts-ignore - public: true, - }); - }); - } else { - bulkSelect.map(async (feed) => { - await feed.put({ - owner: feedName, + public: sharePublically, + owner: sharePublically ? undefined : feedName, }); - }); + } catch (error: any) { + throw new Error(error.message); + } } + }, + onSuccess: () => { + dispatch(setBulkSelect([], false)); + handleModalToggle(false); + }, + onError: (error: { message: string }) => { + handleError(error.message); + }, + }); - setModalState(getInitialState()); - } catch (error: any) { - handleError(error.response.data || error.message); - } - }; - - const handleError = (errorMessage: any) => { - setModalState({ - ...modalState, - errorHandling: errorMessage, - }); - }; - - const handleDownloadFeed = async ( - feedList: Feed[], - feedName: string, - operation: string, - ) => { + const handleDownloadMutation = async (data: { + feedList: Feed[]; + feedName: string; + operation: string; + }) => { + const { feedList, feedName, operation } = data; const client = ChrisAPIClient.getClient(); cujs.setClient(client); const feedIdList = []; const feedNames = []; + for (let i = 0; i < feedList.length; i++) { const data = feedList[i].data; feedIdList.push(data.id); feedNames.push(data.name); } - try { - // truncate name of the merged feed(limit=100) - let newFeedName = feedNames.toString().replace(/[, ]+/g, "_"); - let createdFeed; + // Truncate the name of the merged feed (limit=100) + let newFeedName = feedNames.toString().replace(/[, ]+/g, "_"); + try { if (operation === "download") { newFeedName = `archive-${newFeedName}`; newFeedName = newFeedName.substring(0, 100); - - newFeedName = feedName == "" ? newFeedName : feedName; - createdFeed = await cujs.downloadMultipleFeeds(feedIdList, newFeedName); + newFeedName = feedName === "" ? newFeedName : feedName; + console.log("newFeedName", newFeedName, feedIdList, data.operation); + // Call the downloadMultipleFeeds function + await cujs.downloadMultipleFeeds(feedIdList, newFeedName); } if (operation === "merge") { newFeedName = `merge-${newFeedName}`; newFeedName = newFeedName.substring(0, 100); - newFeedName = feedName == "" ? newFeedName : feedName; - createdFeed = await cujs.mergeMultipleFeeds(feedIdList, newFeedName); - } + newFeedName = feedName === "" ? newFeedName : feedName; - if (createdFeed) { - queryClient.invalidateQueries({ - queryKey: ["feeds"], - }); - setModalState({ - ...modalState, - isOpen: false, - }); + // Call the mergeMultipleFeeds function + await cujs.mergeMultipleFeeds(feedIdList, newFeedName); } - } catch (error: any) { - const errorMessage = error.response ? error.response.data : error.message; - handleError(errorMessage); + + // Handle success actions if needed + queryClient.invalidateQueries({ + queryKey: ["feeds"], + }); + + // Close the modal + handleModalToggle(false); + } catch (error) { + // Handle errors here + console.error("Error", error); + //handleError(error.message); } }; - const handleDuplicateFeed = async (feedList: Feed[], feedName: string) => { - const client = ChrisAPIClient.getClient(); - cujs.setClient(client); - - for (let i = 0; i < feedList.length; i++) { - const feedIdList = []; - const data = feedList[i].data; - const newFeedName = feedName - ? `${feedName}-${data.name}` - : `duplicate-${data.name}`; - feedIdList.push(data.id); - try { - const createdFeed: Feed = await cujs.mergeMultipleFeeds( - feedIdList, - newFeedName, - ); - if (createdFeed) { - queryClient.invalidateQueries({ - queryKey: ["feeds"], - }); - setModalState({ - ...modalState, - isOpen: false, - }); + const handleDuplicateFeedMutation = useMutation({ + mutationFn: async (data: { feedList: Feed[]; feedName: string }) => { + const { feedList, feedName } = data; + const client = ChrisAPIClient.getClient(); + cujs.setClient(client); + for (let i = 0; i < feedList.length; i++) { + const feedIdList = []; + const data = feedList[i].data; + const newFeedName = feedName + ? `${feedName}-${data.name}` + : `duplicate-${data.name}`; + feedIdList.push(data.id); + try { + await cujs.mergeMultipleFeeds(feedIdList, newFeedName); + } catch (error: any) { + const errorMessage = error.message; + throw new Error(errorMessage); } - } catch (error: any) { - const errorMessage = error.response - ? error.response.data - : error.message; - handleError(errorMessage); } - } + }, + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: ["feeds"], + }); + handleModalToggle(false); + }, + onError: (error: { message: string }) => { + handleError(error.message); + }, + }); + + const handleError = (errorMessage: string) => { + setModalState({ + ...modalState, + errorHandling: errorMessage, + }); }; const handleSubmit = () => { - currentAction === "share" && handleShare(bulkSelect); + currentAction === "share" && + shareFeedMutation.mutate({ bulkSelect, sharePublically, feedName }); + currentAction === "delete" && deleteFeedMutation.mutate(bulkSelect); currentAction === "download" && - handleDownloadFeed(bulkSelect, feedName, "download"); + handleDownloadMutation({ + feedList: bulkSelect, + feedName, + operation: "download", + }); currentAction === "merge" && - handleDownloadFeed(bulkSelect, feedName, "merge"); - currentAction === "delete" && handleDelete(bulkSelect); - currentAction === "duplicate" && handleDuplicateFeed(bulkSelect, feedName); - }; - - const alert = (_error: any) => { - return ; + handleDownloadMutation({ + feedList: bulkSelect, + feedName, + operation: "merge", + }); + currentAction === "duplicate" && + handleDuplicateFeedMutation.mutate({ feedList: bulkSelect, feedName }); }; return ( @@ -371,11 +381,9 @@ const IconContainer = ({ allFeeds }: { allFeeds: Feed[] }) => { )}
- {Object.keys(errorHandling).length > 0 && - //@ts-ignore - errorHandling.value.map((error) => { - return alert(error); - })} + {errorHandling && ( + + )}
From baea6ca53ae11610a5cbc0758328c8651ca05eac Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Tue, 27 Feb 2024 12:15:56 -0500 Subject: [PATCH 2/3] Archive-Feed-Fix --- src/components/IconContainer/index.tsx | 88 ++++++++++++++------------ 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/components/IconContainer/index.tsx b/src/components/IconContainer/index.tsx index 6fc276d7b..843610fac 100644 --- a/src/components/IconContainer/index.tsx +++ b/src/components/IconContainer/index.tsx @@ -24,7 +24,6 @@ import ChrisAPIClient from "../../api/chrisapiclient"; import { ShareButtonIcon } from "../../icons"; import { setBulkSelect } from "../../store/feed/actions"; import { useTypedSelector } from "../../store/hooks"; -import { catchError } from "../../api/common"; function capitalizeFirstLetter(stringLetter: string) { return stringLetter.charAt(0).toUpperCase() + stringLetter.slice(1); @@ -166,7 +165,7 @@ const IconContainer = () => { owner: sharePublically ? undefined : feedName, }); } catch (error: any) { - throw new Error(error.message); + throw new Error(error); } } }, @@ -174,39 +173,47 @@ const IconContainer = () => { dispatch(setBulkSelect([], false)); handleModalToggle(false); }, - onError: (error: { message: string }) => { + onError: (error) => { handleError(error.message); }, }); - const handleDownloadMutation = async (data: { - feedList: Feed[]; - feedName: string; - operation: string; - }) => { - const { feedList, feedName, operation } = data; - const client = ChrisAPIClient.getClient(); - cujs.setClient(client); - const feedIdList = []; - const feedNames = []; + const handleDownloadMutation = useMutation({ + mutationFn: async (data: { + feedList: Feed[]; + feedName: string; + operation: string; + }) => { + const { feedList, feedName, operation } = data; - for (let i = 0; i < feedList.length; i++) { - const data = feedList[i].data; - feedIdList.push(data.id); - feedNames.push(data.name); - } + const client = ChrisAPIClient.getClient(); + cujs.setClient(client); + const feedIdList = []; + const feedNames = []; + for (let i = 0; i < feedList.length; i++) { + const data = feedList[i].data; + feedIdList.push(data.id); + feedNames.push(data.name); + } - // Truncate the name of the merged feed (limit=100) - let newFeedName = feedNames.toString().replace(/[, ]+/g, "_"); + // Truncate the name of the merged feed (limit=100) + let newFeedName = feedNames.toString().replace(/[, ]+/g, "_"); + let createdFeed: Feed | null = null; - try { if (operation === "download") { newFeedName = `archive-${newFeedName}`; newFeedName = newFeedName.substring(0, 100); newFeedName = feedName === "" ? newFeedName : feedName; - console.log("newFeedName", newFeedName, feedIdList, data.operation); - // Call the downloadMultipleFeeds function - await cujs.downloadMultipleFeeds(feedIdList, newFeedName); + + try { + createdFeed = await cujs.downloadMultipleFeeds( + feedIdList, + newFeedName, + ); + } catch (e: any) { + throw new Error(e); + // Not throwing the error here to allow handling in the onError callback + } } if (operation === "merge") { @@ -214,24 +221,26 @@ const IconContainer = () => { newFeedName = newFeedName.substring(0, 100); newFeedName = feedName === "" ? newFeedName : feedName; - // Call the mergeMultipleFeeds function - await cujs.mergeMultipleFeeds(feedIdList, newFeedName); + try { + createdFeed = await cujs.mergeMultipleFeeds(feedIdList, newFeedName); + } catch (e: any) { + throw new Error(e); + } } + return createdFeed; // Return null if operation is neither "download" nor "merge" + }, + onSuccess: () => { // Handle success actions if needed queryClient.invalidateQueries({ queryKey: ["feeds"], }); - - // Close the modal handleModalToggle(false); - } catch (error) { - // Handle errors here - console.error("Error", error); - //handleError(error.message); - } - }; - + }, + onError: (error: Error) => { + handleError(error.message); + }, + }); const handleDuplicateFeedMutation = useMutation({ mutationFn: async (data: { feedList: Feed[]; feedName: string }) => { const { feedList, feedName } = data; @@ -247,8 +256,7 @@ const IconContainer = () => { try { await cujs.mergeMultipleFeeds(feedIdList, newFeedName); } catch (error: any) { - const errorMessage = error.message; - throw new Error(errorMessage); + throw new Error(error); } } }, @@ -258,7 +266,7 @@ const IconContainer = () => { }); handleModalToggle(false); }, - onError: (error: { message: string }) => { + onError: (error) => { handleError(error.message); }, }); @@ -275,13 +283,13 @@ const IconContainer = () => { shareFeedMutation.mutate({ bulkSelect, sharePublically, feedName }); currentAction === "delete" && deleteFeedMutation.mutate(bulkSelect); currentAction === "download" && - handleDownloadMutation({ + handleDownloadMutation.mutate({ feedList: bulkSelect, feedName, operation: "download", }); currentAction === "merge" && - handleDownloadMutation({ + handleDownloadMutation.mutate({ feedList: bulkSelect, feedName, operation: "merge", From d94b1205fd8d523ebbf08ecd32aff1611ad14ad1 Mon Sep 17 00:00:00 2001 From: PintoGideon Date: Tue, 27 Feb 2024 12:21:09 -0500 Subject: [PATCH 3/3] Code Cleanup --- src/components/CreateFeed/createFeedHelper.ts | 97 ++++++++----------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/src/components/CreateFeed/createFeedHelper.ts b/src/components/CreateFeed/createFeedHelper.ts index 2633db222..f8f7201b0 100644 --- a/src/components/CreateFeed/createFeedHelper.ts +++ b/src/components/CreateFeed/createFeedHelper.ts @@ -76,12 +76,10 @@ export const createFeedInstanceWithDircopy = async ( state: PipelineState, ) => { const { chrisFiles, localFiles } = data; - - let dirpath: string[] = []; - let feed: Feed; + const dirpath: string[] = []; if (selectedConfig.includes("swift_storage")) { - dirpath = chrisFiles.map((path: string) => path); + dirpath.push(...chrisFiles); } if (selectedConfig.includes("local_select")) { @@ -92,8 +90,8 @@ export const createFeedInstanceWithDircopy = async ( try { await uploadLocalFiles(localFiles, path, setUploadFileCallback); } catch (error) { - const errObj = catchError(error); - errorCallback(errObj); + errorCallback(catchError(error)); + return null; } } @@ -101,61 +99,48 @@ export const createFeedInstanceWithDircopy = async ( const client = ChrisAPIClient.getClient(); const dircopy = await getPlugin("pl-dircopy"); - if (dircopy instanceof Plugin) { - try { - const createdInstance = await client.createPluginInstance( - dircopy.data.id, - { - //@ts-ignore - dir: dirpath.join(","), - }, - ); - const { pipelineToAdd, computeInfo, titleInfo, selectedPipeline } = - state; - - const id = pipelineToAdd?.data.id; - const resources = selectedPipeline?.[id]; - if (createdInstance) { - if (resources) { - const { parameters } = resources; - - const nodes_info = client.computeWorkflowNodesInfo(parameters.data); - - for (const node of nodes_info) { - // Set compute info - const activeNode = computeInfo?.[id][node.piping_id]; - // Set Title - const titleSet = titleInfo?.[id][node.piping_id]; - - if (activeNode) { - const compute_node = activeNode.currentlySelected; - node.compute_resource_name = compute_node; - } - - if (titleSet) { - node.title = titleSet; - } - } - - await client.createWorkflow(id, { - previous_plugin_inst_id: createdInstance.data.id, - nodes_info: JSON.stringify(nodes_info), - }); - } + if (!(dircopy instanceof Plugin)) { + return null; + } + + const createdInstance = await client.createPluginInstance(dircopy.data.id, { + //@ts-ignore + dir: dirpath.join(","), + }); + + const { pipelineToAdd, computeInfo, titleInfo, selectedPipeline } = state; + const id = pipelineToAdd?.data.id; + const resources = selectedPipeline?.[id]; + + if (createdInstance && resources) { + const { parameters } = resources; + const nodes_info = client.computeWorkflowNodesInfo(parameters.data); - feed = (await createdInstance.getFeed()) as Feed; - return feed; + for (const node of nodes_info) { + const activeNode = computeInfo?.[id][node.piping_id]; + const titleSet = titleInfo?.[id][node.piping_id]; + + if (activeNode) { + node.compute_resource_name = activeNode.currentlySelected; + } + + if (titleSet) { + node.title = titleSet; } - } catch (error) { - console.log("Error", error); } - return null; - //when the `post` finishes, the dircopyInstances's internal collection is updated + await client.createWorkflow(id, { + previous_plugin_inst_id: createdInstance.data.id, + nodes_info: JSON.stringify(nodes_info), + }); + + return (await createdInstance.getFeed()) as Feed; } + + return null; } catch (error) { - const errorObj = catchError(error); - errorCallback(errorObj); + errorCallback(catchError(error)); + return null; } }; @@ -165,7 +150,7 @@ export const createFeedInstanceWithFS = async ( selectedPlugin: Plugin | undefined, errorCallback: (error: any) => void, ) => { - let feed; + let feed: Feed | null = null; if (selectedPlugin) { if (selectedPlugin instanceof Plugin) { const data = await getRequiredObject(