From 81422299993af23310bfd430ab39970b0f7f9098 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Wed, 25 Nov 2020 15:26:40 -0500 Subject: [PATCH 01/51] context menu component --- src/UI/ContextMenu/context-menu.stories.js | 25 +++++++++ src/UI/ContextMenu/index.js | 51 +++++++++++++++++++ src/UI/ContextMenu/styles.js | 27 ++++++++++ .../components/ObjectsTable/ObjectsTable.js | 41 ++++++++++++++- 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 src/UI/ContextMenu/context-menu.stories.js create mode 100644 src/UI/ContextMenu/index.js create mode 100644 src/UI/ContextMenu/styles.js diff --git a/src/UI/ContextMenu/context-menu.stories.js b/src/UI/ContextMenu/context-menu.stories.js new file mode 100644 index 00000000..bdbb7e76 --- /dev/null +++ b/src/UI/ContextMenu/context-menu.stories.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { text } from '@storybook/addon-knobs'; + +import ContextMenu from './index'; + +const categoryName = 'ContextMenu'; + +storiesOf(categoryName, module).add('default', () => { + const defaultProps = { + menuItemOnClick: (id) => { console.log(id) }, + i18n: { + open: 'Open', + share: 'Share', + rename: 'Rename', + trash: 'Trash', + }, + }; + + return ( +
+ +
+ ); +}); diff --git a/src/UI/ContextMenu/index.js b/src/UI/ContextMenu/index.js new file mode 100644 index 00000000..b59295f1 --- /dev/null +++ b/src/UI/ContextMenu/index.js @@ -0,0 +1,51 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Paper from '@material-ui/core/Paper'; +import MenuItem from '@material-ui/core/MenuItem'; +import useStyles from './styles'; + +export const CONTEXT_OPTION_IDS = { + open: 'open', + share: 'share', + rename: 'rename', + trash: 'trash', +}; + +const ContextMenu = ({ + menuItemOnClick, + i18n, +}) => { + const classes = useStyles(); + + const items = [ + CONTEXT_OPTION_IDS.open, + CONTEXT_OPTION_IDS.share, + CONTEXT_OPTION_IDS.rename, + CONTEXT_OPTION_IDS.trash, + ]; + + return ( + + {items.map((item) => ( + menuItemOnClick(item)} + > + {i18n[item]} + + ))} + + ); +}; + +ContextMenu.propTypes = { + menuItemOnClick: PropTypes.func.isRequired, + i18n: PropTypes.shape({ + open: PropTypes.string, + share: PropTypes.string, + rename: PropTypes.string, + trash: PropTypes.string, + }).isRequired, +}; + +export default ContextMenu; diff --git a/src/UI/ContextMenu/styles.js b/src/UI/ContextMenu/styles.js new file mode 100644 index 00000000..e6f70e6e --- /dev/null +++ b/src/UI/ContextMenu/styles.js @@ -0,0 +1,27 @@ +import { makeStyles } from '@material-ui/core/styles'; + +const getOuterBorder = () => ('1px solid #D8D8d8'); +const getInnerBorder = (theme) => (`1px solid ${theme.palette.palette.gray4}`); + +export default makeStyles((theme) => ({ + paper: { + width: 165, + boxShadow: '0px 3px 6px #00000029', + borderRadius: 6, + }, + menuItem: { + borderRight: getOuterBorder(theme), + borderLeft: getOuterBorder(theme), + borderBottom: getInnerBorder(theme), + '&:first-child': { + borderTop: getOuterBorder(theme), + borderTopRightRadius: 6, + borderTopLeftRadius: 6, + }, + '&:last-child': { + borderBottom: getOuterBorder(theme), + borderBottomRightRadius: 6, + borderBottomLeftRadius: 6, + }, + }, +})); diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 9a4e0747..ca47edab 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -13,6 +13,10 @@ import Typography from '@material-ui/core/Typography'; import { openObject } from '@events'; import { UPDATE_OBJECTS } from '@reducers/storage'; import Dropzone from '@shared/components/Dropzone'; +import Paper from '@material-ui/core/Paper'; +import MenuItem from '@material-ui/core/MenuItem'; +import Popper from '@material-ui/core/Popper'; +import ClickAwayListener from '@material-ui/core/ClickAwayListener'; import Table, { TableCell, TableRow } from '@ui/Table'; import useStyles from './styles'; @@ -33,6 +37,12 @@ const ObjectsTable = ({ const classes = useStyles(); const history = useHistory(); const dispatch = useDispatch(); + const initialContextState = { + mouseX: null, + mouseY: null, + }; + const [contextState, setContextState] = React.useState(initialContextState); + const wrapperRef = React.useRef(null); const [filtersDirection, setFiltersDirection] = useState({ name: 'desc', @@ -165,9 +175,13 @@ const ObjectsTable = ({ }; const handleRowRightClick = ({ row }) => (event) => { + console.log('right click!'); event.preventDefault(); - // eslint-disable-next-line no-console - console.log('TODO: show context menu'); + + setContextState({ + mouseX: event.clientX - 2, + mouseY: event.clientY - 4, + }); if (row.selected) { return; @@ -185,6 +199,9 @@ const ObjectsTable = ({ }); }; + const handleContextClose = () => { + setContextState(initialContextState); + }; const handleTableOutsideClick = (event) => { if (wrapperRef.current && !wrapperRef.current.contains(event.target)) { onOutsideClick(event.target); @@ -312,6 +329,26 @@ const ObjectsTable = ({ )} /> + + + + Copy + Print + Highlight + Email + + + {!loading && !sortedRows.length && } From 7f72ed51a28d554dd9a99173698c1dcc96c45367 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Wed, 25 Nov 2020 17:29:02 -0500 Subject: [PATCH 02/51] ContextMenu component --- src/UI/ContextMenu/context-menu.stories.js | 29 +++++++++++++++++-- src/UI/ContextMenu/index.js | 33 +++++++++++++++------- src/UI/ContextMenu/styles.js | 16 +++++++++++ 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/UI/ContextMenu/context-menu.stories.js b/src/UI/ContextMenu/context-menu.stories.js index bdbb7e76..4abe5802 100644 --- a/src/UI/ContextMenu/context-menu.stories.js +++ b/src/UI/ContextMenu/context-menu.stories.js @@ -1,8 +1,11 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; -import ContextMenu from './index'; +import ContextMenu, { CONTEXT_OPTION_IDS } from './index'; +import { faExpandArrowsAlt } from '@fortawesome/pro-regular-svg-icons/faExpandArrowsAlt'; +import { faShare } from '@fortawesome/pro-regular-svg-icons/faShare'; +import { faPencil } from '@fortawesome/pro-regular-svg-icons/faPencil'; +import { faTrash } from '@fortawesome/pro-regular-svg-icons/faTrash'; const categoryName = 'ContextMenu'; @@ -15,6 +18,28 @@ storiesOf(categoryName, module).add('default', () => { rename: 'Rename', trash: 'Trash', }, + items: [ + { + id: CONTEXT_OPTION_IDS.open, + displayText: 'Open', + icon: faExpandArrowsAlt, + }, + { + id: CONTEXT_OPTION_IDS.share, + displayText: 'Share', + icon: faShare, + }, + { + id: CONTEXT_OPTION_IDS.rename, + displayText: 'Rename', + icon: faPencil, + }, + { + id: CONTEXT_OPTION_IDS.trash, + displayText: 'Move to Trash', + icon: faTrash, + }, + ] }; return ( diff --git a/src/UI/ContextMenu/index.js b/src/UI/ContextMenu/index.js index b59295f1..54cede29 100644 --- a/src/UI/ContextMenu/index.js +++ b/src/UI/ContextMenu/index.js @@ -2,6 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import Paper from '@material-ui/core/Paper'; import MenuItem from '@material-ui/core/MenuItem'; +import Typography from '@material-ui/core/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + import useStyles from './styles'; export const CONTEXT_OPTION_IDS = { @@ -13,25 +16,28 @@ export const CONTEXT_OPTION_IDS = { const ContextMenu = ({ menuItemOnClick, - i18n, + items, }) => { const classes = useStyles(); - const items = [ - CONTEXT_OPTION_IDS.open, - CONTEXT_OPTION_IDS.share, - CONTEXT_OPTION_IDS.rename, - CONTEXT_OPTION_IDS.trash, - ]; - return ( {items.map((item) => ( menuItemOnClick(item)} + onClick={() => menuItemOnClick(item.id)} > - {i18n[item]} +
+ +
+ + {item.displayText} +
))}
@@ -46,6 +52,13 @@ ContextMenu.propTypes = { rename: PropTypes.string, trash: PropTypes.string, }).isRequired, + items: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + displayText: PropTypes.string, + icon: PropTypes.element, + }), + ).isRequired, }; export default ContextMenu; diff --git a/src/UI/ContextMenu/styles.js b/src/UI/ContextMenu/styles.js index e6f70e6e..a2bb7c65 100644 --- a/src/UI/ContextMenu/styles.js +++ b/src/UI/ContextMenu/styles.js @@ -10,6 +10,10 @@ export default makeStyles((theme) => ({ borderRadius: 6, }, menuItem: { + display: 'flex', + alignContent: 'center', + justifyContent: 'flex-start', + padding: '11px 0px 11px 15px', borderRight: getOuterBorder(theme), borderLeft: getOuterBorder(theme), borderBottom: getInnerBorder(theme), @@ -24,4 +28,16 @@ export default makeStyles((theme) => ({ borderBottomLeftRadius: 6, }, }, + iconContainer: { + width: 21, + display: 'flex', + alignContent: 'center', + }, + icon: { + fontSize: 11, + color: '#7F8185', + }, + displayText: { + fontSize: 14, + }, })); From df3b674baf62cfa43537b5828f7fe465633026ae Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 26 Nov 2020 10:22:23 -0500 Subject: [PATCH 03/51] add context menu --- src/UI/ContextMenu/context-menu.stories.js | 6 ---- .../components/ObjectsTable/ObjectsTable.js | 20 +++++++------ .../ObjectsTable/utils/get-context-menu.js | 30 +++++++++++++++++++ 3 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 src/shared/components/ObjectsTable/utils/get-context-menu.js diff --git a/src/UI/ContextMenu/context-menu.stories.js b/src/UI/ContextMenu/context-menu.stories.js index 4abe5802..75b812f0 100644 --- a/src/UI/ContextMenu/context-menu.stories.js +++ b/src/UI/ContextMenu/context-menu.stories.js @@ -12,12 +12,6 @@ const categoryName = 'ContextMenu'; storiesOf(categoryName, module).add('default', () => { const defaultProps = { menuItemOnClick: (id) => { console.log(id) }, - i18n: { - open: 'Open', - share: 'Share', - rename: 'Rename', - trash: 'Trash', - }, items: [ { id: CONTEXT_OPTION_IDS.open, diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index ca47edab..0c52056a 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -13,12 +13,12 @@ import Typography from '@material-ui/core/Typography'; import { openObject } from '@events'; import { UPDATE_OBJECTS } from '@reducers/storage'; import Dropzone from '@shared/components/Dropzone'; -import Paper from '@material-ui/core/Paper'; -import MenuItem from '@material-ui/core/MenuItem'; import Popper from '@material-ui/core/Popper'; import ClickAwayListener from '@material-ui/core/ClickAwayListener'; import Table, { TableCell, TableRow } from '@ui/Table'; +import ContextMenu from '@ui/ContextMenu'; +import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; const ObjectsTable = ({ @@ -175,7 +175,6 @@ const ObjectsTable = ({ }; const handleRowRightClick = ({ row }) => (event) => { - console.log('right click!'); event.preventDefault(); setContextState({ @@ -246,6 +245,11 @@ const ObjectsTable = ({ }); }; + const menuItemOnClick = (id) => { + console.log(id); + handleContextClose(); + }; + const contextMenuItems = getContextMenuItems(); return (
- - Copy - Print - Highlight - Email - +
diff --git a/src/shared/components/ObjectsTable/utils/get-context-menu.js b/src/shared/components/ObjectsTable/utils/get-context-menu.js new file mode 100644 index 00000000..9651006b --- /dev/null +++ b/src/shared/components/ObjectsTable/utils/get-context-menu.js @@ -0,0 +1,30 @@ +import { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; +import { faExpandArrowsAlt } from '@fortawesome/pro-regular-svg-icons/faExpandArrowsAlt'; +import { faShare } from '@fortawesome/pro-regular-svg-icons/faShare'; +// import { faPencil } from '@fortawesome/pro-regular-svg-icons/faPencil'; +// import { faTrash } from '@fortawesome/pro-regular-svg-icons/faTrash'; + +const mapContextMenuItems = () => ([ + { + id: CONTEXT_OPTION_IDS.open, + displayText: 'Open', + icon: faExpandArrowsAlt, + }, + { + id: CONTEXT_OPTION_IDS.share, + displayText: 'Share', + icon: faShare, + }, + // { + // id: CONTEXT_OPTION_IDS.rename, + // displayText: 'Rename', + // icon: faPencil, + // }, + // { + // id: CONTEXT_OPTION_IDS.trash, + // displayText: 'Move to Trash', + // icon: faTrash, + // }, +]); + +export default mapContextMenuItems; From abeabeda4986b70bc425df96e1e69c8bdad459b4 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 26 Nov 2020 10:56:02 -0500 Subject: [PATCH 04/51] added open --- src/UI/ContextMenu/index.js | 43 +++++++++++-------- .../components/ObjectsTable/ObjectsTable.js | 32 +++++++------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/UI/ContextMenu/index.js b/src/UI/ContextMenu/index.js index 54cede29..8c4d1080 100644 --- a/src/UI/ContextMenu/index.js +++ b/src/UI/ContextMenu/index.js @@ -4,6 +4,7 @@ import Paper from '@material-ui/core/Paper'; import MenuItem from '@material-ui/core/MenuItem'; import Typography from '@material-ui/core/Typography'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import ClickAwayListener from '@material-ui/core/ClickAwayListener'; import useStyles from './styles'; @@ -17,30 +18,33 @@ export const CONTEXT_OPTION_IDS = { const ContextMenu = ({ menuItemOnClick, items, + onClickAway, }) => { const classes = useStyles(); return ( - - {items.map((item) => ( - menuItemOnClick(item.id)} - > -
- -
- + + {items.map((item) => ( + menuItemOnClick(item.id)} > - {item.displayText} - -
- ))} -
+
+ +
+ + {item.displayText} + + + ))} + + ); }; @@ -59,6 +63,7 @@ ContextMenu.propTypes = { icon: PropTypes.element, }), ).isRequired, + onClickAway: PropTypes.func.isRequired, }; export default ContextMenu; diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 0c52056a..2ff5e2f0 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -14,9 +14,8 @@ import { openObject } from '@events'; import { UPDATE_OBJECTS } from '@reducers/storage'; import Dropzone from '@shared/components/Dropzone'; import Popper from '@material-ui/core/Popper'; -import ClickAwayListener from '@material-ui/core/ClickAwayListener'; import Table, { TableCell, TableRow } from '@ui/Table'; -import ContextMenu from '@ui/ContextMenu'; +import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; @@ -138,7 +137,9 @@ const ObjectsTable = ({ }; const handleDoubleRowClick = ({ row }) => (event) => { - event.preventDefault(); + if (event) { + event.preventDefault(); + } let newRows = []; if (row.type === 'folder') { @@ -182,10 +183,6 @@ const ObjectsTable = ({ mouseY: event.clientY - 4, }); - if (row.selected) { - return; - } - const newRows = sortedRows.map((_row) => ({ ..._row, pivote: _row.id === row.id, @@ -245,8 +242,14 @@ const ObjectsTable = ({ }); }; - const menuItemOnClick = (id) => { - console.log(id); + const menuItemOnClick = (optionId) => { + const clickedItem = sortedRows.find((row) => row.selected); + switch (optionId) { + case CONTEXT_OPTION_IDS.OPEN: + default: + handleDoubleRowClick({ row: clickedItem })(); + break; + } handleContextClose(); }; const contextMenuItems = getContextMenuItems(); @@ -342,14 +345,11 @@ const ObjectsTable = ({ left: contextState.mouseX, }} > - - - + menuItemOnClick={menuItemOnClick} + items={contextMenuItems} + /> {!loading && !sortedRows.length && } From 86a211f42f591123ac7ee2526a14407fc2b5cdea Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 26 Nov 2020 12:18:32 -0500 Subject: [PATCH 05/51] added share --- .../components/ObjectsTable/ObjectsTable.js | 14 ++++-- .../ObjectsTable/utils/get-context-menu.js | 44 +++++++++++-------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 2ff5e2f0..a6ea468b 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -16,6 +16,7 @@ import Dropzone from '@shared/components/Dropzone'; import Popper from '@material-ui/core/Popper'; import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; +import { openModal, SHARING_MODAL } from '@shared/components/Modal/actions'; import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; @@ -92,6 +93,7 @@ const ObjectsTable = ({ }; const sortedRows = sortAndAddSubfolders(unsortedRows); + const clickedItem = sortedRows.find((row) => row.selected); const handleRowClick = ({ rowIndex }) => (event) => { event.preventDefault(); @@ -243,16 +245,20 @@ const ObjectsTable = ({ }; const menuItemOnClick = (optionId) => { - const clickedItem = sortedRows.find((row) => row.selected); switch (optionId) { - case CONTEXT_OPTION_IDS.OPEN: - default: + case CONTEXT_OPTION_IDS.open: handleDoubleRowClick({ row: clickedItem })(); break; + case CONTEXT_OPTION_IDS.share: + default: + dispatch(openModal(SHARING_MODAL, { selectedObjects: [clickedItem] })); + break; } handleContextClose(); }; - const contextMenuItems = getContextMenuItems(); + + const contextMenuItems = getContextMenuItems(clickedItem); + return (
([ - { - id: CONTEXT_OPTION_IDS.open, - displayText: 'Open', - icon: faExpandArrowsAlt, - }, - { +const mapContextMenuItems = (clickedItem = {}) => { + const showShareOption = clickedItem.type === 'file' && clickedItem.isAvailableInSpace; + + const shareOption = { id: CONTEXT_OPTION_IDS.share, displayText: 'Share', icon: faShare, - }, - // { - // id: CONTEXT_OPTION_IDS.rename, - // displayText: 'Rename', - // icon: faPencil, - // }, - // { - // id: CONTEXT_OPTION_IDS.trash, - // displayText: 'Move to Trash', - // icon: faTrash, - // }, -]); + }; + + return ([ + { + id: CONTEXT_OPTION_IDS.open, + displayText: 'Open', + icon: faExpandArrowsAlt, + }, + ...(showShareOption ? [shareOption] : []), + // { + // id: CONTEXT_OPTION_IDS.rename, + // displayText: 'Rename', + // icon: faPencil, + // }, + // { + // id: CONTEXT_OPTION_IDS.trash, + // displayText: 'Move to Trash', + // icon: faTrash, + // }, + ]); +}; export default mapContextMenuItems; From 41356d11d7b8d87445b80c5cdbb29d7c8f8f243c Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 27 Nov 2020 12:05:09 -0500 Subject: [PATCH 06/51] added modal and success message --- package.json | 2 +- public/electron/events/objects.js | 19 +++ src/events/objects.js | 24 ++++ src/locales/en/translation.json | 8 ++ src/reducers/delete-object.js | 46 +++++++ src/reducers/index.js | 2 + .../components/Modal/DeleteObject/index.js | 117 ++++++++++++++++++ .../components/Modal/DeleteObject/styles.js | 47 +++++++ .../Modal/DeleteObjectSuccess/index.js | 60 +++++++++ .../Modal/DeleteObjectSuccess/styles.js | 26 ++++ src/shared/components/Modal/actions.js | 2 + src/shared/components/Modal/index.js | 6 + .../components/ObjectsTable/ObjectsTable.js | 5 +- .../ObjectsTable/utils/get-context-menu.js | 12 +- yarn.lock | 8 +- 15 files changed, 372 insertions(+), 12 deletions(-) create mode 100644 src/reducers/delete-object.js create mode 100644 src/shared/components/Modal/DeleteObject/index.js create mode 100644 src/shared/components/Modal/DeleteObject/styles.js create mode 100644 src/shared/components/Modal/DeleteObjectSuccess/index.js create mode 100644 src/shared/components/Modal/DeleteObjectSuccess/styles.js diff --git a/package.json b/package.json index c734edf8..baa3f2fe 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "build-storybook": "build-storybook -s public" }, "dependencies": { - "@fleekhq/space-client": "^1.1.5", + "@fleekhq/space-client": "^1.1.8", "@fortawesome/fontawesome-svg-core": "^1.2.28", "@fortawesome/free-brands-svg-icons": "^5.13.0", "@fortawesome/free-solid-svg-icons": "^5.13.0", diff --git a/public/electron/events/objects.js b/public/electron/events/objects.js index 346b35bc..78a819a3 100644 --- a/public/electron/events/objects.js +++ b/public/electron/events/objects.js @@ -20,6 +20,9 @@ const OPEN_PUBLIC_FILE_SUCCESS_EVENT = `${EVENT_PREFIX}:openPublicFile:success`; const SEARCH_EVENT = `${EVENT_PREFIX}:search`; const SEARCH_ERROR_EVENT = `${SEARCH_EVENT}:error`; const SEARCH_SUCCESS_EVENT = `${SEARCH_EVENT}:success`; +const DELETE_OBJECT_EVENT = `${EVENT_PREFIX}:deleteObject`; +const DELETE_OBJECT_ERROR_EVENT = `${EVENT_PREFIX}:deleteObject:error`; +const DELETE_OBJECT_SUCCESS_EVENT = `${EVENT_PREFIX}:deleteObject:success`; const DEFAULT_BUCKET = 'personal'; @@ -235,6 +238,22 @@ const registerObjectsEvents = (mainWindow) => { }); } }); + + ipcMain.on(DELETE_OBJECT_EVENT, async (event, payload) => { + try { + console.log(payload); + await spaceClient.removeDirOrFile({ + bucket: payload.bucket, + path: payload.path, + }); + console.log('success'); + mainWindow.webContents.send(DELETE_OBJECT_SUCCESS_EVENT); + } catch (err) { + mainWindow.webContents.send(DELETE_OBJECT_ERROR_EVENT, { + error: err.message, + }); + } + }); }; module.exports = { diff --git a/src/events/objects.js b/src/events/objects.js index 463257cb..949c5add 100644 --- a/src/events/objects.js +++ b/src/events/objects.js @@ -11,6 +11,7 @@ import { } from '@reducers/storage'; import { SEARCH_ACTION_TYPES } from '@reducers/search'; import { OPEN_PUBLIC_FILE_ACTION_TYPES } from '@reducers/open-public-file'; +import { DELETE_OBJECT_ACTION_TYPES } from '@reducers/delete-object'; import store from '../store'; @@ -31,6 +32,9 @@ const OPEN_PUBLIC_FILE_SUCCESS_EVENT = `${EVENT_PREFIX}:openPublicFile:success`; const SEARCH_EVENT = `${EVENT_PREFIX}:search`; const SEARCH_ERROR_EVENT = `${SEARCH_EVENT}:error`; const SEARCH_SUCCESS_EVENT = `${SEARCH_EVENT}:success`; +const DELETE_OBJECT_EVENT = `${EVENT_PREFIX}:deleteObject`; +const DELETE_OBJECT_ERROR_EVENT = `${EVENT_PREFIX}:deleteObject:error`; +const DELETE_OBJECT_SUCCESS_EVENT = `${EVENT_PREFIX}:deleteObject:success`; const registerObjectsEvents = () => { ipcRenderer.on(SUCCESS_EVENT, (event, payload) => { @@ -142,6 +146,19 @@ ipcRenderer.on(OPEN_ERROR_EVENT, (event, payload) => { }); }); +ipcRenderer.on(DELETE_OBJECT_SUCCESS_EVENT, () => { + store.dispatch({ + type: DELETE_OBJECT_ACTION_TYPES.ON_SUCCESS, + }); +}); + +ipcRenderer.on(DELETE_OBJECT_ERROR_EVENT, (event, payload) => { + store.dispatch({ + error: payload.error, + type: DELETE_OBJECT_ACTION_TYPES.ON_ERROR, + }); +}); + export const fetchSharedObjects = (seek = '', limit = 100) => { store.dispatch({ payload: { @@ -220,4 +237,11 @@ export const searchFiles = (searchTerm) => { } }; +export const deleteObject = (payload) => { + store.dispatch({ + type: DELETE_OBJECT_ACTION_TYPES.ON_SUBMIT, + }); + ipcRenderer.send(DELETE_OBJECT_EVENT, payload); +}; + export default registerObjectsEvents; diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index ab7cb157..d6b9845b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -29,6 +29,7 @@ "noResults": "No results", "comingSoon": "Coming Soon!", "goBack": "Go Back", + "delete": "Delete", "access": { "edit": { "title": "Can edit", @@ -452,6 +453,13 @@ "testKeysError": "Incorrect current password", "backupKeysError": "Failed to update password" }, + "deleteObject": { + "title": "Delete", + "description": "Confirm you want to delete \"{{filename}}\". This file will be gone forever.", + "error": "An error occurred. Please try again.", + "successFile": "File Deleted", + "successFolder": "Folder Deleted" + }, "createFolder": { "title": "Create New Folder", "inputLabel": "Folder Name" diff --git a/src/reducers/delete-object.js b/src/reducers/delete-object.js new file mode 100644 index 00000000..9395cfa2 --- /dev/null +++ b/src/reducers/delete-object.js @@ -0,0 +1,46 @@ +const DEFAULT_STATE = { + error: null, + success: false, + loading: false, +}; + +export const DELETE_OBJECT_ACTION_TYPES = { + ON_SUBMIT: 'DELETE_OBJECT_ON_SUBMIT', + ON_RESTART: 'DELETE_OBJECT_ON_RESTART', + ON_ERROR: 'DELETE_OBJECT_ON_ERROR', + ON_SUCCESS: 'DELETE_OBJECT_ON_SUCCESS', +}; + +export default (state = DEFAULT_STATE, action) => { + switch (action.type) { + case DELETE_OBJECT_ACTION_TYPES.ON_SUBMIT: { + return { + ...state, + error: null, + loading: true, + }; + } + case DELETE_OBJECT_ACTION_TYPES.ON_ERROR: { + return { + ...state, + loading: false, + error: action.error, + }; + } + case DELETE_OBJECT_ACTION_TYPES.ON_SUCCESS: { + return { + ...state, + loading: false, + success: true, + }; + } + case DELETE_OBJECT_ACTION_TYPES.ON_RESTART: { + return { + ...DEFAULT_STATE, + }; + } + default: { + return state; + } + } +}; diff --git a/src/reducers/index.js b/src/reducers/index.js index 99ab878d..ba26e4ec 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -17,6 +17,7 @@ import settingsReducer from './settings'; import openPublicFileReducer from './open-public-file'; import searchReducer from './search'; import linkedAddressesReducer from './linked-addresses'; +import deleteObjectReducer from './delete-object'; const rootReducer = combineReducers({ auth: authReducer, @@ -36,6 +37,7 @@ const rootReducer = combineReducers({ openPublicFile: openPublicFileReducer, search: searchReducer, linkedAddresses: linkedAddressesReducer, + deleteObject: deleteObjectReducer, }); /* eslint-disable no-param-reassign */ diff --git a/src/shared/components/Modal/DeleteObject/index.js b/src/shared/components/Modal/DeleteObject/index.js new file mode 100644 index 00000000..9888a6e1 --- /dev/null +++ b/src/shared/components/Modal/DeleteObject/index.js @@ -0,0 +1,117 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import Button from '@terminal-packages/space-ui/core/Button'; +import ButtonBase from '@material-ui/core/ButtonBase'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTimes } from '@fortawesome/pro-light-svg-icons/faTimes'; +import { faSpinner } from '@fortawesome/pro-regular-svg-icons/faSpinner'; +import BaseModal from '@ui/BaseModal'; +import Typography from '@ui/Typography'; +import { deleteObject } from '@events'; +import { openModal, DELETE_OBJECT_SUCCESS } from '@shared/components/Modal/actions'; + +import { DELETE_OBJECT_ACTION_TYPES } from '@reducers/delete-object'; +import useStyles from './styles'; + +const DeleteFile = ({ + item, + closeModal, +}) => { + const classes = useStyles(); + const { t } = useTranslation(); + const state = useSelector((s) => s.deleteObject); + const dispatch = useDispatch(); + + const onSubmitForm = (e) => { + e.preventDefault(); + deleteObject({ + bucket: item.bucket, + path: `/${item.key}`, + }); + }; + + React.useEffect(() => ( + () => { + dispatch({ + type: DELETE_OBJECT_ACTION_TYPES.ON_RESTART, + }); + } + ), []); + + React.useEffect(() => { + if (state.success) { + closeModal(); + dispatch(openModal(DELETE_OBJECT_SUCCESS, { isFile: item.isDir })); + } + }, [state.success]); + + return ( + +
+ + {t('modals.deleteObject.title')} + + + + +
+
+
+ + {t('modals.deleteObject.description', { + filename: item.name, + })} + + {state.error && ( + + {t('modals.deleteObject.description')} + + )} +
+ + +
+
+
+
+ ); +}; + +DeleteFile.propTypes = { + item: PropTypes.shape({ + name: PropTypes.string, + bucket: PropTypes.string, + key: PropTypes.string, + isDir: PropTypes.bool, + }).isRequired, + closeModal: PropTypes.func.isRequired, +}; + +export default DeleteFile; diff --git a/src/shared/components/Modal/DeleteObject/styles.js b/src/shared/components/Modal/DeleteObject/styles.js new file mode 100644 index 00000000..a4f5861e --- /dev/null +++ b/src/shared/components/Modal/DeleteObject/styles.js @@ -0,0 +1,47 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + root: { + padding: '15px 20px 20px 18px', + maxWidth: 321, + }, + header: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + }, + textField: { + marginTop: 15, + }, + buttonContainer: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + marginTop: 16, + '& > button': { + width: 84, + }, + '& > *:not(:last-child)': { + marginRight: 10, + }, + }, + errorMessage: { + marginTop: 5, + color: theme.palette.palette.red, + }, + icon: { + fontSize: 12, + color: theme.palette.palette.gray1, + }, + title: { + fontSize: 16, + fontWeight: 600, + }, + description: { + marginTop: 8, + marginBottom: 14, + }, + button: { + height: 34, + }, +})); diff --git a/src/shared/components/Modal/DeleteObjectSuccess/index.js b/src/shared/components/Modal/DeleteObjectSuccess/index.js new file mode 100644 index 00000000..4e98ab54 --- /dev/null +++ b/src/shared/components/Modal/DeleteObjectSuccess/index.js @@ -0,0 +1,60 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import Grow from '@material-ui/core/Grow'; +import { faCheck } from '@fortawesome/pro-regular-svg-icons/faCheck'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import Typography from '@material-ui/core/Typography'; + +import useStyles from './styles'; + +const DELAYED_CLOSE_DELAY = 3000; +const TRANSITION_TIMEOUT = 300; + +const DeleteObjectSuccess = ({ closeModal, isFile }) => { + const classes = useStyles(); + const { t } = useTranslation(); + const [timeoutIdAnimation, setTimeoutIdAnimation] = useState(null); + const [timeoutIdDelayedClose, setTimeoutIdDelayedClose] = useState(null); + const modalCloseAnimation = () => { + setTimeoutIdAnimation( + setTimeout(closeModal, TRANSITION_TIMEOUT), + ); + }; + + useEffect(() => { + if (!timeoutIdDelayedClose) { + setTimeoutIdDelayedClose( + setTimeout(modalCloseAnimation, DELAYED_CLOSE_DELAY), + ); + } else { + clearTimeout(timeoutIdAnimation); + clearTimeout(timeoutIdDelayedClose); + } + }, []); + + return ( + +
+ + + {isFile ? ( + t('modals.deleteObject.successFile') + ) : ( + t('modals.deleteObject.successFolder') + )} + +
+
+ ); +}; + +DeleteObjectSuccess.propTypes = { + closeModal: PropTypes.func.isRequired, + isFile: PropTypes.bool.isRequired, +}; + +export default DeleteObjectSuccess; diff --git a/src/shared/components/Modal/DeleteObjectSuccess/styles.js b/src/shared/components/Modal/DeleteObjectSuccess/styles.js new file mode 100644 index 00000000..331fc00a --- /dev/null +++ b/src/shared/components/Modal/DeleteObjectSuccess/styles.js @@ -0,0 +1,26 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + root: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + padding: '10px 13px 10px 10px', + backgroundColor: theme.palette.palette.black, + borderRadius: 4, + position: 'absolute', + left: '50%', + transform: 'translateX(-50%)', + bottom: 12, + zIndex: 10, + }, + iconCheck: { + color: theme.palette.palette.green2, + fontSize: 13, + marginRight: 7, + }, + text: { + color: theme.palette.palette.white, + fontSize: 14, + }, +})); diff --git a/src/shared/components/Modal/actions.js b/src/shared/components/Modal/actions.js index 3bb7da5a..2ba66938 100644 --- a/src/shared/components/Modal/actions.js +++ b/src/shared/components/Modal/actions.js @@ -18,6 +18,8 @@ export const LICENSE_REGISTRATION = 'LICENSE_REGISTRATION'; export const FILE_LINK_PASSWORD = 'FILE_LINK_PASSWORD'; export const ADD_BACK_UP_SIGN_IN = 'ADD_BACK_UP_SIGN_IN'; export const CREATE_USERNAME_PASSWORD = 'CREATE_USERNAME_PASSWORD'; +export const DELETE_OBJECT = 'DELETE_OBJECT'; +export const DELETE_OBJECT_SUCCESS = 'DELETE_OBJECT_SUCCESS'; /* Action creators */ export const openModal = (modalType, props = {}) => (dispatch) => { diff --git a/src/shared/components/Modal/index.js b/src/shared/components/Modal/index.js index a4cf65dd..d03b35aa 100644 --- a/src/shared/components/Modal/index.js +++ b/src/shared/components/Modal/index.js @@ -14,6 +14,8 @@ import LicenseRegistration from './LicenseRegistration'; import FileLinkPassword from './FileLinkPassword'; import AddBackUpSignIn from './AddBackupSignIn'; import CreateUsernamePassword from './CreateUsernamePassword'; +import DeleteObject from './DeleteObject'; +import DeleteObjectSuccess from './DeleteObjectSuccess'; import useStyles from './styles'; import { @@ -31,6 +33,8 @@ import { ADD_BACK_UP_SIGN_IN, FILE_LINK_PASSWORD, CREATE_USERNAME_PASSWORD, + DELETE_OBJECT, + DELETE_OBJECT_SUCCESS, } from './actions'; const MODALS = { @@ -47,6 +51,8 @@ const MODALS = { [FILE_LINK_PASSWORD]: FileLinkPassword, [ADD_BACK_UP_SIGN_IN]: AddBackUpSignIn, [CREATE_USERNAME_PASSWORD]: CreateUsernamePassword, + [DELETE_OBJECT]: DeleteObject, + [DELETE_OBJECT_SUCCESS]: DeleteObjectSuccess, }; const getModalsComponents = (modals, dispatch) => modals.map(({ id, type, props }) => { diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index a6ea468b..ab5588e4 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -16,7 +16,7 @@ import Dropzone from '@shared/components/Dropzone'; import Popper from '@material-ui/core/Popper'; import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; -import { openModal, SHARING_MODAL } from '@shared/components/Modal/actions'; +import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Modal/actions'; import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; @@ -249,6 +249,9 @@ const ObjectsTable = ({ case CONTEXT_OPTION_IDS.open: handleDoubleRowClick({ row: clickedItem })(); break; + case CONTEXT_OPTION_IDS.trash: + dispatch(openModal(DELETE_OBJECT, { item: clickedItem })); + break; case CONTEXT_OPTION_IDS.share: default: dispatch(openModal(SHARING_MODAL, { selectedObjects: [clickedItem] })); diff --git a/src/shared/components/ObjectsTable/utils/get-context-menu.js b/src/shared/components/ObjectsTable/utils/get-context-menu.js index fb25fb9b..5a4e274b 100644 --- a/src/shared/components/ObjectsTable/utils/get-context-menu.js +++ b/src/shared/components/ObjectsTable/utils/get-context-menu.js @@ -2,7 +2,7 @@ import { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import { faExpandArrowsAlt } from '@fortawesome/pro-regular-svg-icons/faExpandArrowsAlt'; import { faShare } from '@fortawesome/pro-regular-svg-icons/faShare'; // import { faPencil } from '@fortawesome/pro-regular-svg-icons/faPencil'; -// import { faTrash } from '@fortawesome/pro-regular-svg-icons/faTrash'; +import { faTrash } from '@fortawesome/pro-regular-svg-icons/faTrash'; const mapContextMenuItems = (clickedItem = {}) => { const showShareOption = clickedItem.type === 'file' && clickedItem.isAvailableInSpace; @@ -25,11 +25,11 @@ const mapContextMenuItems = (clickedItem = {}) => { // displayText: 'Rename', // icon: faPencil, // }, - // { - // id: CONTEXT_OPTION_IDS.trash, - // displayText: 'Move to Trash', - // icon: faTrash, - // }, + { + id: CONTEXT_OPTION_IDS.trash, + displayText: 'Move to Trash', + icon: faTrash, + }, ]); }; diff --git a/yarn.lock b/yarn.lock index dffeb267..db685be8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1692,10 +1692,10 @@ "@ethersproject/properties" "^5.0.3" "@ethersproject/strings" "^5.0.4" -"@fleekhq/space-client@^1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@fleekhq/space-client/-/space-client-1.1.5.tgz#ed79f280f1d1cb1f9965289d25907c6a71c2cdf0" - integrity sha512-dkJseEFRCyELhdccdZwoTFQZPFCixOgRtGLWybb0fPKstQYKXU/2he5FduKVaur6G+rxXW6pNgwAqTo43wz8zA== +"@fleekhq/space-client@^1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@fleekhq/space-client/-/space-client-1.1.8.tgz#9e2e69703008df1eaed0d4931bdf462e986df670" + integrity sha512-to7UW9naEfYIlIqoT2dQ96grWm3zzYFK5r9yHJUg65B+kjpd9PpSLMyCDdzSdT7OrVP4hcy0nHtJbG2jeBqpxQ== dependencies: "@types/google-protobuf" "^3.7.2" google-protobuf "^3.12.2" From eed73ab20f04f4b63ae6123fbcdcc260e5871269 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 27 Nov 2020 12:40:57 -0500 Subject: [PATCH 07/51] delete itnegration --- src/reducers/storage/bucket.js | 10 ++++++++++ src/reducers/storage/index.js | 2 ++ src/shared/components/Modal/DeleteObject/index.js | 13 +++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/reducers/storage/bucket.js b/src/reducers/storage/bucket.js index 728911c8..1d3c8bf9 100644 --- a/src/reducers/storage/bucket.js +++ b/src/reducers/storage/bucket.js @@ -6,6 +6,7 @@ export const STORE_DIR = 'STORE_DIR'; export const ADD_OBJECT = 'ADD_OBJECT'; export const STORE_OBJECTS = 'STORE_OBJECTS'; export const DELETE_OBJECT = 'DELETE_OBJECT'; +export const DELETE_OBJECT_AND_CHILDREN = 'DELETE_OBJECT_AND_CHILDREN'; export const UPDATE_OBJECTS = 'UPDATE_OBJECTS'; export const STORE_BUCKETS = 'STORE_BUCKETS'; export const UPDATE_OR_ADD_OBJECT = 'UPDATE_OR_ADD_OBJECT'; @@ -99,6 +100,15 @@ export default (state = DEFAULT_STATE, action) => { }; } + case DELETE_OBJECT_AND_CHILDREN: { + return { + ...state, + objects: state.objects.filter( + (obj) => !obj.fullKey.startsWith(action.payload.fullKey), + ), + }; + } + case UPDATE_OR_ADD_OBJECT: { let objects = []; const objectIndex = state.objects.findIndex((obj) => obj.fullKey === action.payload.fullKey); diff --git a/src/reducers/storage/index.js b/src/reducers/storage/index.js index 125ed69b..0fb984f7 100644 --- a/src/reducers/storage/index.js +++ b/src/reducers/storage/index.js @@ -5,6 +5,7 @@ import bucketReducer, { ADD_OBJECT, STORE_OBJECTS, DELETE_OBJECT, + DELETE_OBJECT_AND_CHILDREN, UPDATE_OBJECTS, STORE_BUCKETS, SET_LOADING_STATE_BUCKET, @@ -158,6 +159,7 @@ export default (state = DEFAULT_STATE, action) => { case STORE_DIR: case ADD_OBJECT: case DELETE_OBJECT: + case DELETE_OBJECT_AND_CHILDREN: case UPDATE_OBJECTS: case UPDATE_OR_ADD_OBJECT: case UPDATE_SHARE_AMOUNT_OBJECTS: diff --git a/src/shared/components/Modal/DeleteObject/index.js b/src/shared/components/Modal/DeleteObject/index.js index 9888a6e1..984869c9 100644 --- a/src/shared/components/Modal/DeleteObject/index.js +++ b/src/shared/components/Modal/DeleteObject/index.js @@ -11,6 +11,7 @@ import BaseModal from '@ui/BaseModal'; import Typography from '@ui/Typography'; import { deleteObject } from '@events'; import { openModal, DELETE_OBJECT_SUCCESS } from '@shared/components/Modal/actions'; +import { DELETE_OBJECT_AND_CHILDREN } from '@reducers/storage/bucket'; import { DELETE_OBJECT_ACTION_TYPES } from '@reducers/delete-object'; import useStyles from './styles'; @@ -42,8 +43,15 @@ const DeleteFile = ({ React.useEffect(() => { if (state.success) { + dispatch(openModal(DELETE_OBJECT_SUCCESS, { isFile: item.type === 'file' })); + dispatch({ + type: DELETE_OBJECT_AND_CHILDREN, + payload: { + fullKey: item.fullKey, + bucket: item.bucket, + }, + }); closeModal(); - dispatch(openModal(DELETE_OBJECT_SUCCESS, { isFile: item.isDir })); } }, [state.success]); @@ -109,7 +117,8 @@ DeleteFile.propTypes = { name: PropTypes.string, bucket: PropTypes.string, key: PropTypes.string, - isDir: PropTypes.bool, + type: PropTypes.string, + fullKey: PropTypes.string, }).isRequired, closeModal: PropTypes.func.isRequired, }; From 881a61324aa98ab8387362cef6b8ea08c2138da0 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 27 Nov 2020 12:44:05 -0500 Subject: [PATCH 08/51] payload cleanup --- public/electron/events/objects.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/electron/events/objects.js b/public/electron/events/objects.js index 78a819a3..e01ba004 100644 --- a/public/electron/events/objects.js +++ b/public/electron/events/objects.js @@ -241,12 +241,10 @@ const registerObjectsEvents = (mainWindow) => { ipcMain.on(DELETE_OBJECT_EVENT, async (event, payload) => { try { - console.log(payload); await spaceClient.removeDirOrFile({ bucket: payload.bucket, path: payload.path, }); - console.log('success'); mainWindow.webContents.send(DELETE_OBJECT_SUCCESS_EVENT); } catch (err) { mainWindow.webContents.send(DELETE_OBJECT_ERROR_EVENT, { From 07bada77a8d3a861cff2dfc57f6ee8e8f03f06a4 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 10:27:55 -0500 Subject: [PATCH 09/51] change move to trash to delete --- src/locales/en/translation.json | 5 +++++ src/shared/components/ObjectsTable/ObjectsTable.js | 4 +++- .../components/ObjectsTable/utils/get-context-menu.js | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index d6b9845b..64049b4b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -516,5 +516,10 @@ "cancel": "Cancel", "continue": "Continue", "torusError": "Something went wrong, please try again later." + }, + "tableMenu": { + "open": "Open", + "share": "Share", + "delete": "Delete" } } diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index ab5588e4..9dacfe75 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -17,6 +17,7 @@ import Popper from '@material-ui/core/Popper'; import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Modal/actions'; +import { useTranslation } from 'react-i18next'; import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; @@ -34,6 +35,7 @@ const ObjectsTable = ({ EmptyState, fetchDir, }) => { + const { t } = useTranslation(); const classes = useStyles(); const history = useHistory(); const dispatch = useDispatch(); @@ -260,7 +262,7 @@ const ObjectsTable = ({ handleContextClose(); }; - const contextMenuItems = getContextMenuItems(clickedItem); + const contextMenuItems = getContextMenuItems(clickedItem, t); return (
diff --git a/src/shared/components/ObjectsTable/utils/get-context-menu.js b/src/shared/components/ObjectsTable/utils/get-context-menu.js index 5a4e274b..8413338f 100644 --- a/src/shared/components/ObjectsTable/utils/get-context-menu.js +++ b/src/shared/components/ObjectsTable/utils/get-context-menu.js @@ -4,19 +4,19 @@ import { faShare } from '@fortawesome/pro-regular-svg-icons/faShare'; // import { faPencil } from '@fortawesome/pro-regular-svg-icons/faPencil'; import { faTrash } from '@fortawesome/pro-regular-svg-icons/faTrash'; -const mapContextMenuItems = (clickedItem = {}) => { +const mapContextMenuItems = (clickedItem = {}, t) => { const showShareOption = clickedItem.type === 'file' && clickedItem.isAvailableInSpace; const shareOption = { id: CONTEXT_OPTION_IDS.share, - displayText: 'Share', + displayText: t('tableMenu.share'), icon: faShare, }; return ([ { id: CONTEXT_OPTION_IDS.open, - displayText: 'Open', + displayText: t('tableMenu.open'), icon: faExpandArrowsAlt, }, ...(showShareOption ? [shareOption] : []), @@ -27,7 +27,7 @@ const mapContextMenuItems = (clickedItem = {}) => { // }, { id: CONTEXT_OPTION_IDS.trash, - displayText: 'Move to Trash', + displayText: t('tableMenu.delete'), icon: faTrash, }, ]); From 09bf2aaa5ecbd8df3427f76d3e2e5f66427dc6d1 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 14:36:07 -0500 Subject: [PATCH 10/51] added hover, selected, error states --- .../components/ObjectsTable/ObjectsTable.js | 2 ++ src/shared/components/ObjectsTable/styles.js | 11 ++++++++++- src/views/Storage/shared/RenderRow.js | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 9dacfe75..8324f72c 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -321,6 +321,7 @@ const ObjectsTable = ({ key={row.id} className={classNames(classes.row, { [classes.selected]: row.selected, + [classes.error]: row.error, })} onClick={handleRowClick({ row, rowIndex })} onContextMenu={handleRowRightClick({ row })} @@ -329,6 +330,7 @@ const ObjectsTable = ({ arrowOnClick(row)} + classes={classes} /> {withRowOptions && ( diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index b53b9541..49caa646 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -9,6 +9,9 @@ export default makeStyles((theme) => ({ }, row: { cursor: 'pointer', + '&&&:hover': { + backgroundColor: '#F5F6F8', + }, }, headerCell: { paddingTop: 6, @@ -21,7 +24,10 @@ export default makeStyles((theme) => ({ padding: '0 5px', }, selected: { - backgroundColor: `${theme.palette.palette.white} !important`, + backgroundColor: '#E5F0FF !important', + }, + error: { + backgroundColor: '#F8DEDF !important', }, tableWrapper: { flexGrow: 1, @@ -44,4 +50,7 @@ export default makeStyles((theme) => ({ sortButton: { padding: 2, }, + highlighted: { + color: theme.palette.palette.spaceBlue, + }, })); diff --git a/src/views/Storage/shared/RenderRow.js b/src/views/Storage/shared/RenderRow.js index bb641f00..af4a9c39 100644 --- a/src/views/Storage/shared/RenderRow.js +++ b/src/views/Storage/shared/RenderRow.js @@ -8,8 +8,9 @@ import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; import { TableCell, FileCell, IconsCell } from '@ui/Table'; import { openModal, LICENSE_REGISTRATION } from '@shared/components/Modal/actions'; +import classnames from 'classnames'; -const RenderRow = ({ row, arrowOnClick }) => { +const RenderRow = ({ row, arrowOnClick, classes }) => { const { t } = useTranslation(); const dispatch = useDispatch(); const location = useLocation(); @@ -41,7 +42,13 @@ const RenderRow = ({ row, arrowOnClick }) => { expanded={row.expanded} tabulations={getTabulationAmount()} > - + {row.name} @@ -89,8 +96,12 @@ RenderRow.propTypes = { isLocallyAvailable: PropTypes.bool, isAvailableInSpace: PropTypes.bool, expanded: PropTypes.bool, + selected: PropTypes.bool, }).isRequired, arrowOnClick: PropTypes.func, + classes: PropTypes.shape({ + highlighted: PropTypes.string, + }).isRequired, }; export default RenderRow; From 2c2bc2cae47fecd65f704f0884ae04504844a61b Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 14:39:20 -0500 Subject: [PATCH 11/51] remove hour, mins, secs --- src/views/Storage/shared/RenderRow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Storage/shared/RenderRow.js b/src/views/Storage/shared/RenderRow.js index af4a9c39..28679d6a 100644 --- a/src/views/Storage/shared/RenderRow.js +++ b/src/views/Storage/shared/RenderRow.js @@ -59,7 +59,7 @@ const RenderRow = ({ row, arrowOnClick, classes }) => { - {moment(row.lastModified).format('MMM D, YYYY hh:mm:ss A z')} + {moment(row.lastModified).format('MMM D, YYYY')} {/* ^ just for testing, after POC should be used line below */} {/* {formatMonthDayYear(row.lastModified)} */} From 4967b258ede109eeb9512cd0a62dfd0ccdb06bfd Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 15:32:07 -0500 Subject: [PATCH 12/51] added loading --- .../{RenderRow.js => RenderRow/index.js} | 39 ++++++++++++++++--- src/views/Storage/shared/RenderRow/styles.js | 23 +++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) rename src/views/Storage/shared/{RenderRow.js => RenderRow/index.js} (76%) create mode 100644 src/views/Storage/shared/RenderRow/styles.js diff --git a/src/views/Storage/shared/RenderRow.js b/src/views/Storage/shared/RenderRow/index.js similarity index 76% rename from src/views/Storage/shared/RenderRow.js rename to src/views/Storage/shared/RenderRow/index.js index 28679d6a..dfb8b927 100644 --- a/src/views/Storage/shared/RenderRow.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -9,11 +9,16 @@ import Typography from '@material-ui/core/Typography'; import { TableCell, FileCell, IconsCell } from '@ui/Table'; import { openModal, LICENSE_REGISTRATION } from '@shared/components/Modal/actions'; import classnames from 'classnames'; +import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSpinner } from '@fortawesome/pro-regular-svg-icons/faSpinner'; +import useStyles from './styles'; -const RenderRow = ({ row, arrowOnClick, classes }) => { +const RenderRow = ({ row, arrowOnClick }) => { const { t } = useTranslation(); const dispatch = useDispatch(); const location = useLocation(); + const classes = useStyles(); const shareAmount = row.shareAmount - 1; const iconsCellI18n = { @@ -33,6 +38,30 @@ const RenderRow = ({ row, arrowOnClick, classes }) => { return tabulations; }; + const getSizeIcon = () => { + if (row.isAvailableInSpace) { + return ( +
+ +
+ ); + } + return ( +
+ +
+ ); + }; + return ( <> { {row.name} - + + {getSizeIcon()} {formatBytes(row.size)} @@ -99,9 +131,6 @@ RenderRow.propTypes = { selected: PropTypes.bool, }).isRequired, arrowOnClick: PropTypes.func, - classes: PropTypes.shape({ - highlighted: PropTypes.string, - }).isRequired, }; export default RenderRow; diff --git a/src/views/Storage/shared/RenderRow/styles.js b/src/views/Storage/shared/RenderRow/styles.js new file mode 100644 index 00000000..e72eca3e --- /dev/null +++ b/src/views/Storage/shared/RenderRow/styles.js @@ -0,0 +1,23 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + iconSizeContainer: { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + }, + iconContainer: { + width: 25, + }, + checkIcon: { + fontSize: 11, + color: theme.palette.palette.green2, + }, + notAvailableLocally: { + color: '#7F8185', + }, + loadingIcon: { + fontSize: 16, + color: theme.palette.palette.spaceBlue, + }, +})); From 7446b2c9fefb19717ad196d6d07d0171bc96fac9 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 15:39:52 -0500 Subject: [PATCH 13/51] error state --- package.json | 1 + src/views/Storage/shared/RenderRow/index.js | 4 ++-- src/views/Storage/shared/RenderRow/styles.js | 2 +- yarn.lock | 7 +++++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index baa3f2fe..99bdac23 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.28", "@fortawesome/free-brands-svg-icons": "^5.13.0", "@fortawesome/free-solid-svg-icons": "^5.13.0", + "@fortawesome/pro-duotone-svg-icons": "^5.15.1", "@fortawesome/pro-light-svg-icons": "^5.13.0", "@fortawesome/pro-regular-svg-icons": "^5.13.0", "@fortawesome/pro-solid-svg-icons": "^5.13.0", diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index dfb8b927..719593d4 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -10,8 +10,8 @@ import { TableCell, FileCell, IconsCell } from '@ui/Table'; import { openModal, LICENSE_REGISTRATION } from '@shared/components/Modal/actions'; import classnames from 'classnames'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; +import { faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons/faSpinnerThird'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faSpinner } from '@fortawesome/pro-regular-svg-icons/faSpinner'; import useStyles from './styles'; const RenderRow = ({ row, arrowOnClick }) => { @@ -55,7 +55,7 @@ const RenderRow = ({ row, arrowOnClick }) => {
diff --git a/src/views/Storage/shared/RenderRow/styles.js b/src/views/Storage/shared/RenderRow/styles.js index e72eca3e..9be0a3f7 100644 --- a/src/views/Storage/shared/RenderRow/styles.js +++ b/src/views/Storage/shared/RenderRow/styles.js @@ -17,7 +17,7 @@ export default makeStyles((theme) => ({ color: '#7F8185', }, loadingIcon: { - fontSize: 16, + fontSize: 11, color: theme.palette.palette.spaceBlue, }, })); diff --git a/yarn.lock b/yarn.lock index db685be8..53ebff3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1727,6 +1727,13 @@ dependencies: "@fortawesome/fontawesome-common-types" "^0.2.32" +"@fortawesome/pro-duotone-svg-icons@^5.15.1": + version "5.15.1" + resolved "https://npm.fontawesome.com/@fortawesome/pro-duotone-svg-icons/-/5.15.1/pro-duotone-svg-icons-5.15.1.tgz#1493535aaf89b1fcd8f85e22991da986e520b236" + integrity sha512-FgpjgPpitmg9GKfA0JIjmxdzcrT2eS6qbVDGXlWvy41R8TmD9SHalTsVKjodT1m1EQ55UYaLY3bTZTAmtq5nzA== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.32" + "@fortawesome/pro-light-svg-icons@^5.13.0": version "5.15.1" resolved "https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/5.15.1/pro-light-svg-icons-5.15.1.tgz#bbe0cff115f271419327dd8d77e2fcb7634004ad" From 8a17efb3a621d4c37188c2a6c2459a2192a7ca56 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 15:43:26 -0500 Subject: [PATCH 14/51] cleab up --- src/shared/components/ObjectsTable/ObjectsTable.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 8324f72c..35af1d4d 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -330,7 +330,6 @@ const ObjectsTable = ({ arrowOnClick(row)} - classes={classes} /> {withRowOptions && ( From 98c92083ce2669d4357312db555176c6c06c2fb4 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 30 Nov 2020 15:48:40 -0500 Subject: [PATCH 15/51] fix highlight --- src/shared/components/ObjectsTable/styles.js | 5 +---- src/views/Storage/shared/RenderRow/styles.js | 3 +++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index 49caa646..59cec7f3 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -1,6 +1,6 @@ import { makeStyles } from '@material-ui/core/styles'; -export default makeStyles((theme) => ({ +export default makeStyles(() => ({ root: { position: 'relative', // to keep table above the rainbow field userSelect: 'none', @@ -50,7 +50,4 @@ export default makeStyles((theme) => ({ sortButton: { padding: 2, }, - highlighted: { - color: theme.palette.palette.spaceBlue, - }, })); diff --git a/src/views/Storage/shared/RenderRow/styles.js b/src/views/Storage/shared/RenderRow/styles.js index 9be0a3f7..3c6ec009 100644 --- a/src/views/Storage/shared/RenderRow/styles.js +++ b/src/views/Storage/shared/RenderRow/styles.js @@ -20,4 +20,7 @@ export default makeStyles((theme) => ({ fontSize: 11, color: theme.palette.palette.spaceBlue, }, + highlighted: { + color: theme.palette.palette.spaceBlue, + }, })); From 2e0d5e569d9cba9360d16a0fbf5cef62f5c79652 Mon Sep 17 00:00:00 2001 From: Mateusz Walendzik Date: Tue, 1 Dec 2020 16:13:41 +0100 Subject: [PATCH 16/51] add FileNameCell shared component (#376) * add FileNameCell shared component * show shared icon only when it's not a folder --- .../components/FileNameCell/FileNameCell.js | 126 ++++++++++++++++++ .../components/FileNameCell/PeopleIcon.js | 32 +++++ .../FileNameCell/file-name-cell.stories.js | 32 +++++ src/UI/Table/components/FileNameCell/index.js | 1 + .../Table/components/FileNameCell/styles.js | 68 ++++++++++ 5 files changed, 259 insertions(+) create mode 100644 src/UI/Table/components/FileNameCell/FileNameCell.js create mode 100644 src/UI/Table/components/FileNameCell/PeopleIcon.js create mode 100644 src/UI/Table/components/FileNameCell/file-name-cell.stories.js create mode 100644 src/UI/Table/components/FileNameCell/index.js create mode 100644 src/UI/Table/components/FileNameCell/styles.js diff --git a/src/UI/Table/components/FileNameCell/FileNameCell.js b/src/UI/Table/components/FileNameCell/FileNameCell.js new file mode 100644 index 00000000..dca99b27 --- /dev/null +++ b/src/UI/Table/components/FileNameCell/FileNameCell.js @@ -0,0 +1,126 @@ +import React, { useLayoutEffect, useRef, useState } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import Typography from '@material-ui/core/Typography'; +import Tooltip from '@material-ui/core/Tooltip'; +import ButtonBase from '@material-ui/core/ButtonBase'; +import FileIcon from '@terminal-packages/space-ui/core/FileIcon'; +import { faChevronDown } from '@fortawesome/pro-light-svg-icons/faChevronDown'; +import { faChevronRight } from '@fortawesome/pro-light-svg-icons/faChevronRight'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import PeopleIcon from './PeopleIcon'; +import useStyles from './styles'; +import TableCell from '../TableCell'; + +const FileNameCell = (props) => { + const { + ext, + src, + name, + expanded, + isShared, + selected, + tabulations, + arrowOnClick, + ...tableCellProps + } = props; + + const classes = useStyles({ tabulations }); + const textNode = useRef(null); + const [isTooltip, setIsTooltip] = useState(false); + const isFolder = ext === 'folder'; + + useLayoutEffect(() => { + if (textNode.current) { + setIsTooltip(textNode.current.scrollWidth > textNode.current.clientWidth); + } + }, [isShared, name, tabulations]); + + const nameComponent = ( + + {name} + + ); + + return ( + // eslint-disable-next-line react/jsx-props-no-spreading + +
+
+
+ {isFolder && ( + { + e.stopPropagation(); + arrowOnClick(); + }} + onDoubleClick={(e) => e.stopPropagation()} + > + + + )} +
+
+ + {isFolder && isShared && } +
+ {isTooltip ? ( + {name}} + > + {nameComponent} + + ) : nameComponent} + + {(isShared && !isFolder) && } +
+ + ); +}; + +FileNameCell.defaultProps = { + name: '', + src: null, + ext: 'default', + selected: PropTypes.bool, + expanded: false, + tabulations: 0, + isShared: false, + arrowOnClick: () => {}, +}; + +FileNameCell.propTypes = { + name: PropTypes.string, + ext: PropTypes.string, + selected: PropTypes.bool, + src: PropTypes.string, + expanded: PropTypes.bool, + tabulations: PropTypes.number, + isShared: PropTypes.bool, + arrowOnClick: PropTypes.func, +}; + +export default FileNameCell; diff --git a/src/UI/Table/components/FileNameCell/PeopleIcon.js b/src/UI/Table/components/FileNameCell/PeopleIcon.js new file mode 100644 index 00000000..088b17d3 --- /dev/null +++ b/src/UI/Table/components/FileNameCell/PeopleIcon.js @@ -0,0 +1,32 @@ +/* eslint-disable max-len */ +import React from 'react'; +import PropTypes from 'prop-types'; + +const PeopleIcon = ({ color, className }) => ( + + + +); + +PeopleIcon.defaultProps = { + color: undefined, + className: undefined, +}; + +PeopleIcon.propTypes = { + color: PropTypes.string, + className: PropTypes.string, +}; + +export default PeopleIcon; diff --git a/src/UI/Table/components/FileNameCell/file-name-cell.stories.js b/src/UI/Table/components/FileNameCell/file-name-cell.stories.js new file mode 100644 index 00000000..7228387b --- /dev/null +++ b/src/UI/Table/components/FileNameCell/file-name-cell.stories.js @@ -0,0 +1,32 @@ +import React from 'react'; +import Table from '@material-ui/core/Table'; +import { storiesOf } from '@storybook/react'; +import { boolean, text } from '@storybook/addon-knobs'; +import TableBody from '@material-ui/core/TableBody'; +import TableHead from '@material-ui/core/TableHead'; + +import FileCell from './index'; +import TableRow from '../TableRow'; +import TableCell from '../TableCell'; + +const categoryName = 'ElementalComponents/Table'; + +storiesOf(categoryName, module).add('FileNameCell', () => { + const defaultProps = { + ext: text('ext', 'docx'), + src: text('src', 'https://education.district0x.io/wp-content/uploads/IPFS-Large.jpg'), + isShared: boolean('isShared', false), + name: text('name', 'TechDocsV2.docx'), + selected: boolean('selected', false), + }; + + return ( + + + + + + +
+ ); +}); diff --git a/src/UI/Table/components/FileNameCell/index.js b/src/UI/Table/components/FileNameCell/index.js new file mode 100644 index 00000000..6d3db412 --- /dev/null +++ b/src/UI/Table/components/FileNameCell/index.js @@ -0,0 +1 @@ +export { default } from './FileNameCell'; diff --git a/src/UI/Table/components/FileNameCell/styles.js b/src/UI/Table/components/FileNameCell/styles.js new file mode 100644 index 00000000..f0d75e82 --- /dev/null +++ b/src/UI/Table/components/FileNameCell/styles.js @@ -0,0 +1,68 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + container: { + display: 'flex', + alignItems: 'center', + }, + iconContainer: { + position: 'relative', + width: 22, + height: 22, + marginRight: 8, + borderRadius: 3, + overflow: 'hidden', + flexShrink: 0, + }, + arrow: { + fontSize: 11, + }, + arrowContainer: { + width: 16, + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + marginRight: 6, + }, + tabulations: { + content: '', + width: ({ tabulations }) => (30 * tabulations), + }, + arrowButton: { + padding: 4, + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + sharedFolder: { + position: 'absolute', + width: '48%', + right: '12%', + bottom: '20%', + }, + icon: { + height: '0.9em', + margin: '0.1em 0 0 7px', + flexShrink: 0, + }, + tooltipRoot: { + margin: 0, + maxWidth: 300, + padding: '5px 10px', + color: theme.palette.common.white, + backgroundColor: '#171717', + borderRadius: 4, + }, + name: { + '&:hover': { + color: theme.palette.palette.blue1, + textDecoration: 'underline', + }, + }, + selected: { + color: theme.palette.palette.blue1, + }, + tooltipArrow: { + color: '#171717', + }, +})); From 8831bd71a6bccefe06ed934762bae2107c01ffe2 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Tue, 1 Dec 2020 14:04:05 -0500 Subject: [PATCH 17/51] background white --- src/UI/Table/components/index.js | 1 + src/UI/Table/table.stories.js | 2 +- .../Layout/components/Sidebar/styles.js | 1 + src/shared/components/Layout/styles.js | 2 +- src/views/Storage/shared/RenderRow/index.js | 18 +++++------------- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/UI/Table/components/index.js b/src/UI/Table/components/index.js index 9d3a2bc4..0eca1935 100644 --- a/src/UI/Table/components/index.js +++ b/src/UI/Table/components/index.js @@ -1,4 +1,5 @@ export { default as FileCell } from './FileCell'; +export { default as FileNameCell } from './FileNameCell'; export { default as TableRow } from './TableRow'; export { default as TableCell } from './TableCell'; export { default as IconsCell } from './IconsCell'; diff --git a/src/UI/Table/table.stories.js b/src/UI/Table/table.stories.js index bdf8b9a7..886151cf 100644 --- a/src/UI/Table/table.stories.js +++ b/src/UI/Table/table.stories.js @@ -6,7 +6,7 @@ import { object, boolean } from '@storybook/addon-knobs'; import Table from './index'; import { - FileCell, + FileNameCell, TableRow, TableCell, IconsCell, diff --git a/src/shared/components/Layout/components/Sidebar/styles.js b/src/shared/components/Layout/components/Sidebar/styles.js index 1e1c4519..6dcadf3d 100644 --- a/src/shared/components/Layout/components/Sidebar/styles.js +++ b/src/shared/components/Layout/components/Sidebar/styles.js @@ -35,6 +35,7 @@ export default makeStyles((theme) => ({ width: 163, display: 'flex', flexDirection: 'column', + borderRight: `1px solid ${theme.palette.palette.gray4}`, }, userContent: { display: 'flex', diff --git a/src/shared/components/Layout/styles.js b/src/shared/components/Layout/styles.js index a633273c..8263e64e 100644 --- a/src/shared/components/Layout/styles.js +++ b/src/shared/components/Layout/styles.js @@ -4,7 +4,7 @@ export default makeStyles((theme) => ({ root: { display: 'flex', height: '100%', - backgroundColor: theme.palette.palette.gray5, + backgroundColor: theme.palette.palette.white, }, mainContent: { flexGrow: 1, diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 719593d4..dd0016ff 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -6,7 +6,7 @@ import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; -import { TableCell, FileCell, IconsCell } from '@ui/Table'; +import { TableCell, FileNameCell, IconsCell } from '@ui/Table'; import { openModal, LICENSE_REGISTRATION } from '@shared/components/Modal/actions'; import classnames from 'classnames'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; @@ -64,23 +64,15 @@ const RenderRow = ({ row, arrowOnClick }) => { return ( <> - - - {row.name} - - + name={row.name} + selected={!!row.selected} + /> From 5274f39e741ab392a22e04d1002a8c10ed2c0b84 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Tue, 1 Dec 2020 14:09:08 -0500 Subject: [PATCH 18/51] added isShared prop --- src/views/Storage/shared/RenderRow/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index dd0016ff..933f1782 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -72,6 +72,7 @@ const RenderRow = ({ row, arrowOnClick }) => { tabulations={getTabulationAmount()} name={row.name} selected={!!row.selected} + isShared={row.members.length > 0} /> Date: Tue, 1 Dec 2020 16:36:51 -0300 Subject: [PATCH 19/51] updated skeleton --- src/UI/Table/components/LoadingCell/index.js | 54 ++++--------------- .../LoadingCell/loading-cell.stories.js | 17 ++++++ src/UI/Table/components/LoadingCell/styles.js | 12 ++--- src/UI/Table/table.stories.js | 18 +++++-- .../Storage/shared/render-loading-rows.js | 18 +++++-- 5 files changed, 59 insertions(+), 60 deletions(-) create mode 100644 src/UI/Table/components/LoadingCell/loading-cell.stories.js diff --git a/src/UI/Table/components/LoadingCell/index.js b/src/UI/Table/components/LoadingCell/index.js index 001783af..788ac5fc 100644 --- a/src/UI/Table/components/LoadingCell/index.js +++ b/src/UI/Table/components/LoadingCell/index.js @@ -1,55 +1,23 @@ import React from 'react'; -import PropTypes from 'prop-types'; import Skeleton from '@material-ui/lab/Skeleton'; import useStyles from './styles'; +const VARIANT = 'rect'; +const ANIMATION = 'wave'; + +/* eslint-disable react/jsx-props-no-spreading */ const LoadingCell = (props) => { const classes = useStyles(); - const { isLastCell, isIconCell } = props; - const cellWidth = isLastCell ? '100%' : 'calc(100% - 25px)'; - const ANIMATION = 'wave'; - const VARIANT = 'rect'; - return ( - <> - {isIconCell ? ( -
- - -
- ) : ( - - )} - + ); }; -LoadingCell.defaultProps = { - isLastCell: false, - isIconCell: false, -}; - -LoadingCell.propTypes = { - isLastCell: PropTypes.bool, - isIconCell: PropTypes.bool, -}; - export default LoadingCell; diff --git a/src/UI/Table/components/LoadingCell/loading-cell.stories.js b/src/UI/Table/components/LoadingCell/loading-cell.stories.js new file mode 100644 index 00000000..c505060e --- /dev/null +++ b/src/UI/Table/components/LoadingCell/loading-cell.stories.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import LoadingCell from './index'; + +const categoryName = 'ElementalComponents/Table'; + +storiesOf(categoryName, module).add('LoadingCell', () => { + + return ( +
+ +
+ ); +}); diff --git a/src/UI/Table/components/LoadingCell/styles.js b/src/UI/Table/components/LoadingCell/styles.js index dd8138eb..40fa78de 100644 --- a/src/UI/Table/components/LoadingCell/styles.js +++ b/src/UI/Table/components/LoadingCell/styles.js @@ -1,16 +1,10 @@ import { makeStyles } from '@material-ui/core/styles'; export default makeStyles({ - iconCellContainer: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - iconCell: { - marginRight: 6, - display: 'inline-block', - }, cell: { + borderRadius: 4, display: 'inline-block', + width: '100%', + backgroundColor: '#EBEEF3', }, }); diff --git a/src/UI/Table/table.stories.js b/src/UI/Table/table.stories.js index bdf8b9a7..0a722d60 100644 --- a/src/UI/Table/table.stories.js +++ b/src/UI/Table/table.stories.js @@ -73,16 +73,26 @@ const renderLoadingRows = () => [...Array(20)].map((_, index) => ( key={index} > - + - + + - + - + )); diff --git a/src/views/Storage/shared/render-loading-rows.js b/src/views/Storage/shared/render-loading-rows.js index 348ce86d..cf49da4c 100644 --- a/src/views/Storage/shared/render-loading-rows.js +++ b/src/views/Storage/shared/render-loading-rows.js @@ -11,16 +11,26 @@ const renderLoadingRows = () => [...Array(20)].map((_, index) => ( key={index} > - + - + + - + - + )); From 392eaf8f9dbf81800f0221bd6d05d73386e34d23 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Tue, 1 Dec 2020 14:47:38 -0500 Subject: [PATCH 20/51] fixed size header + table border --- src/shared/components/ObjectsTable/ObjectsTable.js | 8 +++++++- src/shared/components/ObjectsTable/styles.js | 4 ++++ src/views/Storage/shared/getTableHeads.js | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 35af1d4d..5fa36517 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -289,8 +289,14 @@ const ObjectsTable = ({ title, isSortable, id, + paddingLeft = 0, }) => ( - + {isSortable ? ( ({ '&&&:hover': { backgroundColor: '#F5F6F8', }, + borderTop: '1px solid #EEF1F6', + '&:last-child': { + borderBottom: '1px solid #EEF1F6', + }, }, headerCell: { paddingTop: 6, diff --git a/src/views/Storage/shared/getTableHeads.js b/src/views/Storage/shared/getTableHeads.js index 78830219..7e595154 100644 --- a/src/views/Storage/shared/getTableHeads.js +++ b/src/views/Storage/shared/getTableHeads.js @@ -14,6 +14,7 @@ export default (t) => [ width: '20%', title: t('modules.storage.fileTable.head.size'), isSortable: true, + paddingLeft: 23, }, { id: 'lastModified', From a5848f83c6efac579d23535c523a4e04a4846a72 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Tue, 1 Dec 2020 14:57:48 -0500 Subject: [PATCH 21/51] removed last row --- src/views/Storage/shared/RenderRow/index.js | 27 +------------------ src/views/Storage/shared/getTableHeads.js | 15 +++-------- .../Storage/shared/render-loading-rows.js | 3 --- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 933f1782..41032359 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -2,12 +2,9 @@ import React from 'react'; import moment from 'moment'; import PropTypes from 'prop-types'; import { formatBytes } from '@utils'; -import { useDispatch } from 'react-redux'; -import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; -import { TableCell, FileNameCell, IconsCell } from '@ui/Table'; -import { openModal, LICENSE_REGISTRATION } from '@shared/components/Modal/actions'; +import { TableCell, FileNameCell } from '@ui/Table'; import classnames from 'classnames'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; import { faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons/faSpinnerThird'; @@ -15,18 +12,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import useStyles from './styles'; const RenderRow = ({ row, arrowOnClick }) => { - const { t } = useTranslation(); - const dispatch = useDispatch(); const location = useLocation(); const classes = useStyles(); - const shareAmount = row.shareAmount - 1; - const iconsCellI18n = { - warning: t('modules.storage.fileTable.storageLimitReached.warning'), - description: t('modules.storage.fileTable.storageLimitReached.description'), - button: t('modules.storage.fileTable.storageLimitReached.button'), - }; - const getTabulationAmount = () => { const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); const locationWithoutRoot = locationWithRoot.slice(2, locationWithRoot.length); @@ -89,19 +77,6 @@ const RenderRow = ({ row, arrowOnClick }) => { {/* {formatMonthDayYear(row.lastModified)} */} - - { - e.stopPropagation(); - dispatch(openModal(LICENSE_REGISTRATION)); - }} - i18n={iconsCellI18n} - /> - ); }; diff --git a/src/views/Storage/shared/getTableHeads.js b/src/views/Storage/shared/getTableHeads.js index 7e595154..ce6b9376 100644 --- a/src/views/Storage/shared/getTableHeads.js +++ b/src/views/Storage/shared/getTableHeads.js @@ -1,30 +1,21 @@ -import React from 'react'; - -import { IconsTooltip } from '@ui/Table'; - export default (t) => [ { id: 'name', - width: '40%', + width: '50%', title: t('modules.storage.fileTable.head.name'), isSortable: true, }, { id: 'size', - width: '20%', + width: '25%', title: t('modules.storage.fileTable.head.size'), isSortable: true, paddingLeft: 23, }, { id: 'lastModified', - width: '32%', + width: '25%', title: t('modules.storage.fileTable.head.lastModified'), isSortable: true, }, - { - id: 'iconsTooltip', - width: '80px', - title: , - }, ]; diff --git a/src/views/Storage/shared/render-loading-rows.js b/src/views/Storage/shared/render-loading-rows.js index 348ce86d..85b582fd 100644 --- a/src/views/Storage/shared/render-loading-rows.js +++ b/src/views/Storage/shared/render-loading-rows.js @@ -16,9 +16,6 @@ const renderLoadingRows = () => [...Array(20)].map((_, index) => ( - - - From 6c386eb6d55c6fb6bd7270b3f44fa4626f0976db Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Tue, 1 Dec 2020 20:39:48 -0500 Subject: [PATCH 22/51] added upload and error state --- .../components/FileNameCell/FileNameCell.js | 19 ++++-- .../Table/components/FileNameCell/styles.js | 3 + src/locales/en/translation.json | 1 + .../components/ObjectsTable/ObjectsTable.js | 3 +- src/shared/components/ObjectsTable/styles.js | 3 + src/views/Storage/shared/RenderRow/index.js | 66 +++++++++++++++++-- src/views/Storage/shared/RenderRow/styles.js | 30 +++++++++ 7 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/UI/Table/components/FileNameCell/FileNameCell.js b/src/UI/Table/components/FileNameCell/FileNameCell.js index dca99b27..e14b457f 100644 --- a/src/UI/Table/components/FileNameCell/FileNameCell.js +++ b/src/UI/Table/components/FileNameCell/FileNameCell.js @@ -22,6 +22,7 @@ const FileNameCell = (props) => { selected, tabulations, arrowOnClick, + isUploading, ...tableCellProps } = props; @@ -41,8 +42,10 @@ const FileNameCell = (props) => { variant="body1" noWrap ref={textNode} - className={classnames(classes.name, { - [classes.selected]: selected, + className={classnames({ + [classes.selected]: selected && !isUploading, + [classes.uploading]: isUploading, + [classes.nameHover]: !isUploading, })} > {name} @@ -58,7 +61,9 @@ const FileNameCell = (props) => { {isFolder && ( { e.stopPropagation(); arrowOnClick(); @@ -72,7 +77,11 @@ const FileNameCell = (props) => { )}
-
+
{}, + isUploading: false, }; FileNameCell.propTypes = { @@ -121,6 +131,7 @@ FileNameCell.propTypes = { tabulations: PropTypes.number, isShared: PropTypes.bool, arrowOnClick: PropTypes.func, + isUploading: PropTypes.bool, }; export default FileNameCell; diff --git a/src/UI/Table/components/FileNameCell/styles.js b/src/UI/Table/components/FileNameCell/styles.js index f0d75e82..252a53c5 100644 --- a/src/UI/Table/components/FileNameCell/styles.js +++ b/src/UI/Table/components/FileNameCell/styles.js @@ -65,4 +65,7 @@ export default makeStyles((theme) => ({ tooltipArrow: { color: '#171717', }, + uploading: { + opacity: '50%', + }, })); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 64049b4b..afd1ad0b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -136,6 +136,7 @@ "message": "Failed to open file, please try again.", "buttonText": "Okay" }, + "uploadFailed": "Upload Failed", "storageLimitReached": { "warning": "Backup Limit Reached", "description": "This file is not backed up, upgrade to Space Pro to back up this file.", diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 5fa36517..9baaf2cb 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -326,8 +326,9 @@ const ObjectsTable = ({ hover key={row.id} className={classNames(classes.row, { + [classes.selectedAndUploading]: row.isUploading && row.selected, [classes.selected]: row.selected, - [classes.error]: row.error, + [classes.error]: row.error && !row.isUploading, })} onClick={handleRowClick({ row, rowIndex })} onContextMenu={handleRowRightClick({ row })} diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index 691300f3..9a63902d 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -30,6 +30,9 @@ export default makeStyles(() => ({ selected: { backgroundColor: '#E5F0FF !important', }, + selectedAndUploading: { + backgroundColor: '#F5F6F8 !important', + }, error: { backgroundColor: '#F8DEDF !important', }, diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 41032359..d7e42aca 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -4,16 +4,19 @@ import PropTypes from 'prop-types'; import { formatBytes } from '@utils'; import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; +import { useTranslation } from 'react-i18next'; import { TableCell, FileNameCell } from '@ui/Table'; import classnames from 'classnames'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; +import { faExclamationCircle } from '@fortawesome/pro-solid-svg-icons/faExclamationCircle'; import { faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons/faSpinnerThird'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import useStyles from './styles'; const RenderRow = ({ row, arrowOnClick }) => { const location = useLocation(); - const classes = useStyles(); + const classes = useStyles({ progress: 0.4 }); + const { t } = useTranslation(); const getTabulationAmount = () => { const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); @@ -27,6 +30,27 @@ const RenderRow = ({ row, arrowOnClick }) => { }; const getSizeIcon = () => { + if (row.isUploading) { + if (row.error) { + return ( +
+ +
+ ); + } + return ( +
+ +
+ ); + } if (row.isAvailableInSpace) { return (
@@ -50,6 +74,28 @@ const RenderRow = ({ row, arrowOnClick }) => { ); }; + const getLastModifiedCell = () => { + if (row.isUploading) { + if (row.error) { + return ( + + {t('modules.storage.fileTable.uploadFailed')} + + ); + } + return ( +
+ ); + } + return ( + + {moment(row.lastModified).format('MMM D, YYYY')} + {/* ^ just for testing, after POC should be used line below */} + {/* {formatMonthDayYear(row.lastModified)} */} + + ); + }; + return ( <> { name={row.name} selected={!!row.selected} isShared={row.members.length > 0} + isUploading={row.isUploading} /> {getSizeIcon()} - + {formatBytes(row.size)} - - {moment(row.lastModified).format('MMM D, YYYY')} - {/* ^ just for testing, after POC should be used line below */} - {/* {formatMonthDayYear(row.lastModified)} */} - + {getLastModifiedCell()} ); @@ -98,6 +148,8 @@ RenderRow.propTypes = { expanded: PropTypes.bool, selected: PropTypes.bool, members: PropTypes.array, + isUploading: PropTypes.bool, + error: PropTypes.bool, }).isRequired, arrowOnClick: PropTypes.func, }; diff --git a/src/views/Storage/shared/RenderRow/styles.js b/src/views/Storage/shared/RenderRow/styles.js index 3c6ec009..dce75ce4 100644 --- a/src/views/Storage/shared/RenderRow/styles.js +++ b/src/views/Storage/shared/RenderRow/styles.js @@ -23,4 +23,34 @@ export default makeStyles((theme) => ({ highlighted: { color: theme.palette.palette.spaceBlue, }, + uploading: { + opacity: '50%', + }, + uploadingIcon: { + fontSize: 11, + color: '#A5A5A5', + }, + progressBar: { + height: 10, + width: 80, + borderRadius: 3, + border: '1px solid #DDE0E2', + backgroundColor: theme.palette.palette.white, + '&:before': { + content: '""', + display: 'block', + width: ({ progress }) => `${progress * 100}%`, + height: '100%', + backgroundColor: '#EAEBEC', + transition: 'width ease-out 0.5s', + }, + }, + errorIcon: { + fontSize: 11, + color: theme.palette.palette.red, + }, + errorText: { + fontSize: 12, + color: theme.palette.palette.red, + }, })); From 24991d5388b2d407280717ae798f9ebad849ab4b Mon Sep 17 00:00:00 2001 From: Guillermo Puente Date: Wed, 2 Dec 2020 14:46:32 -0300 Subject: [PATCH 23/51] Fix navigation inside sub-folders --- src/views/Storage/shared/components/FileTable/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views/Storage/shared/components/FileTable/index.js b/src/views/Storage/shared/components/FileTable/index.js index 62c9c78e..71a84d78 100644 --- a/src/views/Storage/shared/components/FileTable/index.js +++ b/src/views/Storage/shared/components/FileTable/index.js @@ -66,7 +66,10 @@ const FileTable = ({ }); }; - const getRedirectUrl = (row) => path.posix.join(baseRedirectUrl, prefix, row.key); + const getRedirectUrl = (row) => { + const folderPath = row.key.replace(prefix, ''); + return path.posix.join(baseRedirectUrl, prefix, folderPath); + }; return ( Date: Wed, 2 Dec 2020 15:01:52 -0300 Subject: [PATCH 24/51] fix layout border style --- src/shared/components/DetailsPanel/DetailsPanel.js | 13 +++++++++++-- .../components/Layout/components/Sidebar/styles.js | 2 +- src/views/Storage/DetailsPanel/index.js | 4 +++- src/views/Storage/DetailsPanel/styles.js | 7 +++++++ 4 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/views/Storage/DetailsPanel/styles.js diff --git a/src/shared/components/DetailsPanel/DetailsPanel.js b/src/shared/components/DetailsPanel/DetailsPanel.js index c63415b4..ae494438 100644 --- a/src/shared/components/DetailsPanel/DetailsPanel.js +++ b/src/shared/components/DetailsPanel/DetailsPanel.js @@ -1,22 +1,31 @@ import React from 'react'; import PropTypes from 'prop-types'; +import classnames from 'classnames'; import useStyles from './styles'; -const DetailsPanel = ({ id, children }) => { +const DetailsPanel = ({ id, children, className }) => { const classes = useStyles(); return (
{children}
); }; +DetailsPanel.defaultProps = { + className: null, +}; + DetailsPanel.propTypes = { + className: PropTypes.string, id: PropTypes.string.isRequired, children: PropTypes.node.isRequired, }; diff --git a/src/shared/components/Layout/components/Sidebar/styles.js b/src/shared/components/Layout/components/Sidebar/styles.js index 6dcadf3d..3c2bbf7c 100644 --- a/src/shared/components/Layout/components/Sidebar/styles.js +++ b/src/shared/components/Layout/components/Sidebar/styles.js @@ -8,6 +8,7 @@ export default makeStyles((theme) => ({ flexDirection: 'column', backgroundColor: theme.palette.palette.white, flex: `0 0 ${SIDEBAR_WIDTH}px`, + borderRight: `1px solid ${theme.palette.palette.gray4}`, }, trafficLightsSpot: { height: 34, @@ -35,7 +36,6 @@ export default makeStyles((theme) => ({ width: 163, display: 'flex', flexDirection: 'column', - borderRight: `1px solid ${theme.palette.palette.gray4}`, }, userContent: { display: 'flex', diff --git a/src/views/Storage/DetailsPanel/index.js b/src/views/Storage/DetailsPanel/index.js index fd8f8d4f..c777004c 100644 --- a/src/views/Storage/DetailsPanel/index.js +++ b/src/views/Storage/DetailsPanel/index.js @@ -17,8 +17,10 @@ import DetailsPanel, { } from '@shared/components/DetailsPanel'; import { OBJECT_TYPES } from './constants'; +import useStyles from './styles'; const StorageDetailsPanel = () => { + const classes = useStyles(); const { t } = useTranslation(); const location = useLocation(); const dispatch = useDispatch(); @@ -60,7 +62,7 @@ const StorageDetailsPanel = () => { }; return ( - + { selectedObjects.length === 0 ? ( ({ + root: { + borderLeft: `1px solid ${theme.palette.palette.gray4}`, + }, +})); From 10af01b336a00b13eebb1ea77632a78ce55cfa98 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Wed, 2 Dec 2020 18:43:15 -0500 Subject: [PATCH 25/51] popver --- src/UI/HoverMenu/hover-menu.stories.js | 34 ++++++++ src/UI/HoverMenu/index.js | 84 +++++++++++++++++++ src/UI/HoverMenu/styles.js | 56 +++++++++++++ .../Table/components/FileNameCell/styles.js | 8 -- src/UI/Table/table.stories.js | 4 +- src/locales/en/translation.json | 4 + .../components/ObjectsTable/ObjectsTable.js | 58 +++++++++++++ .../ObjectsTable/utils/get-hover-menu.js | 29 +++++++ src/utils/object-presenter.js | 2 + 9 files changed, 269 insertions(+), 10 deletions(-) create mode 100644 src/UI/HoverMenu/hover-menu.stories.js create mode 100644 src/UI/HoverMenu/index.js create mode 100644 src/UI/HoverMenu/styles.js create mode 100644 src/shared/components/ObjectsTable/utils/get-hover-menu.js diff --git a/src/UI/HoverMenu/hover-menu.stories.js b/src/UI/HoverMenu/hover-menu.stories.js new file mode 100644 index 00000000..9f308a13 --- /dev/null +++ b/src/UI/HoverMenu/hover-menu.stories.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import HoverMenu, { HOVER_OPTION_IDS } from './index'; +import { faSyncAlt } from '@fortawesome/pro-regular-svg-icons/faSyncAlt'; +import { faTimes } from '@fortawesome/pro-regular-svg-icons/faTimes'; + +const categoryName = 'HoverMenu'; + +storiesOf(categoryName, module).add('default', () => { + const defaultProps = { + menuItemOnClick: (id) => { console.log(id) }, + i18n: { + cancel: 'Cancel', + retry: 'Retry', + }, + items: [ + { + id: HOVER_OPTION_IDS.retry, + icon: faSyncAlt, + }, + { + id: HOVER_OPTION_IDS.cancel, + icon: faTimes, + }, + ] + }; + + return ( +
+ +
+ ); +}); diff --git a/src/UI/HoverMenu/index.js b/src/UI/HoverMenu/index.js new file mode 100644 index 00000000..b8197ee5 --- /dev/null +++ b/src/UI/HoverMenu/index.js @@ -0,0 +1,84 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Paper from '@material-ui/core/Paper'; +import MenuItem from '@material-ui/core/MenuItem'; +import Typography from '@material-ui/core/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import Tooltip from '@material-ui/core/Tooltip'; +import classnames from 'classnames'; + +import useStyles from './styles'; + +export const HOVER_OPTION_IDS = { + retry: 'retry', + cancel: 'cancel', +}; + +const HoverMenu = ({ + menuItemOnClick, + items, + i18n, +}) => { + const classes = useStyles(); + + return ( + + {items.map((item) => ( + <> + {i18n[item.id]}} + > + menuItemOnClick(item.id)} + > +
+ +
+ + {item.displayText} + +
+
+ + ))} +
+ ); +}; + +HoverMenu.defaultProps = { + items: [], +}; + +HoverMenu.propTypes = { + menuItemOnClick: PropTypes.func.isRequired, + i18n: PropTypes.shape({ + retry: PropTypes.string, + cancel: PropTypes.string, + }).isRequired, + items: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + icon: PropTypes.element, + }), + ), +}; + +export default HoverMenu; diff --git a/src/UI/HoverMenu/styles.js b/src/UI/HoverMenu/styles.js new file mode 100644 index 00000000..f3c9efb7 --- /dev/null +++ b/src/UI/HoverMenu/styles.js @@ -0,0 +1,56 @@ +import { makeStyles } from '@material-ui/core/styles'; + +const getBorder = () => ('1px solid #D8D8d8'); + +export default makeStyles((theme) => ({ + paper: { + width: 'fit-content', + boxShadow: '0px 3px 6px #00000029', + borderRadius: 6, + display: 'flex', + flexDirection: 'row', + height: 32, + }, + menuItem: { + width: 32, + display: 'flex', + alignContent: 'center', + justifyContent: 'center', + borderBottom: getBorder(theme), + borderTop: getBorder(theme), + '&:first-child': { + borderTopLeftRadius: 6, + borderBottomLeftRadius: 6, + borderLeft: getBorder(theme), + }, + '&:last-child': { + borderTopRightRadius: 6, + borderBottomRightRadius: 6, + borderRight: getBorder(theme), + }, + }, + iconContainer: { + width: 21, + display: 'flex', + alignContent: 'center', + }, + icon: { + fontSize: 14, + color: '#7F8185', + }, + cancelIcon: { + fontSize: 19, + }, + tooltipRoot: { + margin: 0, + maxWidth: 300, + padding: '5px 10px', + color: theme.palette.common.white, + backgroundColor: '#171717', + borderRadius: 4, + top: -5, + }, + tooltipArrow: { + color: '#171717', + }, +})); diff --git a/src/UI/Table/components/FileNameCell/styles.js b/src/UI/Table/components/FileNameCell/styles.js index 252a53c5..fc5b49ef 100644 --- a/src/UI/Table/components/FileNameCell/styles.js +++ b/src/UI/Table/components/FileNameCell/styles.js @@ -45,14 +45,6 @@ export default makeStyles((theme) => ({ margin: '0.1em 0 0 7px', flexShrink: 0, }, - tooltipRoot: { - margin: 0, - maxWidth: 300, - padding: '5px 10px', - color: theme.palette.common.white, - backgroundColor: '#171717', - borderRadius: 4, - }, name: { '&:hover': { color: theme.palette.palette.blue1, diff --git a/src/UI/Table/table.stories.js b/src/UI/Table/table.stories.js index 886151cf..5516804c 100644 --- a/src/UI/Table/table.stories.js +++ b/src/UI/Table/table.stories.js @@ -32,7 +32,7 @@ const renderRow = ({ row }) => ( key={row.id} hover > - ( {row.name} - +
Only you diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index afd1ad0b..dcddff91 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -522,5 +522,9 @@ "open": "Open", "share": "Share", "delete": "Delete" + }, + "hoverMenu": { + "retry": "Retry", + "cancel": "Cancel" } } diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 9baaf2cb..6ef9cd88 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -9,6 +9,7 @@ import { faLongArrowDown } from '@fortawesome/pro-regular-svg-icons/faLongArrowD import { faEllipsisH } from '@fortawesome/pro-regular-svg-icons/faEllipsisH'; import Button from '@material-ui/core/Button'; import ButtonBase from '@material-ui/core/ButtonBase'; +import Popover from '@material-ui/core/Popover'; import Typography from '@material-ui/core/Typography'; import { openObject } from '@events'; import { UPDATE_OBJECTS } from '@reducers/storage'; @@ -18,8 +19,10 @@ import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Modal/actions'; import { useTranslation } from 'react-i18next'; +import HoverMenu from '@ui/HoverMenu'; import getContextMenuItems from './utils/get-context-menu'; +import getHoverMenuItems from './utils/get-hover-menu'; import useStyles from './styles'; const ObjectsTable = ({ @@ -39,6 +42,7 @@ const ObjectsTable = ({ const classes = useStyles(); const history = useHistory(); const dispatch = useDispatch(); + const [anchorEl, setAnchorEl] = React.useState(null); const initialContextState = { mouseX: null, mouseY: null, @@ -96,6 +100,10 @@ const ObjectsTable = ({ const sortedRows = sortAndAddSubfolders(unsortedRows); const clickedItem = sortedRows.find((row) => row.selected); + const hoveredItemKey = anchorEl && anchorEl.dataset.key; + const hoveredItem = anchorEl && sortedRows.find((row) => (row.fullKey === hoveredItemKey)); + + const hoveredItemOptions = getHoverMenuItems(hoveredItem); const handleRowClick = ({ rowIndex }) => (event) => { event.preventDefault(); @@ -264,6 +272,20 @@ const ObjectsTable = ({ const contextMenuItems = getContextMenuItems(clickedItem, t); + const handlePopoverOpen = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handlePopoverClose = () => { + setAnchorEl(null); + }; + + const popoverOpen = Boolean(anchorEl); + + const hoverMenuItemOnClick = (id) => { + console.log(id); + }; + return (
( {!loading && !sortedRows.length && } + { + anchorEl && hoveredItemOptions.length > 0 && ( + + + + ) + }
); }; diff --git a/src/shared/components/ObjectsTable/utils/get-hover-menu.js b/src/shared/components/ObjectsTable/utils/get-hover-menu.js new file mode 100644 index 00000000..0efa320b --- /dev/null +++ b/src/shared/components/ObjectsTable/utils/get-hover-menu.js @@ -0,0 +1,29 @@ +import { HOVER_OPTION_IDS } from '@ui/HoverMenu'; +import { faSyncAlt } from '@fortawesome/pro-regular-svg-icons/faSyncAlt'; +import { faTimes } from '@fortawesome/pro-regular-svg-icons/faTimes'; + +const mapHoverMenuItems = (hoveredItem) => { + if (!hoveredItem || !hoveredItem.isUploading) { + return []; + } + if (hoveredItem.error) { + return ([ + { + id: HOVER_OPTION_IDS.retry, + icon: faSyncAlt, + }, + { + id: HOVER_OPTION_IDS.cancel, + icon: faTimes, + }, + ]); + } + return ([ + { + id: HOVER_OPTION_IDS.cancel, + icon: faTimes, + }, + ]); +}; + +export default mapHoverMenuItems; diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 54128ac4..3c4436ac 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -46,6 +46,8 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), + error: false, + isUploading: true, }; }; From 05f0a000e1a9a8bf60751b65091e7f8b2e89f620 Mon Sep 17 00:00:00 2001 From: Mateusz Walendzik Date: Thu, 3 Dec 2020 17:39:21 +0100 Subject: [PATCH 26/51] fix dropzone (#383) --- src/shared/components/Dropzone/index.js | 7 ++--- src/shared/components/Dropzone/styles.js | 14 +++++----- .../components/ObjectsTable/ObjectsTable.js | 26 ++++++++++++++----- src/utils/get-tabulations.js | 11 ++++++++ src/utils/index.js | 1 + src/views/Storage/shared/RenderRow/index.js | 17 +++--------- 6 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 src/utils/get-tabulations.js diff --git a/src/shared/components/Dropzone/index.js b/src/shared/components/Dropzone/index.js index e2789401..87bd42cc 100644 --- a/src/shared/components/Dropzone/index.js +++ b/src/shared/components/Dropzone/index.js @@ -18,9 +18,10 @@ const Dropzone = ({ const { clientY } = event; const { top } = wrapperNode.current.getBoundingClientRect(); const yPosition = clientY - top - headHeight; // y position without top offset and scroll - const hoverRowNumber = Math.floor(yPosition / rowHeight); - if (hoverRowNumber !== rowNumber) { - setRowNumber(hoverRowNumber); + const hoverRowIndex = Math.floor(yPosition / rowHeight); + const hoverRowTopIndex = get(objectsList, `${hoverRowIndex}.index`, -1); + if (hoverRowTopIndex !== rowNumber) { + setRowNumber(hoverRowTopIndex); } }; diff --git a/src/shared/components/Dropzone/styles.js b/src/shared/components/Dropzone/styles.js index 12825023..c7a89bd3 100644 --- a/src/shared/components/Dropzone/styles.js +++ b/src/shared/components/Dropzone/styles.js @@ -1,7 +1,9 @@ import { makeStyles } from '@material-ui/core/styles'; export const rowHeight = 35; -export const headHeight = 27; +export const headHeight = 39; + +const RAINBOW_BORDER_WIDTH = 3; export default makeStyles({ root: { @@ -20,11 +22,11 @@ export default makeStyles({ background: 'linear-gradient(134deg, #ed55eb 18%, #17e0d8 42%, #00ffc2 59%, #ffec06 81%)', backgroundRepeat: 'no-repeat', borderRadius: 6, - top: headHeight - 3, - right: 0, - bottom: 0, - left: 2, - padding: 3, + top: headHeight - 2 * RAINBOW_BORDER_WIDTH, + right: -RAINBOW_BORDER_WIDTH, + bottom: -RAINBOW_BORDER_WIDTH, + left: -RAINBOW_BORDER_WIDTH, + padding: RAINBOW_BORDER_WIDTH, transition: 'top ease .17s, bottom ease .17s', '&:before': { content: '""', diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 4a427970..2e7c3aff 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import { useDispatch } from 'react-redux'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useLocation } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faLongArrowUp } from '@fortawesome/pro-regular-svg-icons/faLongArrowUp'; import { faLongArrowDown } from '@fortawesome/pro-regular-svg-icons/faLongArrowDown'; @@ -18,7 +18,7 @@ import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Modal/actions'; import { useTranslation } from 'react-i18next'; - +import { getTabulations } from '@utils'; import getContextMenuItems from './utils/get-context-menu'; import useStyles from './styles'; @@ -40,6 +40,8 @@ const ObjectsTable = ({ const classes = useStyles(); const history = useHistory(); const dispatch = useDispatch(); + const location = useLocation(); + const initialContextState = { mouseX: null, mouseY: null, @@ -265,16 +267,28 @@ const ObjectsTable = ({ const contextMenuItems = getContextMenuItems(clickedItem, t); + const getDropzoneObjsList = () => { + let indexOfLastVisitedRootObj = 0; + + return sortedRows.map((obj, index) => { + if (getTabulations(obj.key, location) === 0) { + indexOfLastVisitedRootObj = index; + } + return { + isFolder: obj.type === 'folder', + name: obj.key, + index: indexOfLastVisitedRootObj, + }; + }); + }; + return (
({ - isFolder: obj.type === 'folder', - name: obj.key, - }))} + objectsList={getDropzoneObjsList()} >
{ + const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); + const locationWithoutRoot = locationWithRoot.slice(2, locationWithRoot.length); + const rootFolderAmount = locationWithoutRoot.length; + const currentItemFolderAmount = rowKey.split('/').length; + const tabulations = currentItemFolderAmount - rootFolderAmount - 1; + + return tabulations; +}; + +export default getTabulations; diff --git a/src/utils/index.js b/src/utils/index.js index 9a3be228..d2db1df8 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -10,3 +10,4 @@ export { default as getAddressByPublicKey } from './get-address-by-public-key'; export { default as getShortAddress } from './get-short-address'; export { default as useTorusSdk } from './use-torus-sdk'; export { default as useWsChallenge } from './use-ws-challenge'; +export { default as getTabulations } from './get-tabulations'; diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 780fae66..11d71914 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -1,7 +1,7 @@ import React from 'react'; import moment from 'moment'; import PropTypes from 'prop-types'; -import { formatBytes } from '@utils'; +import { formatBytes, getTabulations } from '@utils'; import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; import { TableCell, FileNameCell } from '@ui/Table'; @@ -15,17 +15,6 @@ const RenderRow = ({ row, arrowOnClick, disableOffset }) => { const location = useLocation(); const classes = useStyles(); - const getTabulationAmount = () => { - const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); - const locationWithoutRoot = locationWithRoot.slice(2, locationWithRoot.length); - const rootFolderAmount = locationWithoutRoot.length; - const { key = '' } = row; - const currentItemFolderAmount = key.split('/').length; - const tabulations = currentItemFolderAmount - rootFolderAmount - 1; - - return tabulations; - }; - const getSizeIcon = () => { if (row.isAvailableInSpace) { return ( @@ -57,14 +46,14 @@ const RenderRow = ({ row, arrowOnClick, disableOffset }) => { src={`file:${row.key}`} arrowOnClick={arrowOnClick} expanded={row.expanded} - tabulations={getTabulationAmount()} + tabulations={getTabulations(row.key, location)} name={row.name} selected={!!row.selected} isShared={row.members.length > 0} /> {getSizeIcon()} From 6234f7c3e9be6add3bfa6d4bd328f0edc0ac1b80 Mon Sep 17 00:00:00 2001 From: Mateusz Walendzik Date: Thu, 3 Dec 2020 18:25:55 +0100 Subject: [PATCH 27/51] small rainbow border fix (#384) --- src/shared/components/Dropzone/index.js | 2 +- src/shared/components/Dropzone/styles.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/components/Dropzone/index.js b/src/shared/components/Dropzone/index.js index 87bd42cc..4daa7624 100644 --- a/src/shared/components/Dropzone/index.js +++ b/src/shared/components/Dropzone/index.js @@ -70,7 +70,7 @@ const Dropzone = ({ const classes = useStyles(); const rainbowFieldStyles = get(objectsList, `${rowNumber}.isFolder`) ? { - top: headHeight + rowNumber * rowHeight, + top: headHeight + rowNumber * rowHeight + 1, bottom: wrapperHeight.current - (headHeight + (rowNumber + 1) * rowHeight), } : {}; diff --git a/src/shared/components/Dropzone/styles.js b/src/shared/components/Dropzone/styles.js index c7a89bd3..fdbd63e3 100644 --- a/src/shared/components/Dropzone/styles.js +++ b/src/shared/components/Dropzone/styles.js @@ -1,9 +1,9 @@ import { makeStyles } from '@material-ui/core/styles'; -export const rowHeight = 35; +export const rowHeight = 36; export const headHeight = 39; -const RAINBOW_BORDER_WIDTH = 3; +const RAINBOW_BORDER_WIDTH = 2; export default makeStyles({ root: { From b1fa4d48cb25aaa4651240cb5ae6a4eb936c6b96 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 3 Dec 2020 14:59:25 -0500 Subject: [PATCH 28/51] tooltip --- src/UI/HoverMenu/index.js | 3 +- .../components/ObjectsTable/ObjectsTable.js | 127 +++++++++++------- src/shared/components/ObjectsTable/styles.js | 13 ++ src/views/Storage/shared/RenderRow/index.js | 2 +- 4 files changed, 95 insertions(+), 50 deletions(-) diff --git a/src/UI/HoverMenu/index.js b/src/UI/HoverMenu/index.js index b8197ee5..5c25a2c9 100644 --- a/src/UI/HoverMenu/index.js +++ b/src/UI/HoverMenu/index.js @@ -27,7 +27,8 @@ const HoverMenu = ({ <> { const { t } = useTranslation(); - const classes = useStyles(); const history = useHistory(); const dispatch = useDispatch(); - const [anchorEl, setAnchorEl] = React.useState(null); + const [isHoverOpen, setIsHoverOpen] = React.useState(false); + const [hoveredElement, setHoveredElement] = React.useState(null); + const initialContextState = { mouseX: null, mouseY: null, @@ -99,12 +101,32 @@ const ObjectsTable = ({ }; const sortedRows = sortAndAddSubfolders(unsortedRows); - const clickedItem = sortedRows.find((row) => row.selected); - const hoveredItemKey = anchorEl && anchorEl.dataset.key; - const hoveredItem = anchorEl && sortedRows.find((row) => (row.fullKey === hoveredItemKey)); + + const getHoveredItemSizeAndPosition = (item) => { + if (!item) { + return {}; + } + return item.getBoundingClientRect(); + }; + + const hoveredItemSizePosition = getHoveredItemSizeAndPosition(hoveredElement); + + const hoveredItemKey = hoveredElement && hoveredElement.dataset.key; + + const hoveredItemIndex = hoveredElement && sortedRows.findIndex((row) => (row.fullKey === hoveredItemKey)); + + const hoveredItem = hoveredElement && sortedRows[hoveredItemIndex]; const hoveredItemOptions = getHoverMenuItems(hoveredItem); + const classes = useStyles({ + hoveredItemOptions, + hoveredItemSizePosition, + hoveredItemIndex, + }); + + const clickedItem = sortedRows.find((row) => row.selected); + const handleRowClick = ({ rowIndex }) => (event) => { event.preventDefault(); @@ -272,20 +294,20 @@ const ObjectsTable = ({ const contextMenuItems = getContextMenuItems(clickedItem, t); - const handlePopoverOpen = (event) => { - setAnchorEl(event.currentTarget); + const handleHoverMenuOpen = (event) => { + setHoveredElement(event.currentTarget); }; - const handlePopoverClose = () => { - setAnchorEl(null); + const handleHoverMenuClose = () => { + setHoveredElement(null); }; - const popoverOpen = Boolean(anchorEl); - const hoverMenuItemOnClick = (id) => { console.log(id); }; + console.log(classes); + return (
( { + return ( + { + setIsHoverOpen(true); + }} + onClose={() => { + setIsHoverOpen(false); + }} + open={hoveredItemKey === row.fullKey} + interactive + classes={{ + tooltip: classes.tooltipRoot, + popper: classes.popperRoot, + }} + title={ + + } + > +
+ {children} + + + ); + } + } > {!loading && !sortedRows.length && } - { - anchorEl && hoveredItemOptions.length > 0 && ( - - - - ) - } ); }; diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index 9a63902d..814071d7 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -1,3 +1,4 @@ +/* eslint-disable */ import { makeStyles } from '@material-ui/core/styles'; export default makeStyles(() => ({ @@ -57,4 +58,16 @@ export default makeStyles(() => ({ sortButton: { padding: 2, }, + tooltipRoot: { + backgroundColor: 'transparent', + }, + popperRoot: { + top: ({ hoveredItemIndex }) => { + const distance = (80 + 36 * hoveredItemIndex); + const top = `${distance}px !important`; + return top; + }, + right: ({ hoveredItemOptions }) => (`${212 + hoveredItemOptions.length * 32}px !important`), + // transform: 'none !important', + }, })); diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index d7e42aca..aa9ef44d 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -106,7 +106,7 @@ const RenderRow = ({ row, arrowOnClick }) => { tabulations={getTabulationAmount()} name={row.name} selected={!!row.selected} - isShared={row.members.length > 0} + isShared={row.members.length > 1} isUploading={row.isUploading} /> Date: Thu, 3 Dec 2020 15:18:53 -0500 Subject: [PATCH 29/51] fixed tooltip --- .../components/ObjectsTable/ObjectsTable.js | 51 +++----------- .../ObjectsTable/components/Tooltip/index.js | 66 +++++++++++++++++++ .../ObjectsTable/components/Tooltip/styles.js | 13 ++++ 3 files changed, 89 insertions(+), 41 deletions(-) create mode 100644 src/shared/components/ObjectsTable/components/Tooltip/index.js create mode 100644 src/shared/components/ObjectsTable/components/Tooltip/styles.js diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index cb56301b..a88a75ca 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -8,7 +8,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faLongArrowUp } from '@fortawesome/pro-regular-svg-icons/faLongArrowUp'; import { faLongArrowDown } from '@fortawesome/pro-regular-svg-icons/faLongArrowDown'; import { faEllipsisH } from '@fortawesome/pro-regular-svg-icons/faEllipsisH'; -import Tooltip from '@material-ui/core/Tooltip'; import Button from '@material-ui/core/Button'; import ButtonBase from '@material-ui/core/ButtonBase'; import Typography from '@material-ui/core/Typography'; @@ -20,10 +19,10 @@ import Table, { TableCell, TableRow } from '@ui/Table'; import ContextMenu, { CONTEXT_OPTION_IDS } from '@ui/ContextMenu'; import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Modal/actions'; import { useTranslation } from 'react-i18next'; -import HoverMenu from '@ui/HoverMenu'; import getContextMenuItems from './utils/get-context-menu'; import getHoverMenuItems from './utils/get-hover-menu'; +import HoverTooltip from './components/Tooltip'; import useStyles from './styles'; const ObjectsTable = ({ @@ -306,8 +305,6 @@ const ObjectsTable = ({ console.log(id); }; - console.log(classes); - return (
( { + (rowProps) => { return ( - { - setIsHoverOpen(true); - }} - onClose={() => { - setIsHoverOpen(false); - }} + - } - > - - {children} - - + /> ); } } diff --git a/src/shared/components/ObjectsTable/components/Tooltip/index.js b/src/shared/components/ObjectsTable/components/Tooltip/index.js new file mode 100644 index 00000000..bd8daa08 --- /dev/null +++ b/src/shared/components/ObjectsTable/components/Tooltip/index.js @@ -0,0 +1,66 @@ +/* eslint-disable */ +import React from 'react'; +import HoverMenu from '@ui/HoverMenu'; +import { useTranslation } from 'react-i18next'; +import Tooltip from '@material-ui/core/Tooltip'; + +import useStyles from './styles'; + +const HoverTooltip = ({ + rowProps, + hoveredItemOptions, + hoveredItemSizePosition, + hoveredItemIndex, + hoverMenuItemOnClick, + ...restProps +}) => { + const { t } = useTranslation(); + const { children, ...props } = rowProps; + + const classes = useStyles({ + hoveredItemOptions, + hoveredItemSizePosition, + hoveredItemIndex, + }); + + return ( + { + // setIsHoverOpen(true); + // }} + // onClose={() => { + // setIsHoverOpen(false); + // }} + interactive + classes={{ + tooltip: classes.tooltipRoot, + popper: classes.popperRoot, + }} + title={ + + } + {...restProps} + > + + {children} + + + ); +}; + +export default HoverTooltip; diff --git a/src/shared/components/ObjectsTable/components/Tooltip/styles.js b/src/shared/components/ObjectsTable/components/Tooltip/styles.js new file mode 100644 index 00000000..3b02fd56 --- /dev/null +++ b/src/shared/components/ObjectsTable/components/Tooltip/styles.js @@ -0,0 +1,13 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles(() => ({ + tooltipRoot: { + backgroundColor: 'transparent', + }, + popperRoot: { + top: ({ hoveredItemIndex }) => (`${(80 + 36 * hoveredItemIndex)}px !important`), + left: 'auto !important', + right: ({ hoveredItemOptions }) => (`${212 + hoveredItemOptions.length * 32}px !important`), + transform: 'none !important', + }, +})); From 53ea19b81e245b4a5db36a0238011aebb093cf52 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 3 Dec 2020 15:40:49 -0500 Subject: [PATCH 30/51] cleanup --- .../components/ObjectsTable/ObjectsTable.js | 35 +++++---- .../ObjectsTable/components/Tooltip/index.js | 77 ++++++++++--------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index a88a75ca..4cdf6ce9 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -1,4 +1,3 @@ -/* eslint-disable */ import React, { useState } from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; @@ -41,7 +40,6 @@ const ObjectsTable = ({ const { t } = useTranslation(); const history = useHistory(); const dispatch = useDispatch(); - const [isHoverOpen, setIsHoverOpen] = React.useState(false); const [hoveredElement, setHoveredElement] = React.useState(null); const initialContextState = { @@ -111,8 +109,10 @@ const ObjectsTable = ({ const hoveredItemSizePosition = getHoveredItemSizeAndPosition(hoveredElement); const hoveredItemKey = hoveredElement && hoveredElement.dataset.key; - - const hoveredItemIndex = hoveredElement && sortedRows.findIndex((row) => (row.fullKey === hoveredItemKey)); + + const hoveredItemIndex = hoveredElement && sortedRows.findIndex( + (row) => (row.fullKey === hoveredItemKey), + ); const hoveredItem = hoveredElement && sortedRows[hoveredItemIndex]; @@ -370,7 +370,10 @@ const ObjectsTable = ({ key={row.id} data-key={row.fullKey} className={classNames(classes.row, { - [classes.selectedAndUploading]: (row.isUploading && row.selected) || (row.isUploading && (hoveredItemKey === row.fullKey)), + [classes.selectedAndUploading]: ( + (row.isUploading && row.selected) + || (row.isUploading && (hoveredItemKey === row.fullKey)) + ), [classes.selected]: row.selected, [classes.error]: row.error && !row.isUploading, })} @@ -378,18 +381,16 @@ const ObjectsTable = ({ onContextMenu={handleRowRightClick({ row })} onDoubleClick={handleDoubleRowClick({ row })} component={ - (rowProps) => { - return ( - - ); - } + (rowProps) => ( + + ) } > { - // setIsHoverOpen(true); - // }} - // onClose={() => { - // setIsHoverOpen(false); - // }} - interactive - classes={{ - tooltip: classes.tooltipRoot, - popper: classes.popperRoot, - }} - title={ - - } - {...restProps} - > - - {children} - - + interactive + classes={{ + tooltip: classes.tooltipRoot, + popper: classes.popperRoot, + }} + title={( + + )} + {...restProps} + > + + {children} + + ); }; +HoverTooltip.defaultProps = { + hoveredItemIndex: 0, + hoveredItemSizePosition: {}, +}; + +HoverTooltip.propTypes = { + rowProps: PropTypes.shape({ + children: PropTypes.node, + props: PropTypes.shape({}), + }).isRequired, + hoveredItemOptions: PropTypes.arrayOf( + PropTypes.shape({}), + ).isRequired, + hoverMenuItemOnClick: PropTypes.func.isRequired, + hoveredItemIndex: PropTypes.number, + hoveredItemSizePosition: PropTypes.shape({}), +}; + export default HoverTooltip; From e3f332c9576676cfb66d02ac5d66df7945c980b2 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Thu, 3 Dec 2020 15:54:08 -0500 Subject: [PATCH 31/51] removed forced isUploading value --- .../components/ObjectsTable/ObjectsTable.js | 16 +--------------- .../ObjectsTable/components/Tooltip/index.js | 5 ----- .../ObjectsTable/components/Tooltip/styles.js | 2 +- src/shared/components/ObjectsTable/styles.js | 12 ------------ src/utils/object-presenter.js | 2 -- 5 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 4cdf6ce9..2e8d30d1 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -99,15 +99,6 @@ const ObjectsTable = ({ const sortedRows = sortAndAddSubfolders(unsortedRows); - const getHoveredItemSizeAndPosition = (item) => { - if (!item) { - return {}; - } - return item.getBoundingClientRect(); - }; - - const hoveredItemSizePosition = getHoveredItemSizeAndPosition(hoveredElement); - const hoveredItemKey = hoveredElement && hoveredElement.dataset.key; const hoveredItemIndex = hoveredElement && sortedRows.findIndex( @@ -118,11 +109,7 @@ const ObjectsTable = ({ const hoveredItemOptions = getHoverMenuItems(hoveredItem); - const classes = useStyles({ - hoveredItemOptions, - hoveredItemSizePosition, - hoveredItemIndex, - }); + const classes = useStyles(); const clickedItem = sortedRows.find((row) => row.selected); @@ -385,7 +372,6 @@ const ObjectsTable = ({ ({ popperRoot: { top: ({ hoveredItemIndex }) => (`${(80 + 36 * hoveredItemIndex)}px !important`), left: 'auto !important', - right: ({ hoveredItemOptions }) => (`${212 + hoveredItemOptions.length * 32}px !important`), + right: 220, transform: 'none !important', }, })); diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index 814071d7..230b811a 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -58,16 +58,4 @@ export default makeStyles(() => ({ sortButton: { padding: 2, }, - tooltipRoot: { - backgroundColor: 'transparent', - }, - popperRoot: { - top: ({ hoveredItemIndex }) => { - const distance = (80 + 36 * hoveredItemIndex); - const top = `${distance}px !important`; - return top; - }, - right: ({ hoveredItemOptions }) => (`${212 + hoveredItemOptions.length * 32}px !important`), - // transform: 'none !important', - }, })); diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 3c4436ac..54128ac4 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -46,8 +46,6 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), - error: false, - isUploading: true, }; }; From 0f7c0a50400bbd47d99f67fae9776288f09bba2a Mon Sep 17 00:00:00 2001 From: Guillermo Puente Date: Fri, 4 Dec 2020 13:06:11 -0300 Subject: [PATCH 32/51] Added shared row --- .../LoadingCell/loading-cell.stories.js | 1 + .../Table/components/MemberCell/MemberCell.js | 44 +++++++++++ src/UI/Table/components/MemberCell/index.js | 1 + .../MemberCell/member-cell.stories.js | 39 ++++++++++ src/UI/Table/components/MemberCell/styles.js | 17 ++++ src/UI/Table/components/index.js | 1 + src/UI/Table/table.stories.js | 2 +- src/locales/en/translation.json | 1 + src/views/Storage/SharedBy/index.js | 9 ++- src/views/Storage/shared/RenderRow/index.js | 23 ++---- .../shared/ShareRenderRow/SharedRenderRow.js | 77 +++++++++++++++++++ .../Storage/shared/ShareRenderRow/index.js | 1 + .../Storage/shared/ShareRenderRow/styles.js | 26 +++++++ .../shared/components/FileTable/index.js | 28 ++++--- src/views/Storage/shared/getTableHeads.js | 30 +++++++- .../Storage/shared/helpers/get-row-offset.js | 12 +++ 16 files changed, 280 insertions(+), 32 deletions(-) create mode 100644 src/UI/Table/components/MemberCell/MemberCell.js create mode 100644 src/UI/Table/components/MemberCell/index.js create mode 100644 src/UI/Table/components/MemberCell/member-cell.stories.js create mode 100644 src/UI/Table/components/MemberCell/styles.js create mode 100644 src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js create mode 100644 src/views/Storage/shared/ShareRenderRow/index.js create mode 100644 src/views/Storage/shared/ShareRenderRow/styles.js create mode 100644 src/views/Storage/shared/helpers/get-row-offset.js diff --git a/src/UI/Table/components/LoadingCell/loading-cell.stories.js b/src/UI/Table/components/LoadingCell/loading-cell.stories.js index c505060e..dbff3a9c 100644 --- a/src/UI/Table/components/LoadingCell/loading-cell.stories.js +++ b/src/UI/Table/components/LoadingCell/loading-cell.stories.js @@ -6,6 +6,7 @@ import LoadingCell from './index'; const categoryName = 'ElementalComponents/Table'; storiesOf(categoryName, module).add('LoadingCell', () => { + const defaultProps = {}; return (
diff --git a/src/UI/Table/components/MemberCell/MemberCell.js b/src/UI/Table/components/MemberCell/MemberCell.js new file mode 100644 index 00000000..014cc525 --- /dev/null +++ b/src/UI/Table/components/MemberCell/MemberCell.js @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Typography from '@material-ui/core/Typography'; + +import useStyles from './styles'; +import TableCell from '../TableCell'; +import Avatar from '../../../Avatar'; + +const MemberCell = (props) => { + const { + username, + avatarUrl, + ...tableCellProps + } = props; + + const classes = useStyles(); + + return ( + // eslint-disable-next-line react/jsx-props-no-spreading + +
+ + + {username} + +
+
+ ); +}; + +MemberCell.defaultProps = { + username: '', + avatarUrl: null, +}; + +MemberCell.propTypes = { + username: PropTypes.string, + avatarUrl: PropTypes.string, +}; + +export default MemberCell; diff --git a/src/UI/Table/components/MemberCell/index.js b/src/UI/Table/components/MemberCell/index.js new file mode 100644 index 00000000..e0ba8f09 --- /dev/null +++ b/src/UI/Table/components/MemberCell/index.js @@ -0,0 +1 @@ +export { default } from './MemberCell'; diff --git a/src/UI/Table/components/MemberCell/member-cell.stories.js b/src/UI/Table/components/MemberCell/member-cell.stories.js new file mode 100644 index 00000000..517f5e1b --- /dev/null +++ b/src/UI/Table/components/MemberCell/member-cell.stories.js @@ -0,0 +1,39 @@ +import React from 'react'; +import Table from '@material-ui/core/Table'; +import { storiesOf } from '@storybook/react'; +import { text } from '@storybook/addon-knobs'; +import TableBody from '@material-ui/core/TableBody'; +import TableHead from '@material-ui/core/TableHead'; +import Typography from '@material-ui/core/Typography'; + +import MemberCell from './index'; +import TableRow from '../TableRow'; +import TableCell from '../TableCell'; + +const categoryName = 'ElementalComponents/Table'; + +storiesOf(categoryName, module).add('MemberCell', () => { + const defaultProps = { + avatarUrl: text('imageUrl', 'http://preview.byaviators.com/template/superlist/assets/img/tmp/agent-2.jpg'), + username: text('username', 'Grant Hehmen'), + }; + + const children = text('children', 'TechDocsV2.docx'); + + return ( +
+ + + + Name + + + + + + + + +
+ ); +}); diff --git a/src/UI/Table/components/MemberCell/styles.js b/src/UI/Table/components/MemberCell/styles.js new file mode 100644 index 00000000..4be3a44c --- /dev/null +++ b/src/UI/Table/components/MemberCell/styles.js @@ -0,0 +1,17 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + container: { + color: theme.palette.palette.gray1, + display: 'flex', + '& > *': { + marginRight: 6, + }, + }, + avatarImg: { + width: 17, + height: 17, + borderRadius: '50%', + objectFit: 'cover', + }, +})); diff --git a/src/UI/Table/components/index.js b/src/UI/Table/components/index.js index 0eca1935..321a4272 100644 --- a/src/UI/Table/components/index.js +++ b/src/UI/Table/components/index.js @@ -5,3 +5,4 @@ export { default as TableCell } from './TableCell'; export { default as IconsCell } from './IconsCell'; export { default as IconsTooltip } from './IconsTooltip'; export { default as LoadingCell } from './LoadingCell'; +export { default as MemberCell } from './MemberCell'; diff --git a/src/UI/Table/table.stories.js b/src/UI/Table/table.stories.js index 283b0ccf..0a722d60 100644 --- a/src/UI/Table/table.stories.js +++ b/src/UI/Table/table.stories.js @@ -6,7 +6,7 @@ import { object, boolean } from '@storybook/addon-knobs'; import Table from './index'; import { - FileNameCell, + FileCell, TableRow, TableCell, IconsCell, diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 64049b4b..e9eeffca 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -126,6 +126,7 @@ "members": "Members", "lastModified": "Last Modified", "size": "Size", + "sharedBy": "Shared By", "tooltip": "The first icon is blue if the file is in local storage. The second is green if the file is in space storage. The last icon shows the amount of users the file has been shared with." }, "error": { diff --git a/src/views/Storage/SharedBy/index.js b/src/views/Storage/SharedBy/index.js index 5fbbb96a..e48b669b 100644 --- a/src/views/Storage/SharedBy/index.js +++ b/src/views/Storage/SharedBy/index.js @@ -5,12 +5,13 @@ import { useTranslation } from 'react-i18next'; import { fetchSharedObjects } from '@events/objects'; import { useHistory, matchPath, useLocation } from 'react-router-dom'; -import { openModal, FILE_LINK_PASSWORD } from '@shared/components/Modal/actions'; -import mapBreadcrumbs from '@shared/utils/map-breadcrumbs'; import Breadcrumbs from '@ui/Breadcrumbs'; +import mapBreadcrumbs from '@shared/utils/map-breadcrumbs'; +import { openModal, FILE_LINK_PASSWORD } from '@shared/components/Modal/actions'; -import { FileTable, HeaderNav, FilesErrors } from '../shared/components'; import useStyles from './styles'; +import SharedRenderRow from '../shared/ShareRenderRow'; +import { FileTable, HeaderNav, FilesErrors } from '../shared/components'; const SharedWithMeView = () => { const classes = useStyles(); @@ -60,6 +61,8 @@ const SharedWithMeView = () => { bucket="shared-with-me" baseRedirectUrl="/storage/shared-by" fetchDir={fetchSharedObjects} + renderRow={SharedRenderRow} + type="shared" />
); diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 780fae66..0259adf5 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -1,31 +1,22 @@ import React from 'react'; import moment from 'moment'; import PropTypes from 'prop-types'; +import classnames from 'classnames'; import { formatBytes } from '@utils'; import { useLocation } from 'react-router-dom'; -import Typography from '@material-ui/core/Typography'; import { TableCell, FileNameCell } from '@ui/Table'; -import classnames from 'classnames'; +import Typography from '@material-ui/core/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; import { faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons/faSpinnerThird'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + import useStyles from './styles'; +import getRowOffset from '../helpers/get-row-offset'; const RenderRow = ({ row, arrowOnClick, disableOffset }) => { const location = useLocation(); const classes = useStyles(); - const getTabulationAmount = () => { - const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); - const locationWithoutRoot = locationWithRoot.slice(2, locationWithRoot.length); - const rootFolderAmount = locationWithoutRoot.length; - const { key = '' } = row; - const currentItemFolderAmount = key.split('/').length; - const tabulations = currentItemFolderAmount - rootFolderAmount - 1; - - return tabulations; - }; - const getSizeIcon = () => { if (row.isAvailableInSpace) { return ( @@ -57,14 +48,14 @@ const RenderRow = ({ row, arrowOnClick, disableOffset }) => { src={`file:${row.key}`} arrowOnClick={arrowOnClick} expanded={row.expanded} - tabulations={getTabulationAmount()} + tabulations={getRowOffset(location, row)} name={row.name} selected={!!row.selected} isShared={row.members.length > 0} /> {getSizeIcon()} diff --git a/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js b/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js new file mode 100644 index 00000000..1ee9e36c --- /dev/null +++ b/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js @@ -0,0 +1,77 @@ +import React, { useEffect } from 'react'; +import get from 'lodash/get'; +import moment from 'moment'; +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import { useLocation } from 'react-router-dom'; +import Typography from '@material-ui/core/Typography'; +import { TableCell, FileNameCell, MemberCell } from '@ui/Table'; +import { getIdentitiesByAddress } from '@events/identities'; + +import getRowOffset from '../helpers/get-row-offset'; + +const ShareRenderRow = ({ row, arrowOnClick }) => { + const location = useLocation(); + const members = get(row, 'members', []) || []; + const [userAddress, identities] = useSelector((state) => [state.user.address, state.identities]); + + const firstMember = members.find((item) => item.address !== userAddress); + const firstMemberIdentity = get(identities, `identities.${firstMember.publicKey}`, {}); + + useEffect(() => { + if (!firstMemberIdentity.username) { + getIdentitiesByAddress({ + addresses: [firstMember.address], + }); + } + }, []); + + return ( + <> + 0} + /> + + + + {moment(row.lastModified).format('MMM D, YYYY')} + {/* ^ just for testing, after POC should be used line below */} + {/* {formatMonthDayYear(row.lastModified)} */} + + + + ); +}; + +ShareRenderRow.defaultProps = { + arrowOnClick: () => {}, +}; + +ShareRenderRow.propTypes = { + row: PropTypes.shape({ + shareAmount: PropTypes.number, + ext: PropTypes.string, + key: PropTypes.string, + name: PropTypes.string, + size: PropTypes.number, + lastModified: PropTypes.instanceOf(Date), + isLocallyAvailable: PropTypes.bool, + isAvailableInSpace: PropTypes.bool, + expanded: PropTypes.bool, + selected: PropTypes.bool, + members: PropTypes.array, + }).isRequired, + arrowOnClick: PropTypes.func, +}; + +export default ShareRenderRow; diff --git a/src/views/Storage/shared/ShareRenderRow/index.js b/src/views/Storage/shared/ShareRenderRow/index.js new file mode 100644 index 00000000..fc8c5b1a --- /dev/null +++ b/src/views/Storage/shared/ShareRenderRow/index.js @@ -0,0 +1 @@ +export { default } from './SharedRenderRow'; diff --git a/src/views/Storage/shared/ShareRenderRow/styles.js b/src/views/Storage/shared/ShareRenderRow/styles.js new file mode 100644 index 00000000..3c6ec009 --- /dev/null +++ b/src/views/Storage/shared/ShareRenderRow/styles.js @@ -0,0 +1,26 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export default makeStyles((theme) => ({ + iconSizeContainer: { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + }, + iconContainer: { + width: 25, + }, + checkIcon: { + fontSize: 11, + color: theme.palette.palette.green2, + }, + notAvailableLocally: { + color: '#7F8185', + }, + loadingIcon: { + fontSize: 11, + color: theme.palette.palette.spaceBlue, + }, + highlighted: { + color: theme.palette.palette.spaceBlue, + }, +})); diff --git a/src/views/Storage/shared/components/FileTable/index.js b/src/views/Storage/shared/components/FileTable/index.js index 71a84d78..fbbdee05 100644 --- a/src/views/Storage/shared/components/FileTable/index.js +++ b/src/views/Storage/shared/components/FileTable/index.js @@ -10,16 +10,18 @@ import { UPDATE_OBJECTS } from '@reducers/storage'; import ObjectsTable from '@shared/components/ObjectsTable'; import { SHARING_MODAL } from '@shared/components/Modal/actions'; -import renderLoadingRows from '../../render-loading-rows'; import RenderRow from '../../RenderRow'; import getTableHeads from '../../getTableHeads'; +import renderLoadingRows from '../../render-loading-rows'; const FileTable = ({ + type, bucket, prefix, - baseRedirectUrl, - EmptyState, fetchDir, + renderRow, + EmptyState, + baseRedirectUrl, disableRowOffset, }) => { const dispatch = useDispatch(); @@ -77,8 +79,8 @@ const FileTable = ({ bucket={bucket} loading={rows.length <= 0 && loading} renderLoadingRows={renderLoadingRows} - renderRow={RenderRow} - heads={getTableHeads(t)} + renderRow={renderRow} + heads={getTableHeads(t, type)} getRedirectUrl={getRedirectUrl} onDropzoneDrop={onDropzoneDrop} onOutsideClick={handleTableOutsideClick} @@ -90,19 +92,23 @@ const FileTable = ({ }; FileTable.defaultProps = { - baseRedirectUrl: '/storage/files', - EmptyState: () => null, fetchDir: () => null, + renderRow: RenderRow, + EmptyState: () => null, disableRowOffset: false, + baseRedirectUrl: '/storage/files', + type: 'personal', }; FileTable.propTypes = { - bucket: PropTypes.string.isRequired, - prefix: PropTypes.string.isRequired, - baseRedirectUrl: PropTypes.string, - EmptyState: PropTypes.elementType, fetchDir: PropTypes.func, + renderRow: PropTypes.elementType, + EmptyState: PropTypes.elementType, disableRowOffset: PropTypes.bool, + baseRedirectUrl: PropTypes.string, + bucket: PropTypes.string.isRequired, + prefix: PropTypes.string.isRequired, + type: PropTypes.oneOf(['personal', 'shared']), }; export default FileTable; diff --git a/src/views/Storage/shared/getTableHeads.js b/src/views/Storage/shared/getTableHeads.js index ce6b9376..768c1354 100644 --- a/src/views/Storage/shared/getTableHeads.js +++ b/src/views/Storage/shared/getTableHeads.js @@ -1,4 +1,4 @@ -export default (t) => [ +const getPersonalHeaders = (t) => [ { id: 'name', width: '50%', @@ -19,3 +19,31 @@ export default (t) => [ isSortable: true, }, ]; + +const getSharedHeaders = (t) => [ + { + id: 'name', + width: '50%', + title: t('modules.storage.fileTable.head.name'), + isSortable: true, + }, + { + id: 'size', + width: '25%', + title: t('modules.storage.fileTable.head.sharedBy'), + isSortable: true, + }, + { + id: 'lastModified', + width: '25%', + title: t('modules.storage.fileTable.head.lastModified'), + isSortable: true, + }, +]; + +const headerTypes = { + shared: getSharedHeaders, + personal: getPersonalHeaders, +}; + +export default (t, type) => headerTypes[type](t); diff --git a/src/views/Storage/shared/helpers/get-row-offset.js b/src/views/Storage/shared/helpers/get-row-offset.js new file mode 100644 index 00000000..97ad0af3 --- /dev/null +++ b/src/views/Storage/shared/helpers/get-row-offset.js @@ -0,0 +1,12 @@ +const getTabulationAmount = (location, row) => { + const locationWithRoot = location.pathname.split('/').filter((folder) => folder !== ''); + const locationWithoutRoot = locationWithRoot.slice(2, locationWithRoot.length); + const rootFolderAmount = locationWithoutRoot.length; + const { key = '' } = row; + const currentItemFolderAmount = key.split('/').length; + const tabulations = currentItemFolderAmount - rootFolderAmount - 1; + + return tabulations; +}; + +export default getTabulationAmount; From aa1932d0712fcf94fa5a6caae1c90478cbd3599e Mon Sep 17 00:00:00 2001 From: Guillermo Puente Date: Fri, 4 Dec 2020 14:13:24 -0300 Subject: [PATCH 33/51] upgraded space client ver 1.19 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 99bdac23..9c8b4c58 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "build-storybook": "build-storybook -s public" }, "dependencies": { - "@fleekhq/space-client": "^1.1.8", + "@fleekhq/space-client": "^1.1.9", "@fortawesome/fontawesome-svg-core": "^1.2.28", "@fortawesome/free-brands-svg-icons": "^5.13.0", "@fortawesome/free-solid-svg-icons": "^5.13.0", diff --git a/yarn.lock b/yarn.lock index 482335ea..ac496045 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1682,10 +1682,10 @@ "@ethersproject/properties" "^5.0.3" "@ethersproject/strings" "^5.0.4" -"@fleekhq/space-client@^1.1.8": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@fleekhq/space-client/-/space-client-1.1.8.tgz#9e2e69703008df1eaed0d4931bdf462e986df670" - integrity sha512-to7UW9naEfYIlIqoT2dQ96grWm3zzYFK5r9yHJUg65B+kjpd9PpSLMyCDdzSdT7OrVP4hcy0nHtJbG2jeBqpxQ== +"@fleekhq/space-client@^1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@fleekhq/space-client/-/space-client-1.1.9.tgz#8ea86b49cbba51dd736e0be24d1defa45962cfa2" + integrity sha512-sHnDb0zdrhCxUKPkxnPVg1G2Mq+nTpMvncXm4C58SMd6awmxLPgFWp/Nte6QUW8CJvSQS3sWZMfe35Pt3WYDaA== dependencies: "@types/google-protobuf" "^3.7.2" google-protobuf "^3.12.2" From 07804d9fccd3e4ae6388a0e4ab317187471b5db3 Mon Sep 17 00:00:00 2001 From: Guillermo Puente Date: Fri, 4 Dec 2020 17:15:35 -0300 Subject: [PATCH 34/51] Added open file error --- src/events/objects.js | 40 +++++++++++++++++++ src/reducers/storage/bucket.js | 19 +++++++++ src/reducers/storage/index.js | 2 + .../DetailsPanel/components/Header/index.js | 1 + .../components/ObjectsTable/ObjectsTable.js | 1 + src/utils/object-presenter.js | 1 + src/views/Storage/Files/index.js | 8 ++-- .../shared/components/FilesErrors/index.js | 40 +++++++++---------- .../shared/components/FilesErrors/styles.js | 5 +++ .../shared/components/HeaderNav/index.js | 1 + 10 files changed, 93 insertions(+), 25 deletions(-) diff --git a/src/events/objects.js b/src/events/objects.js index 949c5add..c76ba360 100644 --- a/src/events/objects.js +++ b/src/events/objects.js @@ -8,6 +8,7 @@ import { SET_ERROR_BUCKET, SET_LOADING_STATE, SET_OPEN_ERROR_BUCKET, + UPDATE_OBJECT, } from '@reducers/storage'; import { SEARCH_ACTION_TYPES } from '@reducers/search'; import { OPEN_PUBLIC_FILE_ACTION_TYPES } from '@reducers/open-public-file'; @@ -36,6 +37,9 @@ const DELETE_OBJECT_EVENT = `${EVENT_PREFIX}:deleteObject`; const DELETE_OBJECT_ERROR_EVENT = `${EVENT_PREFIX}:deleteObject:error`; const DELETE_OBJECT_SUCCESS_EVENT = `${EVENT_PREFIX}:deleteObject:success`; +const ERROR_TIMEOUT = 5000; +let openErrorTimeout = null; + const registerObjectsEvents = () => { ipcRenderer.on(SUCCESS_EVENT, (event, payload) => { const entries = get(payload, 'entries', []) || []; @@ -144,6 +148,40 @@ ipcRenderer.on(OPEN_ERROR_EVENT, (event, payload) => { }, type: SET_OPEN_ERROR_BUCKET, }); + + const baseErrorPayload = { + fullKey: payload.fullKey, + bucket: payload.bucket === 'personal' ? 'personal' : 'shared-with-me', + }; + + store.dispatch({ + type: UPDATE_OBJECT, + payload: { + error: true, + ...baseErrorPayload, + }, + }); + + setTimeout(() => { + store.dispatch({ + type: UPDATE_OBJECT, + payload: { + error: false, + ...baseErrorPayload, + }, + }); + }, ERROR_TIMEOUT); + + window.clearTimeout(openErrorTimeout); + openErrorTimeout = setTimeout(() => { + store.dispatch({ + payload: { + ...payload, + error: false, + }, + type: SET_OPEN_ERROR_BUCKET, + }); + }, ERROR_TIMEOUT); }); ipcRenderer.on(DELETE_OBJECT_SUCCESS_EVENT, () => { @@ -195,6 +233,7 @@ export const openObject = ({ path, dbId, name, + fullKey, ipfsHash, isPublicLink = false, bucket = 'personal', @@ -210,6 +249,7 @@ export const openObject = ({ ipcRenderer.send(OPEN_EVENT, { path, bucket, + fullKey, ...(dbId && { dbId }), }); }; diff --git a/src/reducers/storage/bucket.js b/src/reducers/storage/bucket.js index 1d3c8bf9..c60437b4 100644 --- a/src/reducers/storage/bucket.js +++ b/src/reducers/storage/bucket.js @@ -7,6 +7,7 @@ export const ADD_OBJECT = 'ADD_OBJECT'; export const STORE_OBJECTS = 'STORE_OBJECTS'; export const DELETE_OBJECT = 'DELETE_OBJECT'; export const DELETE_OBJECT_AND_CHILDREN = 'DELETE_OBJECT_AND_CHILDREN'; +export const UPDATE_OBJECT = 'UPDATE_OBJECT'; export const UPDATE_OBJECTS = 'UPDATE_OBJECTS'; export const STORE_BUCKETS = 'STORE_BUCKETS'; export const UPDATE_OR_ADD_OBJECT = 'UPDATE_OR_ADD_OBJECT'; @@ -148,6 +149,24 @@ export default (state = DEFAULT_STATE, action) => { }; } + case UPDATE_OBJECT: { + const updatedObjects = state.objects.map((obj) => { + if (obj.fullKey === action.payload.fullKey) { + return { + ...obj, + ...action.payload, + }; + } + + return obj; + }); + + return { + ...state, + objects: updatedObjects, + }; + } + case UPDATE_OBJECTS: { const newObjs = state.objects.filter((obj) => ( action.payload.findIndex((newObj) => obj.id === newObj.id) === -1 diff --git a/src/reducers/storage/index.js b/src/reducers/storage/index.js index 0fb984f7..1fc8bfc1 100644 --- a/src/reducers/storage/index.js +++ b/src/reducers/storage/index.js @@ -6,6 +6,7 @@ import bucketReducer, { STORE_OBJECTS, DELETE_OBJECT, DELETE_OBJECT_AND_CHILDREN, + UPDATE_OBJECT, UPDATE_OBJECTS, STORE_BUCKETS, SET_LOADING_STATE_BUCKET, @@ -160,6 +161,7 @@ export default (state = DEFAULT_STATE, action) => { case ADD_OBJECT: case DELETE_OBJECT: case DELETE_OBJECT_AND_CHILDREN: + case UPDATE_OBJECT: case UPDATE_OBJECTS: case UPDATE_OR_ADD_OBJECT: case UPDATE_SHARE_AMOUNT_OBJECTS: diff --git a/src/shared/components/DetailsPanel/components/Header/index.js b/src/shared/components/DetailsPanel/components/Header/index.js index efa3aae8..1cb7279b 100644 --- a/src/shared/components/DetailsPanel/components/Header/index.js +++ b/src/shared/components/DetailsPanel/components/Header/index.js @@ -32,6 +32,7 @@ const DetailsPanelHeader = ({ objects }) => { name: file.name, ipfsHash: file.ipfsHash, isPublicLink: file.isPublicLink, + fullKey: file.fullKey, }); } }; diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 2e7c3aff..0e04b87a 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -167,6 +167,7 @@ const ObjectsTable = ({ name: row.name, ipfsHash: row.ipfsHash, isPublicLink: row.isPublicLink, + fullKey: row.fullKey, }); newRows = sortedRows.map((_row) => ({ diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 54128ac4..786508c5 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -36,6 +36,7 @@ const objectPresenter = (obj = {}, isRootDir = false) => { members, created, bytesSize, + error: false, lastModified, isPublicLink, isLocallyAvailable, diff --git a/src/views/Storage/Files/index.js b/src/views/Storage/Files/index.js index b8b2d17e..4c691da8 100644 --- a/src/views/Storage/Files/index.js +++ b/src/views/Storage/Files/index.js @@ -28,10 +28,6 @@ const StorageMainView = () => { return (
- fetchDir(prefix)} - /> { EmptyState={EmptyState} fetchDir={fetchDir} /> + fetchDir(prefix)} + />
); }; diff --git a/src/views/Storage/shared/components/FilesErrors/index.js b/src/views/Storage/shared/components/FilesErrors/index.js index e63bba82..64bb42b3 100644 --- a/src/views/Storage/shared/components/FilesErrors/index.js +++ b/src/views/Storage/shared/components/FilesErrors/index.js @@ -1,13 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import ErrorCard from '@ui/ErrorCard'; import { useSelector } from 'react-redux'; import ErrorCardButton from '@ui/ErrorCardButton'; import { useTranslation } from 'react-i18next'; -import store from '../../../../../store'; -import { SET_OPEN_ERROR_BUCKET } from '../../../../../reducers/storage/bucket'; import useStyles from './styles'; +/* eslint-disable react/jsx-props-no-spreading */ const FilesErrors = ({ bucket, fetchObjects, @@ -35,16 +36,6 @@ const FilesErrors = ({ errors.push({ id: 'open-error', message: t('modules.storage.fileTable.openError.message'), - buttonText: t('modules.storage.fileTable.openError.buttonText'), - buttonOnClick: () => { - store.dispatch({ - payload: { - bucket, - error: false, - }, - type: SET_OPEN_ERROR_BUCKET, - }); - }, }); } @@ -52,15 +43,22 @@ const FilesErrors = ({ <> {errors.length > 0 && (
- {errors.map((error) => ( -
- -
- ))} + {errors.map(({ id, ...errorProps }) => { + const isOpenError = id === 'open-error'; + const ErrorComponent = isOpenError ? ErrorCard : ErrorCardButton; + + return ( +
+ +
+ ); + })}
)} diff --git a/src/views/Storage/shared/components/FilesErrors/styles.js b/src/views/Storage/shared/components/FilesErrors/styles.js index 72a74717..58df0bc1 100644 --- a/src/views/Storage/shared/components/FilesErrors/styles.js +++ b/src/views/Storage/shared/components/FilesErrors/styles.js @@ -7,4 +7,9 @@ export default makeStyles({ errorBoxContainer: { marginBottom: 10, }, + openError: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, }); diff --git a/src/views/Storage/shared/components/HeaderNav/index.js b/src/views/Storage/shared/components/HeaderNav/index.js index f20cd14a..1a39b7f0 100644 --- a/src/views/Storage/shared/components/HeaderNav/index.js +++ b/src/views/Storage/shared/components/HeaderNav/index.js @@ -69,6 +69,7 @@ const HeaderNav = () => { name: item.name, ipfsHash: item.ipfsHash, isPublicLink: item.isPublicLink, + fullKey: item.fullKey, }); }; From 657b8cedcbc9f53c85158574e1b071018a5c11f3 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 4 Dec 2020 15:26:41 -0500 Subject: [PATCH 35/51] use less useStates --- .../components/ObjectsTable/ObjectsTable.js | 19 +++++++++++-------- src/utils/object-presenter.js | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 4cd88dae..35781104 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -1,4 +1,6 @@ +/* eslint-disable */ import React, { useState } from 'react'; +import get from 'lodash/get'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import { useDispatch } from 'react-redux'; @@ -41,7 +43,7 @@ const ObjectsTable = ({ const { t } = useTranslation(); const history = useHistory(); const dispatch = useDispatch(); - const [hoveredElement, setHoveredElement] = React.useState(null); + const [hoveredItemKey, setHoveredItemKey] = React.useState(null); const location = useLocation(); const initialContextState = { @@ -101,13 +103,11 @@ const ObjectsTable = ({ const sortedRows = sortAndAddSubfolders(unsortedRows); - const hoveredItemKey = hoveredElement && hoveredElement.dataset.key; - - const hoveredItemIndex = hoveredElement && sortedRows.findIndex( + const hoveredItemIndex = hoveredItemKey && sortedRows.findIndex( (row) => (row.fullKey === hoveredItemKey), ); - const hoveredItem = hoveredElement && sortedRows[hoveredItemIndex]; + const hoveredItem = hoveredItemKey && sortedRows[hoveredItemIndex]; const hoveredItemOptions = getHoverMenuItems(hoveredItem); @@ -283,11 +283,14 @@ const ObjectsTable = ({ const contextMenuItems = getContextMenuItems(clickedItem, t); const handleHoverMenuOpen = (event) => { - setHoveredElement(event.currentTarget); + const newItemKey = get(event, 'target.parentNode.dataset.key'); + if ((newItemKey && (newItemKey !== hoveredItemKey)) || !hoveredItemKey) { + setHoveredItemKey(newItemKey); + } }; const handleHoverMenuClose = () => { - setHoveredElement(null); + setHoveredItemKey(null); }; const hoverMenuItemOnClick = (id) => { @@ -366,7 +369,7 @@ const ObjectsTable = ({ )} renderRow={({ row, rowIndex }) => ( { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), + isUploading: true, }; }; From 0265c0f0b2a52eaa5dc77fa6653b240beb8dbd47 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 4 Dec 2020 18:09:56 -0500 Subject: [PATCH 36/51] remove eslint disable --- src/shared/components/ObjectsTable/ObjectsTable.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index 35781104..6b509329 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -1,4 +1,3 @@ -/* eslint-disable */ import React, { useState } from 'react'; import get from 'lodash/get'; import classNames from 'classnames'; From dcee5bda184d9fce6e53c2a178a42a7de0171ba2 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 4 Dec 2020 18:14:41 -0500 Subject: [PATCH 37/51] remove isUploading --- src/utils/object-presenter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 3e021343..54128ac4 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -46,7 +46,6 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), - isUploading: true, }; }; From 7dcc50a3e89929e3d24c1e5113c637d9c28eda8c Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Fri, 4 Dec 2020 18:26:14 -0500 Subject: [PATCH 38/51] remove typography --- src/views/Storage/shared/RenderRow/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 0f150958..78b34bca 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -7,7 +7,7 @@ import Typography from '@material-ui/core/Typography'; import { useTranslation } from 'react-i18next'; import { TableCell, FileNameCell } from '@ui/Table'; import { formatBytes, getTabulations } from '@utils'; -import Typography from '@material-ui/core/Typography'; + import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; import { faExclamationCircle } from '@fortawesome/pro-solid-svg-icons/faExclamationCircle'; From b04b53026e16e31fad454c4c57a2eaac35912dc0 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 7 Dec 2020 12:50:58 -0500 Subject: [PATCH 39/51] fix performance of hovers --- .../components/ObjectsTable/ObjectsTable.js | 92 +++---------------- src/shared/components/ObjectsTable/styles.js | 18 ++-- .../ObjectsTable/utils/hover-menu-on-click.js | 5 + src/utils/object-presenter.js | 1 + src/views/Storage/shared/RenderRow/index.js | 75 ++++++++++++++- src/views/Storage/shared/RenderRow/styles.js | 9 ++ .../shared/ShareRenderRow/SharedRenderRow.js | 85 ++++++++++++++++- .../Storage/shared/ShareRenderRow/styles.js | 9 ++ 8 files changed, 196 insertions(+), 98 deletions(-) create mode 100644 src/shared/components/ObjectsTable/utils/hover-menu-on-click.js diff --git a/src/shared/components/ObjectsTable/ObjectsTable.js b/src/shared/components/ObjectsTable/ObjectsTable.js index ed291c30..396ed682 100644 --- a/src/shared/components/ObjectsTable/ObjectsTable.js +++ b/src/shared/components/ObjectsTable/ObjectsTable.js @@ -1,14 +1,10 @@ import React, { useState } from 'react'; -import get from 'lodash/get'; -import classNames from 'classnames'; import PropTypes from 'prop-types'; import { useDispatch } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faLongArrowUp } from '@fortawesome/pro-regular-svg-icons/faLongArrowUp'; import { faLongArrowDown } from '@fortawesome/pro-regular-svg-icons/faLongArrowDown'; -import { faEllipsisH } from '@fortawesome/pro-regular-svg-icons/faEllipsisH'; -import Button from '@material-ui/core/Button'; import ButtonBase from '@material-ui/core/ButtonBase'; import Typography from '@material-ui/core/Typography'; import { openObject } from '@events'; @@ -21,8 +17,7 @@ import { openModal, SHARING_MODAL, DELETE_OBJECT } from '@shared/components/Moda import { useTranslation } from 'react-i18next'; import { getTabulations } from '@utils'; import getContextMenuItems from './utils/get-context-menu'; -import getHoverMenuItems from './utils/get-hover-menu'; -import HoverTooltip from './components/Tooltip'; + import useStyles from './styles'; const ObjectsTable = ({ @@ -42,7 +37,6 @@ const ObjectsTable = ({ const { t } = useTranslation(); const history = useHistory(); const dispatch = useDispatch(); - const [hoveredItemKey, setHoveredItemKey] = React.useState(null); const location = useLocation(); const initialContextState = { @@ -102,14 +96,6 @@ const ObjectsTable = ({ const sortedRows = sortAndAddSubfolders(unsortedRows); - const hoveredItemIndex = hoveredItemKey && sortedRows.findIndex( - (row) => (row.fullKey === hoveredItemKey), - ); - - const hoveredItem = hoveredItemKey && sortedRows[hoveredItemIndex]; - - const hoveredItemOptions = getHoverMenuItems(hoveredItem); - const classes = useStyles(); const clickedItem = sortedRows.find((row) => row.selected); @@ -282,21 +268,6 @@ const ObjectsTable = ({ const contextMenuItems = getContextMenuItems(clickedItem, t); - const handleHoverMenuOpen = (event) => { - const newItemKey = get(event, 'target.parentNode.dataset.key'); - if ((newItemKey && (newItemKey !== hoveredItemKey)) || !hoveredItemKey) { - setHoveredItemKey(newItemKey); - } - }; - - const handleHoverMenuClose = () => { - setHoveredItemKey(null); - }; - - const hoverMenuItemOnClick = (id) => { - console.log(id); - }; - const getDropzoneObjsList = () => { let indexOfLastVisitedRootObj = 0; @@ -322,7 +293,6 @@ const ObjectsTable = ({ >
)} renderRow={({ row, rowIndex }) => ( - ( - - ) - } - > - arrowOnClick(row)} - /> - {withRowOptions && ( - - - - )} - + arrowOnClick(row)} + handleRowClick={handleRowClick} + handleRowRightClick={handleRowRightClick} + handleDoubleRowClick={handleDoubleRowClick} + rowClasses={classes} + /> )} /> null, renderLoadingRows: () => null, loading: false, diff --git a/src/shared/components/ObjectsTable/styles.js b/src/shared/components/ObjectsTable/styles.js index 230b811a..3dabca46 100644 --- a/src/shared/components/ObjectsTable/styles.js +++ b/src/shared/components/ObjectsTable/styles.js @@ -28,15 +28,6 @@ export default makeStyles(() => ({ height: '100%', padding: '0 5px', }, - selected: { - backgroundColor: '#E5F0FF !important', - }, - selectedAndUploading: { - backgroundColor: '#F5F6F8 !important', - }, - error: { - backgroundColor: '#F8DEDF !important', - }, tableWrapper: { flexGrow: 1, padding: 6, @@ -58,4 +49,13 @@ export default makeStyles(() => ({ sortButton: { padding: 2, }, + selected: { + backgroundColor: '#E5F0FF !important', + }, + selectedAndUploading: { + backgroundColor: '#F5F6F8 !important', + }, + error: { + backgroundColor: '#F8DEDF !important', + }, })); diff --git a/src/shared/components/ObjectsTable/utils/hover-menu-on-click.js b/src/shared/components/ObjectsTable/utils/hover-menu-on-click.js new file mode 100644 index 00000000..2a119870 --- /dev/null +++ b/src/shared/components/ObjectsTable/utils/hover-menu-on-click.js @@ -0,0 +1,5 @@ +const hoverMenuItemOnClick = (id) => { + console.log('id', id); +}; + +export default hoverMenuItemOnClick; diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 786508c5..db507c3a 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -47,6 +47,7 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), + isUploading: true, }; }; diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index 78b34bca..9ae26c06 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; import moment from 'moment'; import PropTypes from 'prop-types'; @@ -5,19 +6,32 @@ import classnames from 'classnames'; import { useLocation } from 'react-router-dom'; import Typography from '@material-ui/core/Typography'; import { useTranslation } from 'react-i18next'; -import { TableCell, FileNameCell } from '@ui/Table'; +import { TableCell, FileNameCell, TableRow } from '@ui/Table'; import { formatBytes, getTabulations } from '@utils'; +import getHoverMenuItems from '@shared/components/ObjectsTable/utils/get-hover-menu'; +import hoverMenuItemOnClick from '@shared/components/ObjectsTable/utils/hover-menu-on-click'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons/faCheckCircle'; import { faExclamationCircle } from '@fortawesome/pro-solid-svg-icons/faExclamationCircle'; import { faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons/faSpinnerThird'; +import HoverMenu from '@ui/HoverMenu'; +import Tooltip from '@material-ui/core/Tooltip'; import useStyles from './styles'; -const RenderRow = ({ row, arrowOnClick, disableOffset }) => { +const RenderRow = ({ + row, + arrowOnClick, + disableOffset, + rowIndex, + handleRowClick, + handleRowRightClick, + handleDoubleRowClick, + rowClasses, +}) => { const location = useLocation(); - const classes = useStyles({ progress: 0.4 }); + const classes = useStyles({ progress: 0.4, rowIndex }); const { t } = useTranslation(); const getSizeIcon = () => { @@ -88,7 +102,46 @@ const RenderRow = ({ row, arrowOnClick, disableOffset }) => { }; return ( - <> + ( + + )} + > + + {children} + + + ) + } + > { {getLastModifiedCell()} - + ); }; @@ -130,6 +183,8 @@ RenderRow.defaultProps = { RenderRow.propTypes = { row: PropTypes.shape({ + id: PropTypes.string, + fullKey: PropTypes.string, shareAmount: PropTypes.number, ext: PropTypes.string, key: PropTypes.string, @@ -146,6 +201,16 @@ RenderRow.propTypes = { }).isRequired, disableOffset: PropTypes.bool, arrowOnClick: PropTypes.func, + rowIndex: PropTypes.number.isRequired, + handleRowClick: PropTypes.func.isRequired, + handleRowRightClick: PropTypes.func.isRequired, + handleDoubleRowClick: PropTypes.func.isRequired, + rowClasses: PropTypes.shape({ + row: PropTypes.string, + selected: PropTypes.string, + selectedAndUploading: PropTypes.string, + error: PropTypes.string, + }).isRequired, }; export default RenderRow; diff --git a/src/views/Storage/shared/RenderRow/styles.js b/src/views/Storage/shared/RenderRow/styles.js index dce75ce4..d6ddf03c 100644 --- a/src/views/Storage/shared/RenderRow/styles.js +++ b/src/views/Storage/shared/RenderRow/styles.js @@ -53,4 +53,13 @@ export default makeStyles((theme) => ({ fontSize: 12, color: theme.palette.palette.red, }, + tooltipRoot: { + backgroundColor: 'transparent', + }, + popperRoot: { + top: ({ rowIndex }) => (`${(80 + 36 * rowIndex)}px !important`), + left: 'auto !important', + right: 260, + transform: 'none !important', + }, })); diff --git a/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js b/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js index ccb0cb3b..28c0565a 100644 --- a/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js +++ b/src/views/Storage/shared/ShareRenderRow/SharedRenderRow.js @@ -1,18 +1,42 @@ +/* eslint-disable react/jsx-props-no-spreading */ import React, { useEffect } from 'react'; +import classnames from 'classnames'; import get from 'lodash/get'; import moment from 'moment'; import PropTypes from 'prop-types'; import { getTabulations } from '@utils'; import { useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import Typography from '@material-ui/core/Typography'; -import { TableCell, FileNameCell, MemberCell } from '@ui/Table'; +import { + TableCell, + FileNameCell, + MemberCell, + TableRow, +} from '@ui/Table'; import { getIdentitiesByAddress } from '@events/identities'; +import getHoverMenuItems from '@shared/components/ObjectsTable/utils/get-hover-menu'; +import hoverMenuItemOnClick from '@shared/components/ObjectsTable/utils/hover-menu-on-click'; +import HoverMenu from '@ui/HoverMenu'; +import Tooltip from '@material-ui/core/Tooltip'; -const ShareRenderRow = ({ row, arrowOnClick }) => { +import useStyles from './styles'; + +const ShareRenderRow = ({ + row, + arrowOnClick, + rowIndex, + handleRowClick, + handleRowRightClick, + handleDoubleRowClick, + rowClasses, +}) => { const location = useLocation(); const members = get(row, 'members', []) || []; const [userAddress, identities] = useSelector((state) => [state.user.address, state.identities]); + const classes = useStyles({ progress: 0.4, rowIndex }); + const { t } = useTranslation(); const firstMember = members.find((item) => item.address !== userAddress); const firstMemberIdentity = get(identities, `identities.${firstMember.publicKey}`, {}); @@ -26,7 +50,46 @@ const ShareRenderRow = ({ row, arrowOnClick }) => { }, []); return ( - <> + ( + + )} + > + + {children} + + + ) + } + > { {/* {formatMonthDayYear(row.lastModified)} */} - + ); }; @@ -58,6 +121,8 @@ ShareRenderRow.defaultProps = { ShareRenderRow.propTypes = { row: PropTypes.shape({ + id: PropTypes.string, + fullKey: PropTypes.string, shareAmount: PropTypes.number, ext: PropTypes.string, key: PropTypes.string, @@ -69,8 +134,20 @@ ShareRenderRow.propTypes = { expanded: PropTypes.bool, selected: PropTypes.bool, members: PropTypes.array, + isUploading: PropTypes.bool, + error: PropTypes.bool, }).isRequired, arrowOnClick: PropTypes.func, + rowIndex: PropTypes.number.isRequired, + handleRowClick: PropTypes.func.isRequired, + handleRowRightClick: PropTypes.func.isRequired, + handleDoubleRowClick: PropTypes.func.isRequired, + rowClasses: PropTypes.shape({ + row: PropTypes.string, + selected: PropTypes.string, + selectedAndUploading: PropTypes.string, + error: PropTypes.string, + }).isRequired, }; export default ShareRenderRow; diff --git a/src/views/Storage/shared/ShareRenderRow/styles.js b/src/views/Storage/shared/ShareRenderRow/styles.js index 3c6ec009..7c5af272 100644 --- a/src/views/Storage/shared/ShareRenderRow/styles.js +++ b/src/views/Storage/shared/ShareRenderRow/styles.js @@ -23,4 +23,13 @@ export default makeStyles((theme) => ({ highlighted: { color: theme.palette.palette.spaceBlue, }, + tooltipRoot: { + backgroundColor: 'transparent', + }, + popperRoot: { + top: ({ rowIndex }) => (`${(80 + 36 * rowIndex)}px !important`), + left: 'auto !important', + right: 260, + transform: 'none !important', + }, })); From ed6a0c4d98bed76caf0a7c424a8055a17baa3296 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 7 Dec 2020 12:57:33 -0500 Subject: [PATCH 40/51] clean up --- src/utils/object-presenter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index db507c3a..786508c5 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -47,7 +47,6 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), - isUploading: true, }; }; From eab5eb3676dcc2945f00dd5820f90f1eb4906ea9 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 7 Dec 2020 13:56:58 -0500 Subject: [PATCH 41/51] isuplaoding false --- src/utils/object-presenter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/object-presenter.js b/src/utils/object-presenter.js index 786508c5..a949bdd4 100644 --- a/src/utils/object-presenter.js +++ b/src/utils/object-presenter.js @@ -47,6 +47,7 @@ const objectPresenter = (obj = {}, isRootDir = false) => { isAvailableInSpace: backupCount > 0, sourceBucket: sourceBucket || bucket, shareAmount: Math.max(1, members.length), + isUploading: false, }; }; From 769d91642520643769ea1744047b069a66d75762 Mon Sep 17 00:00:00 2001 From: Guillermo Puente Date: Mon, 7 Dec 2020 16:20:26 -0300 Subject: [PATCH 42/51] remove loading incon for folders --- src/views/Storage/shared/RenderRow/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index eea042b2..7dc14c84 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -17,6 +17,7 @@ const RenderRow = ({ row, arrowOnClick, disableOffset }) => { const classes = useStyles(); const getSizeIcon = () => { + if (row.ext === 'folder') return
; if (row.isAvailableInSpace) { return (
From 5bf2cf735a264cd47bbc45c21d3387086ee02ec8 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Mon, 7 Dec 2020 16:51:00 -0500 Subject: [PATCH 43/51] remove old component --- .../ObjectsTable/components/Tooltip/index.js | 66 ------------------- .../ObjectsTable/components/Tooltip/styles.js | 13 ---- 2 files changed, 79 deletions(-) delete mode 100644 src/shared/components/ObjectsTable/components/Tooltip/index.js delete mode 100644 src/shared/components/ObjectsTable/components/Tooltip/styles.js diff --git a/src/shared/components/ObjectsTable/components/Tooltip/index.js b/src/shared/components/ObjectsTable/components/Tooltip/index.js deleted file mode 100644 index e87b0941..00000000 --- a/src/shared/components/ObjectsTable/components/Tooltip/index.js +++ /dev/null @@ -1,66 +0,0 @@ -/* eslint-disable react/jsx-props-no-spreading */ -import React from 'react'; -import PropTypes from 'prop-types'; -import HoverMenu from '@ui/HoverMenu'; -import { useTranslation } from 'react-i18next'; -import Tooltip from '@material-ui/core/Tooltip'; - -import useStyles from './styles'; - -const HoverTooltip = ({ - rowProps, - hoveredItemOptions, - hoveredItemIndex, - hoverMenuItemOnClick, - ...restProps -}) => { - const { t } = useTranslation(); - const { children, ...props } = rowProps; - - const classes = useStyles({ - hoveredItemIndex, - }); - - return ( - - )} - {...restProps} - > -
- {children} - - - ); -}; - -HoverTooltip.defaultProps = { - hoveredItemIndex: 0, -}; - -HoverTooltip.propTypes = { - rowProps: PropTypes.shape({ - children: PropTypes.node, - props: PropTypes.shape({}), - }).isRequired, - hoveredItemOptions: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, - hoverMenuItemOnClick: PropTypes.func.isRequired, - hoveredItemIndex: PropTypes.number, -}; - -export default HoverTooltip; diff --git a/src/shared/components/ObjectsTable/components/Tooltip/styles.js b/src/shared/components/ObjectsTable/components/Tooltip/styles.js deleted file mode 100644 index f34a579f..00000000 --- a/src/shared/components/ObjectsTable/components/Tooltip/styles.js +++ /dev/null @@ -1,13 +0,0 @@ -import { makeStyles } from '@material-ui/core/styles'; - -export default makeStyles(() => ({ - tooltipRoot: { - backgroundColor: 'transparent', - }, - popperRoot: { - top: ({ hoveredItemIndex }) => (`${(80 + 36 * hoveredItemIndex)}px !important`), - left: 'auto !important', - right: 220, - transform: 'none !important', - }, -})); From 7c055d1ae8297be33503e41e37cf5e0fa442b2a1 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Wed, 9 Dec 2020 10:45:09 -0500 Subject: [PATCH 44/51] share icon spacing --- src/UI/Table/components/FileNameCell/styles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/UI/Table/components/FileNameCell/styles.js b/src/UI/Table/components/FileNameCell/styles.js index fc5b49ef..61a1d880 100644 --- a/src/UI/Table/components/FileNameCell/styles.js +++ b/src/UI/Table/components/FileNameCell/styles.js @@ -4,6 +4,7 @@ export default makeStyles((theme) => ({ container: { display: 'flex', alignItems: 'center', + paddingRight: 20, }, iconContainer: { position: 'relative', From f8724b8b6743d200402b4dddf801553b95c47d01 Mon Sep 17 00:00:00 2001 From: sagostinelli Date: Wed, 9 Dec 2020 13:31:19 -0500 Subject: [PATCH 45/51] handle double row click fix --- src/views/Storage/shared/RenderRow/index.js | 32 +++++++++++++++++-- .../shared/ShareRenderRow/SharedRenderRow.js | 32 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/views/Storage/shared/RenderRow/index.js b/src/views/Storage/shared/RenderRow/index.js index fa6b8118..9bfb5aee 100644 --- a/src/views/Storage/shared/RenderRow/index.js +++ b/src/views/Storage/shared/RenderRow/index.js @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ -import React from 'react'; +import React, { useRef, useEffect } from 'react'; import moment from 'moment'; import PropTypes from 'prop-types'; import classnames from 'classnames'; @@ -30,10 +30,37 @@ const RenderRow = ({ handleDoubleRowClick, rowClasses, }) => { + const clickAmount = useRef(0); + const timer = useRef(null); const location = useLocation(); const classes = useStyles({ progress: 0.4, rowIndex }); const { t } = useTranslation(); + useEffect(() => ( + () => { + if (timer) { + clearTimeout(timer.current); + } + } + ), + []); + + const onClick = (event) => { + clickAmount.current += 1; + if (timer.current) { + return; + } + timer.current = setTimeout(() => { + if (clickAmount.current >= 2) { + handleDoubleRowClick({ row })(event); + } else { + handleRowClick({ rowIndex })(event); + } + clickAmount.current = 0; + timer.current = null; + }, 250); + }; + const getSizeIcon = () => { if (row.isUploading) { if (row.error) { @@ -114,9 +141,8 @@ const RenderRow = ({ [rowClasses.selected]: row.selected, [rowClasses.error]: row.error && !row.isUploading, })} - onClick={handleRowClick({ row, rowIndex })} onContextMenu={handleRowRightClick({ row })} - onDoubleClick={handleDoubleRowClick({ row })} + onClick={onClick} component={ ({ children, ...rowProps }) => ( { + const clickAmount = useRef(0); + const timer = useRef(null); const location = useLocation(); const members = get(row, 'members', []) || []; const [userAddress, identities] = useSelector((state) => [state.user.address, state.identities]); @@ -49,6 +51,31 @@ const ShareRenderRow = ({ } }, []); + useEffect(() => ( + () => { + if (timer) { + clearTimeout(timer.current); + } + } + ), + []); + + const onClick = (event) => { + clickAmount.current += 1; + if (timer.current) { + return; + } + timer.current = setTimeout(() => { + if (clickAmount.current >= 2) { + handleDoubleRowClick({ row })(event); + } else { + handleRowClick({ rowIndex })(event); + } + clickAmount.current = 0; + timer.current = null; + }, 250); + }; + return ( ( Date: Wed, 9 Dec 2020 15:37:54 -0300 Subject: [PATCH 46/51] Fix notifications styles --- src/UI/Notification/NotificationItem/NotificationItem.js | 2 +- src/UI/Notification/NotificationItem/styles.js | 6 +++--- src/UI/Table/table.stories.js | 2 +- .../components/ObjectsTable/utils/hover-menu-on-click.js | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/UI/Notification/NotificationItem/NotificationItem.js b/src/UI/Notification/NotificationItem/NotificationItem.js index 30046b67..45141fd6 100644 --- a/src/UI/Notification/NotificationItem/NotificationItem.js +++ b/src/UI/Notification/NotificationItem/NotificationItem.js @@ -39,7 +39,7 @@ const NotificationItem = (props) => { <>