Skip to content

Commit

Permalink
feat: add import zip tab
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Dec 16, 2021
1 parent 39901ef commit b61a1b2
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 10 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"license": "AGPL-3.0-only",
"dependencies": {
"@graasp/chatbox": "git://github.com/graasp/graasp-chatbox.git#main",
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git",
"@graasp/ui": "git://github.com/graasp/graasp-ui.git",
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git#102/importZip",
"@graasp/ui": "git://github.com/graasp/graasp-ui.git#69/zipIcon",
"@material-ui/core": "4.11.2",
"@material-ui/icons": "5.0.0-beta.4",
"@material-ui/lab": "4.0.0-alpha.57",
Expand Down
100 changes: 100 additions & 0 deletions src/components/main/ImportZip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { useEffect, useState } from 'react';
import '@uppy/core/dist/style.css';
import '@uppy/dashboard/dist/style.css';
import { routines } from '@graasp/query-client';
import { Dashboard } from '@uppy/react';
import { useRouteMatch } from 'react-router';
import { useTranslation } from 'react-i18next';
import Typography from '@material-ui/core/Typography';
import { FILE_UPLOAD_MAX_FILES } from '../../config/constants';
import { configureZipImportUppy } from '../../utils/uppy';
import { ZIP_DASHBOARD_UPLOADER_ID } from '../../config/selectors';
import { buildItemPath } from '../../config/paths';
import notifier from '../../middlewares/notifier';

const ImportZip = () => {
const [uppy, setUppy] = useState(null);
const match = useRouteMatch(buildItemPath());
const itemId = match?.params?.itemId;
const { t } = useTranslation();

const onComplete = (result) => {
// update app on complete
// todo: improve with websockets or by receiving corresponding items
if (!result?.failed.length) {
notifier({ type: routines.importZipRoutine.SUCCESS });
}
};
const onError = () => {
notifier({ type: routines.importZipRoutine.FAILURE });
};

const onFilesAdded = () => {
notifier({ type: routines.importZipRoutine.REQUEST });
};

const applyUppy = () =>
setUppy(
configureZipImportUppy({
itemId,
onComplete,
onError,
onFilesAdded,
}),
);

useEffect(() => {
applyUppy();

return () => {
uppy?.close();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
applyUppy();
// update uppy configuration each time itemId changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [itemId]);

if (!uppy) {
return null;
}

return (
<>
<Typography variant="h6">{t('Import a Graasp Archive')}</Typography>
<Typography variant="caption">
{t(
'You can download your resources from graasp.eu by right clicking and choosing "Download as ZIP".',
)}
</Typography>
<div id={ZIP_DASHBOARD_UPLOADER_ID}>
<Dashboard
uppy={uppy}
height={200}
width="100%"
proudlyDisplayPoweredByUppy={false}
note={t(
`You can upload up to FILE_UPLOAD_MAX_FILES files at a time`,
{
maxFiles: FILE_UPLOAD_MAX_FILES,
},
)}
locale={{
strings: {
// Text to show on the droppable area.
// `%{browse}` is replaced with a link that opens the system file selection dialog.
dropPaste: `${t('Drop here or')} %{browse}`,
// Used as the label for the link that opens the system file selection dialog.
browse: t('Browse'),
},
}}
/>
</div>
</>
);
};

export default ImportZip;
16 changes: 16 additions & 0 deletions src/components/main/ItemTypeTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
CREATE_ITEM_FOLDER_ID,
CREATE_ITEM_DOCUMENT_ID,
CREATE_ITEM_APP_ID,
CREATE_ITEM_ZIP_ID,
} from '../../config/selectors';

const useStyles = makeStyles((theme) => ({
Expand Down Expand Up @@ -38,6 +39,14 @@ const ItemTypeTabs = ({ onTypeChange, initialValue }) => {
onTypeChange(newValue);
};

const zipIcon = (
<ItemIcon
type={ITEM_TYPES.FILE}
iconClass={classes.icon}
extra={{ file: { mimetype: 'application/zip' } }}
/>
);

return (
<Tabs
centered
Expand Down Expand Up @@ -81,6 +90,13 @@ const ItemTypeTabs = ({ onTypeChange, initialValue }) => {
icon={<ItemIcon type={ITEM_TYPES.APP} iconClass={classes.icon} />}
classes={{ wrapper: classes.wrapper }}
/>
<Tab
id={CREATE_ITEM_ZIP_ID}
value={ITEM_TYPES.ZIP}
label={t('Import ZIP')}
icon={zipIcon}
classes={{ wrapper: classes.wrapper }}
/>
</Tabs>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/components/main/NewItemModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { buildItemPath } from '../../config/paths';
import DocumentForm from '../item/form/DocumentForm';
import AppForm from '../item/form/AppForm';
import ItemTypeTabs from './ItemTypeTabs';
import ImportZip from './ImportZip';

const useStyles = makeStyles((theme) => ({
dialogContent: {
Expand Down Expand Up @@ -103,6 +104,8 @@ const NewItemModal = ({ open, handleClose }) => {
);
case ITEM_TYPES.FILE:
return <FileDashboardUploader />;
case ITEM_TYPES.ZIP:
return <ImportZip />;
case ITEM_TYPES.APP:
return (
<AppForm
Expand Down Expand Up @@ -157,6 +160,7 @@ const NewItemModal = ({ open, handleClose }) => {
</>
);
case ITEM_TYPES.FILE:
case ITEM_TYPES.ZIP:
return (
<Button
id={CREATE_ITEM_CLOSE_BUTTON_ID}
Expand Down
6 changes: 6 additions & 0 deletions src/config/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,9 @@ export const UPLOAD_AVATAR_SUCCESS_MESSAGE =
'The avatar was successfully uploaded.';
export const UPLOAD_AVATAR_FAILURE_MESSAGE =
'An error occurred while uploading the avatar.';
export const IMPORT_ZIP_SUCCESS_MESSAGE =
'The ZIP archive was successfully imported.';
export const IMPORT_ZIP_FAILURE_MESSAGE =
'An error occurred while importing The ZIP archive.';
export const IMPORT_ZIP_PROGRESS_MESSAGE =
'The ZIP is being processed. Please wait a moment.';
2 changes: 2 additions & 0 deletions src/config/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const ITEM_FORM_DOCUMENT_TEXT_SELECTOR = `#${ITEM_FORM_DOCUMENT_TEXT_ID}
export const DOCUMENT_ITEM_TEXT_EDITOR_ID = 'documentItemTextEditor';
export const DOCUMENT_ITEM_TEXT_EDITOR_SELECTOR = `#${DOCUMENT_ITEM_TEXT_EDITOR_ID} .ql-editor`;
export const CREATE_ITEM_APP_ID = 'createItemApp';
export const CREATE_ITEM_ZIP_ID = 'createItemZip';
export const ITEM_FORM_APP_URL_ID = 'itemFormAppUrl';
export const buildItemFormAppOptionId = (name) =>
`${name.replaceAll(/\s/g, '-')}`;
Expand Down Expand Up @@ -159,3 +160,4 @@ export const THUMBNAIL_SETTING_UPLOAD_BUTTON_CLASSNAME =
export const CROP_MODAL_CONFIRM_BUTTON_CLASSNAME = 'cropModalConfirmButton';
export const MEMBER_PROFILE_AVATAR_UPLOAD_BUTTON_CLASSNAME =
'memberProfileAvatarUploadButton';
export const ZIP_DASHBOARD_UPLOADER_ID = 'zipDashboardUploader';
3 changes: 3 additions & 0 deletions src/enums/itemTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const ITEM_TYPES = {
SHORTCUT: 'shortcut',
DOCUMENT: 'document',
APP: 'app',
// the following isn't a real item type
// but is used for the creation modal
ZIP: 'zip',
};

Object.freeze(ITEM_TYPES);
Expand Down
19 changes: 19 additions & 0 deletions src/middlewares/notifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import {
UPLOAD_ITEM_THUMBNAIL_FAILURE_MESSAGE,
UPLOAD_AVATAR_FAILURE_MESSAGE,
UPLOAD_AVATAR_SUCCESS_MESSAGE,
IMPORT_ZIP_SUCCESS_MESSAGE,
IMPORT_ZIP_FAILURE_MESSAGE,
IMPORT_ZIP_PROGRESS_MESSAGE,
} from '../config/messages';
import {
COPY_ITEM_LINK_TO_CLIPBOARD,
Expand Down Expand Up @@ -72,6 +75,7 @@ const {
restoreItemsRoutine,
uploadItemThumbnailRoutine,
uploadAvatarRoutine,
importZipRoutine,
} = routines;

export default ({ type, payload }) => {
Expand Down Expand Up @@ -163,6 +167,10 @@ export default ({ type, payload }) => {
message = UPLOAD_AVATAR_FAILURE_MESSAGE;
break;
}
case importZipRoutine.FAILURE: {
message = IMPORT_ZIP_FAILURE_MESSAGE;
break;
}
// success messages
case editMemberRoutine.SUCCESS: {
message = EDIT_MEMBER_SUCCESS_MESSAGE;
Expand Down Expand Up @@ -237,6 +245,10 @@ export default ({ type, payload }) => {
message = UPLOAD_AVATAR_SUCCESS_MESSAGE;
break;
}
case importZipRoutine.SUCCESS: {
message = IMPORT_ZIP_SUCCESS_MESSAGE;
break;
}

// progress messages
// todo: this might be handled differently
Expand All @@ -254,6 +266,13 @@ export default ({ type, payload }) => {
);
break;
}
case importZipRoutine.REQUEST: {
toastr.info(
i18n.t(FILE_UPLOAD_INFO_MESSAGE_HEADER),
i18n.t(IMPORT_ZIP_PROGRESS_MESSAGE),
);
break;
}
default:
}

Expand Down
20 changes: 20 additions & 0 deletions src/utils/uppy.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,23 @@ export const configureAvatarUppy = ({
buildEndpoint: (id) =>
`${API_HOST}/${API_ROUTES.buildUploadAvatarRoute(id)}`,
});

export const configureZipImportUppy = ({
itemId,
onComplete,
onFilesAdded,
onError,
onUpload,
}) =>
configureUppy({
itemId,
onComplete,
onFilesAdded,
onError,
onUpload,
restrictions: {
maxNumberOfFiles: 1,
allowedFileTypes: ['application/zip'],
},
buildEndpoint: (id) => `${API_HOST}/${API_ROUTES.buildImportZipRoute(id)}`,
});
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2166,9 +2166,9 @@ __metadata:
languageName: node
linkType: hard

"@graasp/query-client@git://github.com/graasp/graasp-query-client.git":
"@graasp/query-client@git://github.com/graasp/graasp-query-client.git#102/importZip":
version: 0.1.0
resolution: "@graasp/query-client@git://github.com/graasp/graasp-query-client.git#commit=d90ea22f41148aa45fef8748d9f74be45d86ff13"
resolution: "@graasp/query-client@git://github.com/graasp/graasp-query-client.git#commit=610c7ff002170511103446cd34e760fea30a109b"
dependencies:
axios: 0.24.0
http-status-codes: 2.1.4
Expand All @@ -2179,13 +2179,13 @@ __metadata:
uuid: 8.3.2
peerDependencies:
react: ^17.0.0
checksum: 995f51a282a436138f2852a22f88190b660f804645c31209b7405fc8172378612af032c07bd9d6a795c6f842186019ee93b5ade83d581613ac7d5792e9964812
checksum: 7cec90bd113a7d809ab4ce413c30f222afb71fdeae7b9e38d94288f9812a18ba8ce3fb57b667d9308fc540944957ac759e7ba63a9a739a41ede717f47d4c0443
languageName: node
linkType: hard

"@graasp/ui@git://github.com/graasp/graasp-ui.git":
"@graasp/ui@git://github.com/graasp/graasp-ui.git#69/zipIcon":
version: 0.2.0
resolution: "@graasp/ui@git://github.com/graasp/graasp-ui.git#commit=e0573ae34d23909f2dcd5cb269ed7122b4be3169"
resolution: "@graasp/ui@git://github.com/graasp/graasp-ui.git#commit=a45584873602f4e031a7597f043786684f8e3699"
dependencies:
clsx: 1.1.1
http-status-codes: 2.1.4
Expand All @@ -2202,7 +2202,7 @@ __metadata:
i18next: 21.3.1
react: ^16.13.1
react-dom: 16.13.1
checksum: c5d3c0d9dfa2c0f5e6536a112570618846fbed3c04cb3222be6bdf9578efde553054f48144e4d7eadf16a7917f43fe492f88208f49a3974a03ee6ceb3dc875cb
checksum: 2b935e912e059958f4790685f6cc8207573f0385b77ac977ff3f023145bafab08b221c6ed39c23880ce87fba5f84f929b56db6b8543b2ca8db475becaed8e827
languageName: node
linkType: hard

Expand Down Expand Up @@ -10279,8 +10279,8 @@ __metadata:
"@cypress/code-coverage": 3.9.2
"@cypress/instrument-cra": 1.4.0
"@graasp/chatbox": "git://github.com/graasp/graasp-chatbox.git#main"
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git"
"@graasp/ui": "git://github.com/graasp/graasp-ui.git"
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git#102/importZip"
"@graasp/ui": "git://github.com/graasp/graasp-ui.git#69/zipIcon"
"@graasp/websockets": "git://github.com/graasp/graasp-websockets.git#master"
"@material-ui/core": 4.11.2
"@material-ui/icons": 5.0.0-beta.4
Expand Down

0 comments on commit b61a1b2

Please sign in to comment.