Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add download modal to dataset view actions #6283

Merged
merged 13 commits into from
Jun 21, 2022
Merged
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/default_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ const defaultState: OxalisState = {
showDropzoneModal: false,
showVersionRestore: false,
showDownloadModal: false,
showPythonClientModal: false,
showShareModal: false,
storedLayouts: {},
isImportingMesh: false,
Expand Down
15 changes: 11 additions & 4 deletions frontend/javascripts/oxalis/model/actions/ui_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ type SetThemeAction = {
type: "SET_THEME";
value: Theme;
};

type SetDownloadModalVisibilityAction = {
type: "SET_DOWNLOAD_MODAL_VISIBILITY";
visible: boolean;
};

type SetPythonClientModalVisibilityAction = {
type: "SET_PYTHON_MODAL_VISIBILITY";
visible: boolean;
};
type SetShareModalVisibilityAction = {
type: "SET_SHARE_MODAL_VISIBILITY";
visible: boolean;
Expand All @@ -68,6 +70,7 @@ export type UiAction =
| CycleToolAction
| SetThemeAction
| SetDownloadModalVisibilityAction
| SetPythonClientModalVisibilityAction
| SetShareModalVisibilityAction
| SetBusyBlockingInfoAction;
export const setDropzoneModalVisibilityAction = (
Expand Down Expand Up @@ -117,14 +120,18 @@ export const setThemeAction = (value: Theme): SetThemeAction => ({
type: "SET_THEME",
value,
});

export const setDownloadModalVisibilityAction = (
visible: boolean,
): SetDownloadModalVisibilityAction => ({
type: "SET_DOWNLOAD_MODAL_VISIBILITY",
visible,
});

export const setPythonClientModalVisibilityAction = (
visible: boolean,
): SetPythonClientModalVisibilityAction => ({
type: "SET_PYTHON_MODAL_VISIBILITY",
visible,
});
export const setShareModalVisibilityAction = (visible: boolean): SetShareModalVisibilityAction => ({
type: "SET_SHARE_MODAL_VISIBILITY",
visible,
Expand Down
4 changes: 4 additions & 0 deletions frontend/javascripts/oxalis/model/reducers/ui_reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ function UiReducer(state: OxalisState, action: Action): OxalisState {
return updateKey(state, "uiInformation", { showDownloadModal: action.visible });
}

case "SET_PYTHON_MODAL_VISIBILITY": {
return updateKey(state, "uiInformation", { showPythonClientModal: action.visible });
}

case "SET_SHARE_MODAL_VISIBILITY": {
return updateKey(state, "uiInformation", {
showShareModal: action.visible,
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ type UiInformation = {
readonly showDropzoneModal: boolean;
readonly showVersionRestore: boolean;
readonly showDownloadModal: boolean;
readonly showPythonClientModal: boolean;
readonly showShareModal: boolean;
readonly activeTool: AnnotationTool;
readonly storedLayouts: Record<string, any>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ type Props = {
hasVolumeFallback: boolean;
};

function Hint({ children, style }: { children: React.ReactNode; style: React.CSSProperties }) {
export function Hint({
children,
style,
}: {
children: React.ReactNode;
style: React.CSSProperties;
}) {
return (
<div style={{ ...style, fontSize: 12, color: "var(--ant-text-secondary)" }}>{children}</div>
);
Expand All @@ -45,7 +51,7 @@ export async function copyToClipboard(code: string) {
Toast.success("Snippet copied to clipboard.");
}

function MoreInfoHint() {
export function MoreInfoHint() {
return (
<Hint
style={{
Expand All @@ -65,7 +71,7 @@ function MoreInfoHint() {
);
}

function CopyableCodeSnippet({ code, onCopy }: { code: string; onCopy?: () => void }) {
export function CopyableCodeSnippet({ code, onCopy }: { code: string; onCopy?: () => void }) {
return (
<pre>
<Button
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Divider, Modal, Row, Typography } from "antd";
import React from "react";
import { useFetch } from "libs/react_helpers";
import Toast from "libs/toast";
import messages from "messages";
import { getAuthToken } from "admin/admin_rest_api";
import { useSelector } from "react-redux";
import type { OxalisState } from "oxalis/store";
import { CopyableCodeSnippet, MoreInfoHint } from "./download_modal_view";
const { Paragraph, Text } = Typography;
type Props = {
onClose: () => void;
};

export default function PythonClientModalView(props: Props): JSX.Element {
philippotto marked this conversation as resolved.
Show resolved Hide resolved
const { onClose } = props;
const isPythonClientModalOpen = useSelector(
(state: OxalisState) => state.uiInformation.showPythonClientModal,
);
const activeUser = useSelector((state: OxalisState) => state.activeUser);
const dataset = useSelector((state: OxalisState) => state.dataset);

const maybeShowWarning = () => (
<Row>
<Text
style={{
margin: "0 6px 12px",
}}
type="warning"
>
{activeUser != null
? messages["annotation.python_do_not_share"]
: messages["annotation.register_for_token"]}
</Text>
</Row>
);

const authToken = useFetch(
async () => {
if (activeUser != null) {
return getAuthToken();
}
return null;
},
"loading...",
[activeUser],
);
const wkInitSnippet = `import webknossos as wk

with wk.webknossos_context(token="${authToken || "<insert token here>"}"):
dataset = wk.Dataset.download(
url="${window.location.origin}",
dataset="${dataset.name}"
organization_id="${dataset.owningOrganization}",
)
`;

const alertTokenIsPrivate = () => {
Toast.warning(
"The clipboard contains private data. Do not share this information with anyone you do not trust!",
);
};

return (
<Modal
title="Python Client"
visible={isPythonClientModalOpen}
width={600}
footer={null}
onCancel={onClose}
style={{ overflow: "visible" }}
>
<Row>
<Text
style={{
margin: "0 6px 12px",
}}
>
The following code snippets are suggestions to get you started quickly with the{" "}
<a href="https://docs.webknossos.org/webknossos-py/" target="_blank" rel="noreferrer">
webKnossos Python API
</a>
. To download and use this annotation in your Python project, simply copy and paste the
code snippets to your script.
</Text>
</Row>
<Divider
style={{
margin: "18px 0",
}}
>
Code Snippets
</Divider>
{maybeShowWarning()}
<Paragraph>
<CopyableCodeSnippet code="pip install webknossos" />
<CopyableCodeSnippet code={wkInitSnippet} onCopy={alertTokenIsPrivate} />
</Paragraph>
<Divider
style={{
margin: "18px 0",
}}
/>
<MoreInfoHint />
</Modal>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ type StateProps = {
task: Task | null | undefined;
activeUser: APIUser | null | undefined;
hasTracing: boolean;
isShareModalOpen: boolean;
isDownloadModalOpen: boolean;
isShareModalOpen: boolean;
busyBlockingInfo: BusyBlockingInfo;
};
type Props = OwnProps & StateProps;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React from "react";
import { Dropdown, Menu } from "antd";
import { ShareAltOutlined, DownOutlined, CameraOutlined } from "@ant-design/icons";
import { ShareAltOutlined, DownOutlined, CameraOutlined, CodeOutlined } from "@ant-design/icons";
import ButtonComponent from "oxalis/view/components/button_component";
import ShareViewDatasetModalView from "oxalis/view/action-bar/share_view_dataset_modal_view";
import { downloadScreenshot } from "oxalis/view/rendering_utils";
import { setShareModalVisibilityAction } from "oxalis/model/actions/ui_actions";
import {
setPythonClientModalVisibilityAction,
setShareModalVisibilityAction,
} from "oxalis/model/actions/ui_actions";
import Store from "oxalis/store";
import PythonClientModalView from "./python_client_modal_view";

type Props = {
layoutMenu: React.ReactNode;
Expand All @@ -17,9 +21,14 @@ export const screenshotMenuItem = (
</Menu.Item>
);
export default function ViewDatasetActionsView(props: Props) {
const modal = (
const shareDatasetModal = (
<ShareViewDatasetModalView onOk={() => Store.dispatch(setShareModalVisibilityAction(false))} />
);
const pythonClientModal = (
<PythonClientModalView
onClose={() => Store.dispatch(setPythonClientModalVisibilityAction(false))}
/>
);
const overlayMenu = (
<Menu>
<Menu.Item
Expand All @@ -30,6 +39,13 @@ export default function ViewDatasetActionsView(props: Props) {
Share
</Menu.Item>
{screenshotMenuItem}
<Menu.Item
key="python-client-button"
onClick={() => Store.dispatch(setPythonClientModalVisibilityAction(true))}
>
<CodeOutlined />
Python Client
philippotto marked this conversation as resolved.
Show resolved Hide resolved
</Menu.Item>
{props.layoutMenu}
</Menu>
);
Expand All @@ -39,7 +55,8 @@ export default function ViewDatasetActionsView(props: Props) {
marginLeft: 10,
}}
>
{modal}
{shareDatasetModal}
{pythonClientModal}
<Dropdown overlay={overlayMenu} trigger={["click"]}>
<ButtonComponent
style={{
Expand Down