Skip to content

Commit 7722ff3

Browse files
DaanRosendaltiborsimko
authored andcommitted
feat(ui): add workflow sharing modal (#375)
Closes #651
1 parent ea20030 commit 7722ff3

12 files changed

+1143
-208
lines changed

reana-ui/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"react-redux": "^8.1.3",
2020
"react-router-dom": "^6.17.0",
2121
"react-scripts": "^5.0.0",
22+
"react-semantic-ui-datepickers": "^2.17.2",
2223
"redux": "^4.0.4",
2324
"redux-devtools-extension": "^2.13.8",
2425
"redux-thunk": "^2.3.0",

reana-ui/src/actions.js

+108
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,23 @@ export const WORKFLOW_STOP_INIT = "Initialize workflow stopping";
8686
export const WORKFLOW_STOPPED = "Workflow stopped";
8787
export const OPEN_STOP_WORKFLOW_MODAL = "Open stop workflow modal";
8888
export const CLOSE_STOP_WORKFLOW_MODAL = "Close stop workflow modal";
89+
export const OPEN_SHARE_WORKFLOW_MODAL = "Open share workflow modal";
90+
export const CLOSE_SHARE_WORKFLOW_MODAL = "Close share workflow modal";
8991
export const WORKFLOW_LIST_REFRESH = "Refresh workflow list";
9092
export const OPEN_INTERACTIVE_SESSION_MODAL = "Open interactive session modal";
9193
export const CLOSE_INTERACTIVE_SESSION_MODAL =
9294
"Close interactive session modal";
95+
export const WORKFLOW_SHARE_STATUS_FETCH = "Fetch workflow share status";
96+
export const WORKFLOW_SHARE_STATUS_RECEIVED = "Workflow share status received";
97+
export const WORKFLOW_SHARE_STATUS_FETCH_ERROR =
98+
"Fetch workflow share status error";
99+
export const WORKFLOW_SHARE_INIT = "Initialise workflow sharing";
100+
export const WORKFLOW_SHARED_SUCCESSFULLY = "Workflow shared successfully";
101+
export const WORKFLOW_SHARED_ERROR = "Workflow shared error";
102+
export const WORKFLOW_SHARE_FINISH = "Finish workflow sharing";
103+
export const WORKFLOW_UNSHARE_INIT = "Initialise workflow unsharing";
104+
export const WORKFLOW_UNSHARED = "Workflow unshared";
105+
export const WORKFLOW_UNSHARE_ERROR = "Workflow unshare error";
93106

94107
export const USERS_SHARED_WITH_YOU_FETCH =
95108
"Fetch users who shared workflows with you";
@@ -540,6 +553,14 @@ export function closeInteractiveSession(id) {
540553
};
541554
}
542555

556+
export function openShareWorkflowModal(workflow) {
557+
return { type: OPEN_SHARE_WORKFLOW_MODAL, workflow };
558+
}
559+
560+
export function closeShareWorkflowModal() {
561+
return { type: CLOSE_SHARE_WORKFLOW_MODAL };
562+
}
563+
543564
export function fetchUsersSharedWithYou() {
544565
return async (dispatch) => {
545566
dispatch({ type: USERS_SHARED_WITH_YOU_FETCH });
@@ -577,3 +598,90 @@ export function fetchUsersYouSharedWith() {
577598
});
578599
};
579600
}
601+
602+
export function fetchWorkflowShareStatus(id) {
603+
return async (dispatch) => {
604+
dispatch({ type: WORKFLOW_SHARE_STATUS_FETCH });
605+
return await client
606+
.getWorkflowShareStatus(id)
607+
.then((resp) => {
608+
dispatch({
609+
type: WORKFLOW_SHARE_STATUS_RECEIVED,
610+
id,
611+
workflow_share_status: resp.data.shared_with,
612+
});
613+
return resp;
614+
})
615+
.catch((err) => {
616+
dispatch(errorActionCreator(err, WORKFLOW_SHARE_STATUS_FETCH_ERROR));
617+
});
618+
};
619+
}
620+
621+
export function shareWorkflow(
622+
id,
623+
user_id,
624+
user_emails_to_share_with,
625+
valid_until,
626+
) {
627+
return async (dispatch) => {
628+
dispatch({ type: WORKFLOW_SHARE_INIT });
629+
630+
const users_shared_with = [];
631+
const users_not_shared_with = [];
632+
633+
for (const user_email_to_share_with of user_emails_to_share_with) {
634+
await client
635+
.shareWorkflow(id, {
636+
user_id,
637+
user_email_to_share_with,
638+
valid_until,
639+
})
640+
.then(() => {
641+
users_shared_with.push(user_email_to_share_with);
642+
})
643+
.catch((err) => {
644+
const error_message = err.response.data.message;
645+
users_not_shared_with.push({
646+
user_email_to_share_with,
647+
error_message,
648+
});
649+
});
650+
651+
if (users_shared_with.length > 0) {
652+
dispatch({
653+
type: WORKFLOW_SHARED_SUCCESSFULLY,
654+
users_shared_with,
655+
});
656+
}
657+
658+
if (users_not_shared_with.length > 0) {
659+
dispatch({
660+
type: WORKFLOW_SHARED_ERROR,
661+
users_not_shared_with,
662+
});
663+
}
664+
}
665+
666+
dispatch({ type: WORKFLOW_SHARE_FINISH });
667+
};
668+
}
669+
670+
export function unshareWorkflow(id, user_id, user_email_to_unshare_with) {
671+
return async (dispatch) => {
672+
dispatch({ type: WORKFLOW_UNSHARE_INIT });
673+
674+
return await client
675+
.unshareWorkflow(id, {
676+
user_id,
677+
user_email_to_unshare_with,
678+
})
679+
.then(() => {
680+
dispatch({ type: WORKFLOW_UNSHARED, user_email_to_unshare_with });
681+
})
682+
.catch((err) => {
683+
const error_message = err.response.data.message;
684+
dispatch({ type: WORKFLOW_UNSHARE_ERROR, error_message });
685+
});
686+
};
687+
}

reana-ui/src/client.js

+23
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export const WORKFLOW_FILE_URL = (id, filename, preview = true) =>
4545
)}`;
4646
export const WORKFLOW_SET_STATUS_URL = (id, status) =>
4747
`${api}/api/workflows/${id}/status?${stringifyQueryParams(status)}`;
48+
export const WORKFLOW_SHARE_STATUS_URL = (id) =>
49+
`${api}/api/workflows/${id}/share-status`;
50+
export const WORKFLOW_SHARE_URL = (id) => `${api}/api/workflows/${id}/share`;
51+
export const WORKFLOW_UNSHARE_URL = (id) =>
52+
`${api}/api/workflows/${id}/unshare`;
4853
export const INTERACTIVE_SESSIONS_OPEN_URL = (id, type = "jupyter") =>
4954
`${api}/api/workflows/${id}/open/${type}`;
5055
export const INTERACTIVE_SESSIONS_CLOSE_URL = (id) =>
@@ -226,6 +231,24 @@ class Client {
226231
getUsersYouSharedWith() {
227232
return this._request(USERS_YOU_SHARED_WITH_URL);
228233
}
234+
235+
getWorkflowShareStatus(id) {
236+
return this._request(WORKFLOW_SHARE_STATUS_URL(id));
237+
}
238+
239+
shareWorkflow(id, data) {
240+
return this._request(WORKFLOW_SHARE_URL(id), {
241+
data,
242+
method: "post",
243+
});
244+
}
245+
246+
unshareWorkflow(id, data) {
247+
return this._request(WORKFLOW_UNSHARE_URL(id), {
248+
data,
249+
method: "post",
250+
});
251+
}
229252
}
230253

231254
const client = new Client();

reana-ui/src/components/WorkflowActionsPopup.js

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
openDeleteWorkflowModal,
2121
openStopWorkflowModal,
2222
openInteractiveSessionModal,
23+
openShareWorkflowModal,
2324
} from "~/actions";
2425

2526
import { JupyterNotebookIcon } from "~/components";
@@ -51,6 +52,17 @@ export default function WorkflowActionsPopup({ workflow, className }) {
5152
});
5253
}
5354

55+
menuItems.push({
56+
key: "share",
57+
content: "Share workflow",
58+
icon: "share alternate",
59+
onClick: (e) => {
60+
dispatch(openShareWorkflowModal(workflow));
61+
setOpen(false);
62+
e.stopPropagation();
63+
},
64+
});
65+
5466
if (isSessionOpen) {
5567
menuItems.push({
5668
key: "closeNotebook",

0 commit comments

Comments
 (0)