Web.Files: add GroupButtonMenu: selectors, actions, handling events, fake callbacks
This commit is contained in:
parent
4c09c402f4
commit
9d7d454655
@ -13,7 +13,8 @@ import {
|
||||
import EmptyFolderContainer from "./EmptyFolderContainer";
|
||||
import FilesRowContent from "./FilesRowContent";
|
||||
import { api } from 'asc-web-common';
|
||||
import { fetchFiles, deleteFile, deleteFolder, fetchFolder } from '../../../../../store/files/actions';
|
||||
import { fetchFiles, deleteFile, deleteFolder, fetchFolder, selectFile, deselectFile } from '../../../../../store/files/actions';
|
||||
import { isFileSelected } from '../../../../../store/files/selectors';
|
||||
import store from "../../../../../store/store";
|
||||
import { getFilterByLocation } from "../../../../../helpers/converters";
|
||||
import config from "../../../../../../package.json";
|
||||
@ -172,8 +173,17 @@ class SectionBodyContent extends React.PureComponent {
|
||||
return false;
|
||||
};
|
||||
|
||||
onContentRowSelect = (checked, file) => {
|
||||
|
||||
if (checked) {
|
||||
this.props.selectFile(file);
|
||||
} else {
|
||||
this.props.deselectFile(file);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { files, folders, viewer, parentId, folderId, settings } = this.props;
|
||||
const { files, folders, viewer, parentId, folderId, settings, selection } = this.props;
|
||||
const { editingId, isEdit, isCreating } = this.state;
|
||||
|
||||
let items = [...folders, ...files];
|
||||
@ -194,7 +204,7 @@ class SectionBodyContent extends React.PureComponent {
|
||||
const contextOptionsProps = !contextOptions.length || item.id === -2
|
||||
? {}
|
||||
: { contextOptions };
|
||||
const checked = false; //isUserSelected(selection, user.id);
|
||||
const checked = isFileSelected(selection, item.id);
|
||||
const checkedProps = /* isAdmin(viewer) */ item.id !== -2 && true ? { checked } : {};
|
||||
const element = (isEdit || isCreating) && (item.id === editingId || item.id === -2)
|
||||
? <Loader type='oval' color="black" size='24px' label="Editing..." />
|
||||
@ -207,7 +217,7 @@ class SectionBodyContent extends React.PureComponent {
|
||||
key={item.id}
|
||||
data={item}
|
||||
element={element}
|
||||
onSelect={() => { }}
|
||||
onSelect={this.onContentRowSelect}
|
||||
editing={editingId}
|
||||
{...checkedProps}
|
||||
{...contextOptionsProps}
|
||||
@ -244,5 +254,5 @@ const mapStateToProps = state => {
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ fetchFiles, deleteFile, deleteFolder }
|
||||
{ fetchFiles, deleteFile, deleteFolder, selectFile, deselectFile }
|
||||
)(withRouter(withTranslation()(SectionBodyContent)));
|
||||
|
@ -1,27 +1,33 @@
|
||||
import React, { useCallback } from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { withRouter } from "react-router";
|
||||
import { Headline, store } from 'asc-web-common';
|
||||
import { Headline, store, constants } from 'asc-web-common';
|
||||
import { connect } from "react-redux";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import {
|
||||
toastr,
|
||||
ContextMenuButton
|
||||
ContextMenuButton,
|
||||
GroupButtonsMenu,
|
||||
DropDownItem
|
||||
} from "asc-web-components";
|
||||
|
||||
const { isAdmin } = store.auth.selectors;
|
||||
const { FilterType } = constants;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
${props => props.isHeaderVisible &&
|
||||
css`width: calc(100% + 76px);`}
|
||||
}
|
||||
|
||||
.header-container {
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: calc(100vw - 32px);
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
${props => props.isHeaderVisible && css`width: calc(100% + 76px);`}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
margin-bottom: -1px;
|
||||
margin-left: 16px;
|
||||
@ -38,11 +44,41 @@ const StyledContainer = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group-button-menu-container {
|
||||
margin: 0 -16px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
padding-bottom: 56px;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
& > div:first-child {
|
||||
${props =>
|
||||
props.isArticlePinned &&
|
||||
css`
|
||||
width: calc(100% - 240px);
|
||||
`}
|
||||
position: absolute;
|
||||
top: 56px;
|
||||
z-index: 180;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
margin: 0 -24px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const SectionHeaderContent = props => {
|
||||
|
||||
const { t, folder, title, onCreate } = props;
|
||||
const { t, folder, title,
|
||||
onCreate, onCheck, onSelect,
|
||||
onClose,
|
||||
isHeaderVisible,
|
||||
isHeaderChecked,
|
||||
isHeaderIndeterminate,
|
||||
selection } = props;
|
||||
|
||||
const createDocument = useCallback(
|
||||
() => onCreate('docx'),
|
||||
@ -133,6 +169,11 @@ const SectionHeaderContent = props => {
|
||||
[]
|
||||
);
|
||||
|
||||
const downloadAsAction = useCallback(
|
||||
() => toastr.info("downloadAsAction click"),
|
||||
[]
|
||||
);
|
||||
|
||||
const renameAction = useCallback(
|
||||
() => toastr.info("renameAction click"),
|
||||
[]
|
||||
@ -201,43 +242,116 @@ const SectionHeaderContent = props => {
|
||||
deleteAction
|
||||
]);
|
||||
|
||||
return (
|
||||
<StyledContainer isHeaderVisible={true}>
|
||||
<Headline className='headline-header' type="content" truncate={true}>{title}</Headline>
|
||||
{folder ? (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="VerticalDotsIcon"
|
||||
size={16}
|
||||
color="#A3A9AE"
|
||||
getData={getContextOptionsFolder}
|
||||
isDisabled={false}
|
||||
const isItemsSelected = selection.length;
|
||||
const isOnlyFolderSelected = selection.every(selected => !selected.fileType);
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: t("LblSelect"),
|
||||
isDropdown: true,
|
||||
isSeparator: true,
|
||||
isSelect: true,
|
||||
fontWeight: "bold",
|
||||
children: [
|
||||
<DropDownItem key='all' label={t("All")} />,
|
||||
<DropDownItem key={FilterType.FoldersOnly} label={t("Folders")} />,
|
||||
<DropDownItem key={FilterType.DocumentsOnly} label={t("Documents")} />,
|
||||
<DropDownItem key={FilterType.PresentationsOnly} label={t("Presentations")} />,
|
||||
<DropDownItem key={FilterType.SpreadsheetsOnly} label={t("Spreadsheets")} />,
|
||||
<DropDownItem key={FilterType.ImagesOnly} label={t("Images")} />,
|
||||
<DropDownItem key={FilterType.MediaOnly} label={t("Media")} />,
|
||||
<DropDownItem key={FilterType.ArchiveOnly} label={t("Archives")} />,
|
||||
<DropDownItem key={FilterType.FilesOnly} label={t("AllFiles")} />,
|
||||
],
|
||||
onSelect: item => onSelect(item.key)
|
||||
},
|
||||
{
|
||||
label: t("Share"),
|
||||
disabled: !isItemsSelected,
|
||||
onClick: openSharingSettings
|
||||
},
|
||||
{
|
||||
label: t("Download"),
|
||||
disabled: !isItemsSelected,
|
||||
onClick: downloadAction
|
||||
},
|
||||
{
|
||||
label: t("DownloadAs"),
|
||||
disabled: !isItemsSelected || isOnlyFolderSelected,
|
||||
onClick: downloadAsAction
|
||||
},
|
||||
{
|
||||
label: t("MoveTo"),
|
||||
disabled: !isItemsSelected,
|
||||
onClick: moveAction
|
||||
},
|
||||
{
|
||||
label: t("Copy"),
|
||||
disabled: !isItemsSelected,
|
||||
onClick: copyAction
|
||||
},
|
||||
{
|
||||
label: t("Delete"),
|
||||
disabled: !isItemsSelected,
|
||||
onClick: deleteAction
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<StyledContainer isHeaderVisible={isHeaderVisible}>
|
||||
{isHeaderVisible ? (
|
||||
<div className="group-button-menu-container">
|
||||
<GroupButtonsMenu
|
||||
checked={isHeaderChecked}
|
||||
isIndeterminate={isHeaderIndeterminate}
|
||||
onChange={onCheck}
|
||||
menuItems={menuItems}
|
||||
visible={isHeaderVisible}
|
||||
moreLabel={t("More")}
|
||||
closeTitle={t("CloseButton")}
|
||||
onClose={onClose}
|
||||
selected={menuItems[0].label}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className='header-container'>
|
||||
<Headline className='headline-header' type="content" truncate={true}>{title}</Headline>
|
||||
{folder ?
|
||||
<>
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="VerticalDotsIcon"
|
||||
size={16}
|
||||
color="#A3A9AE"
|
||||
getData={getContextOptionsFolder}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</>
|
||||
:
|
||||
<ContextMenuButton
|
||||
className="action-button"
|
||||
directionX="right"
|
||||
iconName="PlusIcon"
|
||||
size={16}
|
||||
color="#657077"
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
@ -247,7 +361,8 @@ const mapStateToProps = state => {
|
||||
return {
|
||||
isAdmin: isAdmin(state.auth.user),
|
||||
title: state.files.selectedFolder.title,
|
||||
folder: state.files.selectedFolder.parentId !== 0
|
||||
folder: state.files.selectedFolder.parentId !== 0,
|
||||
selection: state.files.selection
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -35,12 +35,12 @@ class PureHome extends React.Component {
|
||||
}
|
||||
|
||||
renderGroupButtonMenu = () => {
|
||||
const { files, selection, selected, setSelected } = this.props;
|
||||
const { files, selection, selected, setSelected, folders } = this.props;
|
||||
|
||||
const headerVisible = selection.length > 0;
|
||||
const headerIndeterminate =
|
||||
headerVisible && selection.length > 0 && selection.length < files.length;
|
||||
const headerChecked = headerVisible && selection.length === files.length;
|
||||
headerVisible && selection.length > 0 && selection.length < files.length + folders.length;
|
||||
const headerChecked = headerVisible && selection.length === files.length + folders.length;
|
||||
|
||||
/*console.log(`renderGroupButtonMenu()
|
||||
headerVisible=${headerVisible}
|
||||
@ -182,6 +182,7 @@ Home.propTypes = {
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
files: state.files.files,
|
||||
folders: state.files.folders,
|
||||
selection: state.files.selection,
|
||||
selected: state.files.selected,
|
||||
isLoaded: state.auth.isLoaded
|
||||
|
@ -45,5 +45,11 @@
|
||||
"TitleModified": "Updated",
|
||||
"TitleRemoved": "Removed",
|
||||
"TitleSubfolders": "Flds",
|
||||
"TitleDocuments": "Dcs"
|
||||
"TitleDocuments": "Dcs",
|
||||
"Share": "Share",
|
||||
"DownloadAs": "Download as",
|
||||
"More": "More",
|
||||
"CloseButton": "Close",
|
||||
"All": "All",
|
||||
"Files": "Files"
|
||||
}
|
@ -39,12 +39,17 @@
|
||||
"NextPage": "Следующая",
|
||||
"DefaultOptionLabel": "Я",
|
||||
"LblSelect": "Выберите",
|
||||
|
||||
"AuthorMe": "Я",
|
||||
"TitleCreated": "Создана",
|
||||
"TitleUploaded": "Загружен",
|
||||
"TitleModified": "Обновлён",
|
||||
"TitleRemoved": "Удалён",
|
||||
"TitleSubfolders": "Flds",
|
||||
"TitleDocuments": "Dcs"
|
||||
"TitleDocuments": "Dcs",
|
||||
"Share": "Общий доступ",
|
||||
"DownloadAs": "Скачать как",
|
||||
"More": "Больше",
|
||||
"CloseButton": "Закрыть",
|
||||
"All": "Все",
|
||||
"Files": "Файлы"
|
||||
}
|
@ -24,6 +24,8 @@ export const SET_SELECTED_FOLDER = "SET_SELECTED_FOLDER";
|
||||
export const SET_ROOT_FOLDERS = "SET_ROOT_FOLDERS";
|
||||
export const SET_FILES_FILTER = "SET_FILES_FILTER";
|
||||
export const SET_FILTER = "SET_FILTER";
|
||||
export const SELECT_FILE = "SELECT_FILE";
|
||||
export const DESELECT_FILE = "DESELECT_FILE";
|
||||
|
||||
export function setFile(file) {
|
||||
return {
|
||||
@ -93,6 +95,20 @@ export function setFilter(filter) {
|
||||
type: SET_FILTER,
|
||||
filter
|
||||
};
|
||||
};
|
||||
|
||||
export function selectFile(file) {
|
||||
return {
|
||||
type: SELECT_FILE,
|
||||
file
|
||||
};
|
||||
}
|
||||
|
||||
export function deselectFile(file) {
|
||||
return {
|
||||
type: DESELECT_FILE,
|
||||
file
|
||||
};
|
||||
}
|
||||
|
||||
export function setFilterUrl(filter) {
|
||||
|
@ -8,9 +8,12 @@ import {
|
||||
SET_ROOT_FOLDERS,
|
||||
SET_SELECTED_FOLDER,
|
||||
SET_SELECTED,
|
||||
SET_SELECTION
|
||||
SET_SELECTION,
|
||||
SELECT_FILE,
|
||||
DESELECT_FILE
|
||||
} from "./actions";
|
||||
import { api } from "asc-web-common";
|
||||
import { isFileSelected, skipFile, getFilesBySelected } from "./selectors";
|
||||
const { FilesFilter } = api;
|
||||
|
||||
const initialState = {
|
||||
@ -49,10 +52,11 @@ const filesReducer = (state = initialState, action) => {
|
||||
return Object.assign({}, state, {
|
||||
selection: action.selection
|
||||
});
|
||||
case SET_SELECTED:
|
||||
return Object.assign({}, state, {
|
||||
selected: action.selected
|
||||
});
|
||||
case SET_SELECTED:
|
||||
return Object.assign({}, state, {
|
||||
selected: action.selected,
|
||||
selection: getFilesBySelected(state.files.concat(state.folders), action.selected)
|
||||
});
|
||||
case SET_SELECTED_FOLDER:
|
||||
return Object.assign({}, state, {
|
||||
selectedFolder: action.selectedFolder
|
||||
@ -69,6 +73,18 @@ const filesReducer = (state = initialState, action) => {
|
||||
return Object.assign({}, state, {
|
||||
filter: action.filter
|
||||
});
|
||||
case SELECT_FILE:
|
||||
if (!isFileSelected(state.selection, action.file.id)) {
|
||||
return Object.assign({}, state, {
|
||||
selection: [...state.selection, action.file]
|
||||
});
|
||||
} else return state;
|
||||
case DESELECT_FILE:
|
||||
if (isFileSelected(state.selection, action.file.id)) {
|
||||
return Object.assign({}, state, {
|
||||
selection: skipFile(state.selection, action.file.id)
|
||||
});
|
||||
} else return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
import { find, filter } from "lodash";
|
||||
import { constants } from 'asc-web-common';
|
||||
|
||||
const { FileType, FilterType } = constants;
|
||||
|
||||
export const getRootFolders = files => {
|
||||
const { my, share, common, project, trash } = files;
|
||||
|
||||
@ -48,3 +53,58 @@ export const canConvert = fileExst => {
|
||||
const result = convertedDocs.findIndex(item => item === fileExst);
|
||||
return result === -1 ? false : true;
|
||||
}
|
||||
|
||||
export function getSelectedFile(selection, fileId) {
|
||||
return find(selection, function (obj) {
|
||||
return obj.id === fileId;
|
||||
});
|
||||
};
|
||||
|
||||
export function isFileSelected(selection, fileId) {
|
||||
return getSelectedFile(selection, fileId) !== undefined;
|
||||
};
|
||||
|
||||
export function skipFile(selection, fileId) {
|
||||
return filter(selection, function (obj) {
|
||||
return obj.id !== fileId;
|
||||
});
|
||||
};
|
||||
|
||||
export function getFilesBySelected(files, selected) {
|
||||
let newSelection = [];
|
||||
files.forEach(file => {
|
||||
const checked = getFilesChecked(file, selected);
|
||||
|
||||
if (checked)
|
||||
newSelection.push(file);
|
||||
});
|
||||
|
||||
return newSelection;
|
||||
};
|
||||
|
||||
const getFilesChecked = (file, selected) => {
|
||||
const type = file.fileType;
|
||||
switch (selected) {
|
||||
case "all":
|
||||
return true;
|
||||
case FilterType.FoldersOnly.toString():
|
||||
return !type;
|
||||
case FilterType.DocumentsOnly.toString():
|
||||
return type === FileType.Document;
|
||||
case FilterType.PresentationsOnly.toString():
|
||||
return type === FileType.Presentation;
|
||||
case FilterType.SpreadsheetsOnly.toString():
|
||||
return type === FileType.Spreadsheet;
|
||||
case FilterType.ImagesOnly.toString():
|
||||
return type === FileType.Image;
|
||||
case FilterType.MediaOnly.toString():
|
||||
return type === FileType.Video || type === FileType.Audio;
|
||||
case FilterType.ArchiveOnly.toString():
|
||||
return type === FileType.Archive;
|
||||
case FilterType.FilesOnly.toString():
|
||||
return type;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user