Loading frontend/src/components/ExerciseList/DownloadLogsButton.tsx +47 −11 Original line number Diff line number Diff line import type { ButtonProps } from '@blueprintjs/core' import { AnchorButton, Button, ButtonGroup, Popover } from '@blueprintjs/core' import { Button, ButtonGroup, Popover } from '@blueprintjs/core' import { css } from '@emotion/css' import { useHost } from '@inject/graphql/connection/host' import { downloadLogUrl } from '@inject/shared/config' import { notify } from '@inject/shared/notification/engine' import authenticatedFetch from '@inject/shared/utils/authenticatedFetch' import type { FC } from 'react' import { useState } from 'react' const content = css` padding: 0.5rem; Loading @@ -23,28 +26,61 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ }) => { const host = useHost() const [standardLoading, setStandardLoading] = useState(false) const [anonymizedLoading, setAnonymizedLoading] = useState(false) const handleClick = (anonymize: boolean) => { switch (anonymize) { case false: setStandardLoading(true) break case true: setAnonymizedLoading(true) break } authenticatedFetch(downloadLogUrl(host, exerciseId, anonymize)) .then(response => response.blob()) .then(blob => { const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `IXP-exercise-${exerciseId}-logs${anonymize ? '-anonymized' : ''}.zip` a.click() }) .catch(error => notify(error.message, JSON.stringify(error), { intent: 'danger' }) ) .finally(() => { switch (anonymize) { case false: setStandardLoading(false) break case true: setAnonymizedLoading(false) break } }) } return ( <Popover content={ <div className={content}> <div>Download logs:</div> <ButtonGroup vertical alignText='left'> <AnchorButton <Button loading={standardLoading} icon='people' href={downloadLogUrl(host || '', exerciseId, false)} target='_blank' rel='noreferrer' onClick={() => handleClick(false)} > Standard </AnchorButton> <AnchorButton </Button> <Button loading={anonymizedLoading} icon='blocked-person' href={downloadLogUrl(host || '', exerciseId, true)} target='_blank' rel='noreferrer' onClick={() => handleClick(true)} > Anonymized </AnchorButton> </Button> </ButtonGroup> </div> } Loading frontend/src/components/FileViewRedirectButton/index.tsx +0 −7 Original line number Diff line number Diff line Loading @@ -2,7 +2,6 @@ import { useNavigate } from '@/router' import { Classes, Icon } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { FileInfo } from '@inject/graphql/fragment-types' import { SUPPORTED_FILE_EXTENSIONS } from '@inject/shared/components/DocViewer' import { breakWord } from '@inject/shared/css/textOverflow' import type { MouseEventHandler } from 'react' import { useMemo, type FC } from 'react' Loading Loading @@ -83,12 +82,6 @@ const FileViewRedirectButton: FC<DocumentViewButtonProps> = ({ // prevent default navigation using anchor to avoid page reload e.preventDefault() const extension = fileInfo.fileName.split('.').pop() if (!extension || !SUPPORTED_FILE_EXTENSIONS.includes(extension)) { window.open(href, '_blank') return } /* * this has to be done with apply to ensure type safety between * link.to and link.params Loading frontend/src/components/Table/Body.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ const Body = <T,>({ } return ( <td className={tableCell}> <td className={tableCell} onClick={e => e.stopPropagation()}> <Checkbox className={checkbox} checked={row.isSelected} Loading shared/components/DocViewer/renderers/NotSupportedRenderer.tsx +32 −13 Original line number Diff line number Diff line import { useEffect, type FC } from 'react' import { AnchorButton, NonIdealState } from '@blueprintjs/core' import { useEffect, useRef, type FC } from 'react' import type { RendererProps } from '../types' const NotSupportedRenderer: FC<RendererProps> = ({ doc }) => { const hasDownloaded = useRef(false) useEffect(() => { if (!hasDownloaded.current) { hasDownloaded.current = true const link = document.createElement('a') link.href = doc.uri link.download = doc.fileName document.body.appendChild(link) link.click() document.body.removeChild(link) if (window.history.length > 1) { window.history.back() } else { window.close() } }, [doc.fileName, doc.uri]) return <></> return ( <NonIdealState icon='cloud-download' title='File type not supported' description='Downloading should start automatically. If not, please click the download button below.' action={ <AnchorButton icon='download' href={doc.uri} target='_blank' rel='noreferrer' intent='primary' loading={!doc.uri} download={doc.fileName} > Download </AnchorButton> } /> ) } export default NotSupportedRenderer Loading
frontend/src/components/ExerciseList/DownloadLogsButton.tsx +47 −11 Original line number Diff line number Diff line import type { ButtonProps } from '@blueprintjs/core' import { AnchorButton, Button, ButtonGroup, Popover } from '@blueprintjs/core' import { Button, ButtonGroup, Popover } from '@blueprintjs/core' import { css } from '@emotion/css' import { useHost } from '@inject/graphql/connection/host' import { downloadLogUrl } from '@inject/shared/config' import { notify } from '@inject/shared/notification/engine' import authenticatedFetch from '@inject/shared/utils/authenticatedFetch' import type { FC } from 'react' import { useState } from 'react' const content = css` padding: 0.5rem; Loading @@ -23,28 +26,61 @@ const DownloadLogsButton: FC<DownloadLogsButtonProps> = ({ }) => { const host = useHost() const [standardLoading, setStandardLoading] = useState(false) const [anonymizedLoading, setAnonymizedLoading] = useState(false) const handleClick = (anonymize: boolean) => { switch (anonymize) { case false: setStandardLoading(true) break case true: setAnonymizedLoading(true) break } authenticatedFetch(downloadLogUrl(host, exerciseId, anonymize)) .then(response => response.blob()) .then(blob => { const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `IXP-exercise-${exerciseId}-logs${anonymize ? '-anonymized' : ''}.zip` a.click() }) .catch(error => notify(error.message, JSON.stringify(error), { intent: 'danger' }) ) .finally(() => { switch (anonymize) { case false: setStandardLoading(false) break case true: setAnonymizedLoading(false) break } }) } return ( <Popover content={ <div className={content}> <div>Download logs:</div> <ButtonGroup vertical alignText='left'> <AnchorButton <Button loading={standardLoading} icon='people' href={downloadLogUrl(host || '', exerciseId, false)} target='_blank' rel='noreferrer' onClick={() => handleClick(false)} > Standard </AnchorButton> <AnchorButton </Button> <Button loading={anonymizedLoading} icon='blocked-person' href={downloadLogUrl(host || '', exerciseId, true)} target='_blank' rel='noreferrer' onClick={() => handleClick(true)} > Anonymized </AnchorButton> </Button> </ButtonGroup> </div> } Loading
frontend/src/components/FileViewRedirectButton/index.tsx +0 −7 Original line number Diff line number Diff line Loading @@ -2,7 +2,6 @@ import { useNavigate } from '@/router' import { Classes, Icon } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { FileInfo } from '@inject/graphql/fragment-types' import { SUPPORTED_FILE_EXTENSIONS } from '@inject/shared/components/DocViewer' import { breakWord } from '@inject/shared/css/textOverflow' import type { MouseEventHandler } from 'react' import { useMemo, type FC } from 'react' Loading Loading @@ -83,12 +82,6 @@ const FileViewRedirectButton: FC<DocumentViewButtonProps> = ({ // prevent default navigation using anchor to avoid page reload e.preventDefault() const extension = fileInfo.fileName.split('.').pop() if (!extension || !SUPPORTED_FILE_EXTENSIONS.includes(extension)) { window.open(href, '_blank') return } /* * this has to be done with apply to ensure type safety between * link.to and link.params Loading
frontend/src/components/Table/Body.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ const Body = <T,>({ } return ( <td className={tableCell}> <td className={tableCell} onClick={e => e.stopPropagation()}> <Checkbox className={checkbox} checked={row.isSelected} Loading
shared/components/DocViewer/renderers/NotSupportedRenderer.tsx +32 −13 Original line number Diff line number Diff line import { useEffect, type FC } from 'react' import { AnchorButton, NonIdealState } from '@blueprintjs/core' import { useEffect, useRef, type FC } from 'react' import type { RendererProps } from '../types' const NotSupportedRenderer: FC<RendererProps> = ({ doc }) => { const hasDownloaded = useRef(false) useEffect(() => { if (!hasDownloaded.current) { hasDownloaded.current = true const link = document.createElement('a') link.href = doc.uri link.download = doc.fileName document.body.appendChild(link) link.click() document.body.removeChild(link) if (window.history.length > 1) { window.history.back() } else { window.close() } }, [doc.fileName, doc.uri]) return <></> return ( <NonIdealState icon='cloud-download' title='File type not supported' description='Downloading should start automatically. If not, please click the download button below.' action={ <AnchorButton icon='download' href={doc.uri} target='_blank' rel='noreferrer' intent='primary' loading={!doc.uri} download={doc.fileName} > Download </AnchorButton> } /> ) } export default NotSupportedRenderer