Skip to content

Commit

Permalink
ui: add way to open, list and close interactive sessions
Browse files Browse the repository at this point in the history
closes #77
  • Loading branch information
audrium committed Oct 15, 2020
1 parent ab36fd4 commit c5cb8d5
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 87 deletions.
55 changes: 54 additions & 1 deletion reana-ui/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export const WORKFLOW_SPECIFICATION_RECEIVED =
"Workflow specification received";
export const WORKFLOW_DELETE_INIT = "Initialize workflow deletion";
export const WORKFLOW_DELETED = "Workflow deleted";
export const OPEN_DELETE_WORKFLOW_MODAL = "Open delete workflow modal";
export const CLOSE_DELETE_WORKFLOW_MODAL = "Close delete workflow modal";
export const WORKFLOW_LIST_REFRESH = "Refresh workflow list";

const CONFIG_URL = `${api}/api/config`;
const USER_INFO_URL = `${api}/api/you`;
Expand All @@ -70,7 +73,9 @@ const USER_SIGNIN_URL = `${api}/api/login`;
const USER_SIGNOUT_URL = `${api}/api/logout`;
const USER_REQUEST_TOKEN_URL = `${api}/api/token`;
const WORKFLOWS_URL = (params) =>
`${api}/api/workflows?verbose=true&${stringifyQueryParams(params)}`;
`${api}/api/workflows?verbose=true&type=interactive&${stringifyQueryParams(
params
)}`;
const WORKFLOW_LOGS_URL = (id) => `${api}/api/workflows/${id}/logs`;
const WORKFLOW_SPECIFICATION_URL = (id) =>
`${api}/api/workflows/${id}/specification`;
Expand All @@ -80,6 +85,12 @@ const WORKFLOW_FILES_URL = (id, pagination) =>
const WORKFLOW_SET_STATUS_URL = (id, status) =>
`${api}/api/workflows/${id}/status?${stringifyQueryParams(status)}`;

const INTERACTIVE_SESSIONS_OPEN_URL = (id, type = "jupyter") =>
`${api}/api/workflows/${id}/open/${type}`;

const INTERACTIVE_SESSIONS_CLOSE_URL = (id) =>
`${api}/api/workflows/${id}/close/`;

function errorActionCreator(error, name) {
const { status, data } = error?.response;
const { message } = data;
Expand Down Expand Up @@ -334,6 +345,7 @@ export function deleteWorkflow(id, workspace = false) {
)
.then((resp) => {
dispatch({ type: WORKFLOW_DELETED, ...resp.data });
dispatch({ type: WORKFLOW_LIST_REFRESH });
dispatch(triggerNotification("Success!", resp.data.message));
})
.catch((err) => {
Expand All @@ -346,3 +358,44 @@ export function deleteWorkflow(id, workspace = false) {
});
};
}

export function openDeleteWorkflowModal(workflow) {
return { type: OPEN_DELETE_WORKFLOW_MODAL, workflow };
}

export function closeDeleteWorkflowModal() {
return { type: CLOSE_DELETE_WORKFLOW_MODAL };
}

export function openInteractiveSession(id) {
return async (dispatch) => {
return await axios
.post(INTERACTIVE_SESSIONS_OPEN_URL(id), null, { withCredentials: true })
.then((resp) => {
dispatch({ type: WORKFLOW_LIST_REFRESH });
dispatch(
triggerNotification(
"Success!",
"The interactive session has been created. However, it could take several minutes to start the Jupyter Notebook."
)
);
})
.catch((err) => {
dispatch(errorActionCreator(err, INTERACTIVE_SESSIONS_OPEN_URL(id)));
});
};
}

export function closeInteractiveSession(id) {
return async (dispatch) => {
return await axios
.post(INTERACTIVE_SESSIONS_CLOSE_URL(id), null, { withCredentials: true })
.then((resp) => {
dispatch({ type: WORKFLOW_LIST_REFRESH });
dispatch(triggerNotification("Success!", resp.data.message));
})
.catch((err) => {
dispatch(errorActionCreator(err, INTERACTIVE_SESSIONS_CLOSE_URL(id)));
});
};
}
68 changes: 68 additions & 0 deletions reana-ui/src/components/JupyterNotebookIcon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions reana-ui/src/components/JupyterNotebookIcon.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
-*- coding: utf-8 -*-
This file is part of REANA.
Copyright (C) 2020 CERN.
REANA is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
*/

@import "@palette";

.icon {
display: inline-block;
vertical-align: middle;
}
1 change: 1 addition & 0 deletions reana-ui/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export { default as Pagination } from "./Pagination";
export { default as Title } from "./Title";
export { default as TopHeader } from "./TopHeader";
export { default as TooltipIfTruncated } from "./TooltipIfTruncated";
export { default as JupyterNotebookIcon } from "./JupyterNotebookIcon";
2 changes: 2 additions & 0 deletions reana-ui/src/pages/workflowDetails/WorkflowDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
WorkflowFiles,
WorkflowSpecification,
} from "./components";
import { WorkflowDeleteModal } from "../workflowList/components";

export default function WorkflowDetailsPage() {
return (
Expand Down Expand Up @@ -91,6 +92,7 @@ function WorkflowDetails() {
<Container>
<WorkflowInfo workflow={workflow} />
<Tab menu={{ secondary: true, pointing: true }} panes={panes} />
<WorkflowDeleteModal />
</Container>
);
}
36 changes: 20 additions & 16 deletions reana-ui/src/pages/workflowDetails/components/WorkflowInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Icon, Popup } from "semantic-ui-react";

import { statusMapping } from "~/util";
import { WorkflowProgress } from "../components";

import { WorkflowActionsPopup } from "../../workflowList/components";
import styles from "./WorkflowInfo.module.scss";

const NON_FINISHED_STATUSES = ["created", "queued", "running"];
Expand Down Expand Up @@ -63,23 +63,27 @@ export default function WorkflowInfo({ workflow }) {
}
/>
</div>
<div>
<span
className={`${styles["status"]} sui-${statusMapping[status].color}`}
>
{status}
</span>{" "}
{statusMapping[status].preposition} {status !== "deleted" && duration}
{NON_FINISHED_STATUSES.includes(status) && (
<Icon
name="refresh"
className={styles.refresh}
onClick={() => window.location.reload()}
/>
)}
<div className={styles.info}>
<div>
step {completed}/{total}
<span
className={`${styles["status"]} sui-${statusMapping[status].color}`}
>
{status}
</span>{" "}
{statusMapping[status].preposition}{" "}
{status !== "deleted" && duration}
{NON_FINISHED_STATUSES.includes(status) && (
<Icon
name="refresh"
className={styles.refresh}
onClick={() => window.location.reload()}
/>
)}
<div>
step {completed}/{total}
</div>
</div>
<WorkflowActionsPopup workflow={workflow} />
</div>
</section>
<WorkflowProgress workflow={workflow} />
Expand Down
5 changes: 5 additions & 0 deletions reana-ui/src/pages/workflowList/WorkflowList.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
getWorkflowsCount,
loadingWorkflows,
userHasWorkflows,
getWorkflowRefresh,
} from "~/selectors";
import BasePage from "../BasePage";
import { Title } from "~/components";
Expand Down Expand Up @@ -55,10 +56,13 @@ function Workflows() {
const workflows = useSelector(getWorkflows);
const workflowsCount = useSelector(getWorkflowsCount);
const hasUserWorkflows = useSelector(userHasWorkflows);
const workflowRefresh = useSelector(getWorkflowRefresh);
const loading = useSelector(loadingWorkflows);
const reanaToken = useSelector(getReanaToken);
const interval = useRef(null);

useEffect(() => cleanPolling(), [workflowRefresh]);

useEffect(() => {
dispatch(
fetchWorkflows({ ...pagination }, searchFilter, statusFilter, sortDir)
Expand Down Expand Up @@ -88,6 +92,7 @@ function Workflows() {
searchFilter,
statusFilter,
sortDir,
workflowRefresh,
]);

const cleanPolling = () => {
Expand Down
Loading

0 comments on commit c5cb8d5

Please sign in to comment.