mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-11 11:51:27 +00:00
['libs' pages] added 'view mode' selector & 'sort' menu for 'my (#7096)
libs, shared with me, shared with all, group, department' pages - besides that, fixed bugs & improved many lines of code
This commit is contained in:
@@ -24,7 +24,7 @@ import ShareAdminLibraries from './pages/share-admin/libraries';
|
|||||||
import ShareAdminFolders from './pages/share-admin/folders';
|
import ShareAdminFolders from './pages/share-admin/folders';
|
||||||
import ShareAdminShareLinks from './pages/share-admin/share-links';
|
import ShareAdminShareLinks from './pages/share-admin/share-links';
|
||||||
import ShareAdminUploadLinks from './pages/share-admin/upload-links';
|
import ShareAdminUploadLinks from './pages/share-admin/upload-links';
|
||||||
import SharedLibraries from './pages/shared-libs/shared-libraries';
|
import SharedLibraries from './pages/shared-libs';
|
||||||
import ShareWithOCM from './pages/share-with-ocm/shared-with-ocm';
|
import ShareWithOCM from './pages/share-with-ocm/shared-with-ocm';
|
||||||
import OCMViaWebdav from './pages/ocm-via-webdav/ocm-via-webdav';
|
import OCMViaWebdav from './pages/ocm-via-webdav/ocm-via-webdav';
|
||||||
import OCMRepoDir from './pages/share-with-ocm/remote-dir-view';
|
import OCMRepoDir from './pages/share-with-ocm/remote-dir-view';
|
||||||
|
@@ -7,7 +7,7 @@ import TextTranslation from '../../utils/text-translation';
|
|||||||
import SeahubPopover from '../common/seahub-popover';
|
import SeahubPopover from '../common/seahub-popover';
|
||||||
import ListTagPopover from '../popover/list-tag-popover';
|
import ListTagPopover from '../popover/list-tag-popover';
|
||||||
import ViewModes from '../../components/view-modes';
|
import ViewModes from '../../components/view-modes';
|
||||||
import ReposSortMenu from '../../components/repos-sort-menu';
|
import SortMenu from '../../components/sort-menu';
|
||||||
import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
||||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
import { DIRENT_DETAIL_MODE } from '../dir-view-mode/constants';
|
import { DIRENT_DETAIL_MODE } from '../dir-view-mode/constants';
|
||||||
@@ -36,13 +36,6 @@ class DirTool extends React.Component {
|
|||||||
isRepoTagDialogOpen: false,
|
isRepoTagDialogOpen: false,
|
||||||
isDropdownMenuOpen: false,
|
isDropdownMenuOpen: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sortOptions = [
|
|
||||||
{ value: 'name-asc', text: gettext('By name ascending') },
|
|
||||||
{ value: 'name-desc', text: gettext('By name descending') },
|
|
||||||
{ value: 'time-asc', text: gettext('By time ascending') },
|
|
||||||
{ value: 'time-desc', text: gettext('By time descending') }
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDropdownMenu = () => {
|
toggleDropdownMenu = () => {
|
||||||
@@ -111,13 +104,6 @@ class DirTool extends React.Component {
|
|||||||
const isFileExtended = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/');
|
const isFileExtended = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/');
|
||||||
const isTagView = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.TAGS_PROPERTIES + '/');
|
const isTagView = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.TAGS_PROPERTIES + '/');
|
||||||
|
|
||||||
const sortOptions = this.sortOptions.map(item => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
isSelected: item.value === `${sortBy}-${sortOrder}`
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isFileExtended) {
|
if (isFileExtended) {
|
||||||
return (
|
return (
|
||||||
<div className="dir-tool">
|
<div className="dir-tool">
|
||||||
@@ -142,7 +128,7 @@ class DirTool extends React.Component {
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="dir-tool d-flex">
|
<div className="dir-tool d-flex">
|
||||||
<ViewModes currentViewMode={currentMode} switchViewMode={this.props.switchViewMode} />
|
<ViewModes currentViewMode={currentMode} switchViewMode={this.props.switchViewMode} />
|
||||||
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
|
<SortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption} />
|
||||||
{(!isCustomPermission) &&
|
{(!isCustomPermission) &&
|
||||||
<div className="cur-view-path-btn" onClick={this.showDirentDetail}>
|
<div className="cur-view-path-btn" onClick={this.showDirentDetail}>
|
||||||
<span className="sf3-font sf3-font-info" aria-label={propertiesText} title={propertiesText}></span>
|
<span className="sf3-font sf3-font-info" aria-label={propertiesText} title={propertiesText}></span>
|
||||||
|
@@ -25,7 +25,6 @@ const propTypes = {
|
|||||||
onItemRename: PropTypes.func,
|
onItemRename: PropTypes.func,
|
||||||
hasNextPage: PropTypes.bool,
|
hasNextPage: PropTypes.bool,
|
||||||
onMonitorRepo: PropTypes.func,
|
onMonitorRepo: PropTypes.func,
|
||||||
theadHidden: PropTypes.bool,
|
|
||||||
inAllLibs: PropTypes.bool,
|
inAllLibs: PropTypes.bool,
|
||||||
onTransferRepo: PropTypes.func,
|
onTransferRepo: PropTypes.func,
|
||||||
};
|
};
|
||||||
@@ -119,7 +118,7 @@ class SharedRepoListView extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderRepoListView = () => {
|
renderRepoListView = () => {
|
||||||
const { currentViewMode = LIST_MODE } = this.props;
|
const { currentViewMode } = this.props;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{this.props.repoList.map((repo, index) => {
|
{this.props.repoList.map((repo, index) => {
|
||||||
@@ -148,12 +147,11 @@ class SharedRepoListView extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderPCUI = () => {
|
renderPCUI = () => {
|
||||||
const { theadHidden = false, currentViewMode = LIST_MODE, currentGroup, libraryType, inAllLibs } = this.props;
|
const { currentViewMode, currentGroup, libraryType, inAllLibs } = this.props;
|
||||||
const { sortByName, sortByTime, sortBySize, sortIcon } = this.getSortMetaData();
|
const { sortByName, sortByTime, sortBySize, sortIcon } = this.getSortMetaData();
|
||||||
|
|
||||||
const content = currentViewMode == LIST_MODE ? (
|
const content = currentViewMode == LIST_MODE ? (
|
||||||
<>
|
<table className={classNames({ 'table-thead-hidden': inAllLibs })}>
|
||||||
<table className={classNames({ 'table-thead-hidden': theadHidden }, { 'repos-container': !inAllLibs })}>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="4%"></th>
|
<th width="4%"></th>
|
||||||
@@ -169,7 +167,6 @@ class SharedRepoListView extends React.Component {
|
|||||||
{this.renderRepoListView()}
|
{this.renderRepoListView()}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="d-flex justify-content-between flex-wrap">
|
<div className="d-flex justify-content-between flex-wrap">
|
||||||
{this.renderRepoListView()}
|
{this.renderRepoListView()}
|
||||||
|
@@ -4,14 +4,21 @@ import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap
|
|||||||
import { gettext } from '../utils/constants';
|
import { gettext } from '../utils/constants';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
sortOptions: PropTypes.array,
|
sortBy: PropTypes.string,
|
||||||
|
sortOrder: PropTypes.string,
|
||||||
onSelectSortOption: PropTypes.func.isRequired
|
onSelectSortOption: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReposSortMenu extends React.Component {
|
class SortMenu extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.sortOptions = [
|
||||||
|
{ value: 'name-asc', text: gettext('By name ascending') },
|
||||||
|
{ value: 'name-desc', text: gettext('By name descending') },
|
||||||
|
{ value: 'time-asc', text: gettext('By time ascending') },
|
||||||
|
{ value: 'time-desc', text: gettext('By time descending') }
|
||||||
|
];
|
||||||
this.state = {
|
this.state = {
|
||||||
isDropdownMenuOpen: false
|
isDropdownMenuOpen: false
|
||||||
};
|
};
|
||||||
@@ -25,7 +32,13 @@ class ReposSortMenu extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isDropdownMenuOpen } = this.state;
|
const { isDropdownMenuOpen } = this.state;
|
||||||
const { sortOptions } = this.props;
|
const { sortBy, sortOrder } = this.props;
|
||||||
|
const sortOptions = this.sortOptions.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
isSelected: item.value == `${sortBy}-${sortOrder}`
|
||||||
|
};
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
isOpen={isDropdownMenuOpen}
|
isOpen={isDropdownMenuOpen}
|
||||||
@@ -59,6 +72,6 @@ class ReposSortMenu extends React.Component {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReposSortMenu.propTypes = propTypes;
|
SortMenu.propTypes = propTypes;
|
||||||
|
|
||||||
export default ReposSortMenu;
|
export default SortMenu;
|
@@ -169,7 +169,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.repos-container {
|
.repos-container {
|
||||||
margin-bottom: 10rem;
|
padding-bottom: 10rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-drop-active::before {
|
.table-drop-active::before {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cookie from 'react-cookies';
|
import cookie from 'react-cookies';
|
||||||
|
import classnames from 'classnames';
|
||||||
import { gettext, username, canAddRepo } from '../../utils/constants';
|
import { gettext, username, canAddRepo } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
@@ -20,6 +21,9 @@ import LeaveGroupDialog from '../../components/dialog/leave-group-dialog';
|
|||||||
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view';
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||||
|
import ViewModes from '../../components/view-modes';
|
||||||
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
|
||||||
import '../../css/group-view.css';
|
import '../../css/group-view.css';
|
||||||
|
|
||||||
@@ -41,6 +45,7 @@ class GroupView extends React.Component {
|
|||||||
currentRepo: null,
|
currentRepo: null,
|
||||||
isStaff: false,
|
isStaff: false,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
|
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||||
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
||||||
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
||||||
isSortOptionsDialogOpen: false,
|
isSortOptionsDialogOpen: false,
|
||||||
@@ -386,8 +391,27 @@ class GroupView extends React.Component {
|
|||||||
return opList;
|
return opList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switchViewMode = (newMode) => {
|
||||||
|
this.setState({
|
||||||
|
currentViewMode: newMode
|
||||||
|
}, () => {
|
||||||
|
localStorage.setItem('sf_repo_list_view_mode', newMode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectSortOption = (sortOption) => {
|
||||||
|
const [sortBy, sortOrder] = sortOption.value.split('-');
|
||||||
|
this.setState({ sortBy, sortOrder }, () => {
|
||||||
|
this.sortItems(sortBy, sortOrder);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { errMessage, emptyTip, currentGroup, isDepartmentGroup, isMembersDialogOpen } = this.state;
|
const {
|
||||||
|
isLoading, repoList, errMessage, emptyTip,
|
||||||
|
currentGroup, isDepartmentGroup, isMembersDialogOpen,
|
||||||
|
currentViewMode, sortBy, sortOrder
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
let useRate = 0;
|
let useRate = 0;
|
||||||
if (isDepartmentGroup && currentGroup.group_quota) {
|
if (isDepartmentGroup && currentGroup.group_quota) {
|
||||||
@@ -409,11 +433,11 @@ class GroupView extends React.Component {
|
|||||||
<span>{currentGroup.name}</span>
|
<span>{currentGroup.name}</span>
|
||||||
<SingleDropdownToolbar opList={opList} />
|
<SingleDropdownToolbar opList={opList} />
|
||||||
</div>
|
</div>
|
||||||
<div className="path-tool">
|
<div className="path-tool d-flex align-items-center">
|
||||||
{isDepartmentGroup && (
|
{isDepartmentGroup && (
|
||||||
<>
|
<>
|
||||||
{currentGroup.group_quota > 0 &&
|
{currentGroup.group_quota > 0 &&
|
||||||
<div className="department-usage-container">
|
<div className="department-usage-container mr-3">
|
||||||
<div className="department-usage">
|
<div className="department-usage">
|
||||||
<span id="quota-bar" className="department-quota-bar"><span id="quota-usage" className="usage" style={{ width: useRate }}></span></span>
|
<span id="quota-bar" className="department-quota-bar"><span id="quota-usage" className="usage" style={{ width: useRate }}></span></span>
|
||||||
<span className="department-quota-info">{Utils.bytesToSize(currentGroup.group_quota_usage)} / {Utils.bytesToSize(currentGroup.group_quota)}</span>
|
<span className="department-quota-info">{Utils.bytesToSize(currentGroup.group_quota_usage)} / {Utils.bytesToSize(currentGroup.group_quota)}</span>
|
||||||
@@ -422,25 +446,39 @@ class GroupView extends React.Component {
|
|||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{Utils.isDesktop() && (
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<div className="mr-2">
|
||||||
|
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
||||||
|
</div>
|
||||||
|
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption}/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{(!Utils.isDesktop() && this.state.repoList.length > 0) &&
|
{(!Utils.isDesktop() && this.state.repoList.length > 0) &&
|
||||||
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
||||||
{this.state.isSortOptionsDialogOpen &&
|
{this.state.isSortOptionsDialogOpen &&
|
||||||
<SortOptionsDialog
|
<SortOptionsDialog
|
||||||
toggleDialog={this.toggleSortOptionsDialog}
|
sortBy={sortBy}
|
||||||
sortBy={this.state.sortBy}
|
sortOrder={sortOrder}
|
||||||
sortOrder={this.state.sortOrder}
|
|
||||||
sortItems={this.sortItems}
|
sortItems={this.sortItems}
|
||||||
|
toggleDialog={this.toggleSortOptionsDialog}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="cur-view-content d-block" onScroll={this.handleScroll}>
|
<div
|
||||||
{this.state.isLoading && <Loading />}
|
className={classnames('cur-view-content', 'd-block', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}
|
||||||
{(!this.state.isLoading && errMessage) && <div className="error text-center mt-2">{errMessage}</div>}
|
onScroll={this.handleScroll}
|
||||||
{(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip}
|
>
|
||||||
{(!this.state.isLoading && this.state.repoList.length > 0) &&
|
{isLoading
|
||||||
|
? <Loading />
|
||||||
|
: errMessage
|
||||||
|
? <p className="error text-center mt-2">{errMessage}</p>
|
||||||
|
: repoList.length == 0
|
||||||
|
? emptyTip
|
||||||
|
: (
|
||||||
<SharedRepoListView
|
<SharedRepoListView
|
||||||
repoList={this.state.repoList}
|
repoList={this.state.repoList}
|
||||||
hasNextPage={this.state.hasNextPage}
|
hasNextPage={this.state.hasNextPage}
|
||||||
@@ -453,7 +491,9 @@ class GroupView extends React.Component {
|
|||||||
onItemRename={this.onItemRename}
|
onItemRename={this.onItemRename}
|
||||||
onMonitorRepo={this.onMonitorRepo}
|
onMonitorRepo={this.onMonitorRepo}
|
||||||
onTransferRepo={this.onItemTransfer}
|
onTransferRepo={this.onItemTransfer}
|
||||||
|
currentViewMode={currentViewMode}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import cookie from 'react-cookies';
|
import cookie from 'react-cookies';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext, canAddRepo, canViewOrg } from '../../utils/constants';
|
import { gettext, canAddRepo, canViewOrg } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
|
||||||
import toaster from '../../components/toast';
|
|
||||||
import Repo from '../../models/repo';
|
import Repo from '../../models/repo';
|
||||||
import Group from '../../models/group';
|
import Group from '../../models/group';
|
||||||
|
import toaster from '../../components/toast';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import ViewModes from '../../components/view-modes';
|
import ViewModes from '../../components/view-modes';
|
||||||
import ReposSortMenu from '../../components/repos-sort-menu';
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
import GuideForNewDialog from '../../components/dialog/guide-for-new-dialog';
|
import GuideForNewDialog from '../../components/dialog/guide-for-new-dialog';
|
||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
||||||
import MylibRepoListView from '../../pages/my-libs/mylib-repo-list-view';
|
import MylibRepoListView from '../../pages/my-libs/mylib-repo-list-view';
|
||||||
import SharedLibraries from '../shared-libs/shared-libraries';
|
import SharedLibraries from '../../pages/shared-libs';
|
||||||
import SharedWithAll from '../../pages/shared-with-all';
|
import SharedWithAll from '../../pages/shared-with-all';
|
||||||
import GroupItem from '../../pages/groups/group-item';
|
import GroupItem from '../../pages/groups/group-item';
|
||||||
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
@@ -24,13 +24,6 @@ import '../../css/files.css';
|
|||||||
class Libraries extends Component {
|
class Libraries extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.sortOptions = [
|
|
||||||
{ value: 'name-asc', text: gettext('By name ascending') },
|
|
||||||
{ value: 'name-desc', text: gettext('By name descending') },
|
|
||||||
{ value: 'time-asc', text: gettext('By time ascending') },
|
|
||||||
{ value: 'time-desc', text: gettext('By time descending') }
|
|
||||||
];
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
// for 'my libs'
|
// for 'my libs'
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
@@ -250,12 +243,6 @@ class Libraries extends Component {
|
|||||||
const { isLoading, currentViewMode, sortBy, sortOrder, groupList } = this.state;
|
const { isLoading, currentViewMode, sortBy, sortOrder, groupList } = this.state;
|
||||||
const isDesktop = Utils.isDesktop();
|
const isDesktop = Utils.isDesktop();
|
||||||
|
|
||||||
const sortOptions = this.sortOptions.map(item => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
isSelected: item.value == `${sortBy}-${sortOrder}`
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="main-panel-center flex-row">
|
<div className="main-panel-center flex-row">
|
||||||
@@ -267,14 +254,13 @@ class Libraries extends Component {
|
|||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
||||||
</div>
|
</div>
|
||||||
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
|
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{isLoading ?
|
<div className="cur-view-content repos-container" id="files-content-container">
|
||||||
<Loading /> :
|
{isLoading ? <Loading /> : (
|
||||||
<div className="cur-view-content" id="files-content-container">
|
<>
|
||||||
|
|
||||||
{(Utils.isDesktop() && currentViewMode == LIST_MODE) && (
|
{(Utils.isDesktop() && currentViewMode == LIST_MODE) && (
|
||||||
<table aria-hidden={true} className="my-3">
|
<table aria-hidden={true} className="my-3">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -305,10 +291,11 @@ class Libraries extends Component {
|
|||||||
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
|
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{this.state.errorMsg ? <p className="error text-center mt-8">{this.state.errorMsg}</p> : (
|
{this.state.errorMsg
|
||||||
this.state.repoList.length === 0 ? (
|
? <p className="error text-center mt-8">{this.state.errorMsg}</p>
|
||||||
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>
|
: this.state.repoList.length == 0
|
||||||
) : (
|
? <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>
|
||||||
|
: (
|
||||||
<MylibRepoListView
|
<MylibRepoListView
|
||||||
sortBy={this.state.sortBy}
|
sortBy={this.state.sortBy}
|
||||||
sortOrder={this.state.sortOrder}
|
sortOrder={this.state.sortOrder}
|
||||||
@@ -322,10 +309,11 @@ class Libraries extends Component {
|
|||||||
inAllLibs={true}
|
inAllLibs={true}
|
||||||
currentViewMode={currentViewMode}
|
currentViewMode={currentViewMode}
|
||||||
/>
|
/>
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="pb-3">
|
<div className="pb-3">
|
||||||
<SharedLibraries
|
<SharedLibraries
|
||||||
repoList={this.state.sharedRepoList}
|
repoList={this.state.sharedRepoList}
|
||||||
@@ -333,6 +321,7 @@ class Libraries extends Component {
|
|||||||
currentViewMode={currentViewMode}
|
currentViewMode={currentViewMode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{canViewOrg &&
|
{canViewOrg &&
|
||||||
<div className="pb-3">
|
<div className="pb-3">
|
||||||
<SharedWithAll
|
<SharedWithAll
|
||||||
@@ -342,7 +331,7 @@ class Libraries extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="repos-container">
|
|
||||||
{groupList.length > 0 && groupList.map((group) => {
|
{groupList.length > 0 && groupList.map((group) => {
|
||||||
return (
|
return (
|
||||||
<GroupItem
|
<GroupItem
|
||||||
@@ -355,10 +344,10 @@ class Libraries extends Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{!isLoading && !this.state.errorMsg && this.state.isGuideForNewDialogOpen &&
|
{!isLoading && !this.state.errorMsg && this.state.isGuideForNewDialogOpen &&
|
||||||
<GuideForNewDialog
|
<GuideForNewDialog
|
||||||
toggleDialog={this.toggleGuideForNewDialog}
|
toggleDialog={this.toggleGuideForNewDialog}
|
||||||
|
@@ -1,18 +1,22 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import cookie from 'react-cookies';
|
import cookie from 'react-cookies';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import Repo from '../../models/repo';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import Repo from '../../models/repo';
|
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import EmptyTip from '../../components/empty-tip';
|
import EmptyTip from '../../components/empty-tip';
|
||||||
import MylibRepoListView from './mylib-repo-list-view';
|
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
|
||||||
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
|
||||||
import ModalPortal from '../../components/modal-portal';
|
import ModalPortal from '../../components/modal-portal';
|
||||||
|
import ViewModes from '../../components/view-modes';
|
||||||
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
|
import SingleDropdownToolbar from '../../components/toolbar/single-dropdown-toolbar';
|
||||||
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
||||||
import DeletedReposDialog from '../../components/dialog/my-deleted-repos';
|
import DeletedReposDialog from '../../components/dialog/my-deleted-repos';
|
||||||
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import MylibRepoListView from './mylib-repo-list-view';
|
||||||
|
|
||||||
class MyLibraries extends Component {
|
class MyLibraries extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -24,6 +28,7 @@ class MyLibraries extends Component {
|
|||||||
isDeletedReposDialogOpen: false,
|
isDeletedReposDialogOpen: false,
|
||||||
isCreateRepoDialogOpen: false,
|
isCreateRepoDialogOpen: false,
|
||||||
isSortOptionsDialogOpen: false,
|
isSortOptionsDialogOpen: false,
|
||||||
|
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||||
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
||||||
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
||||||
};
|
};
|
||||||
@@ -135,7 +140,24 @@ class MyLibraries extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switchViewMode = (newMode) => {
|
||||||
|
this.setState({
|
||||||
|
currentViewMode: newMode
|
||||||
|
}, () => {
|
||||||
|
localStorage.setItem('sf_repo_list_view_mode', newMode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectSortOption = (sortOption) => {
|
||||||
|
const [sortBy, sortOrder] = sortOption.value.split('-');
|
||||||
|
this.setState({ sortBy, sortOrder }, () => {
|
||||||
|
this.sortRepoList(sortBy, sortOrder);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { isLoading, errorMsg, currentViewMode, sortBy, sortOrder, repoList } = this.state;
|
||||||
|
const isDesktop = Utils.isDesktop();
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="main-panel-center flex-row">
|
<div className="main-panel-center flex-row">
|
||||||
@@ -150,33 +172,49 @@ class MyLibraries extends Component {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</h3>
|
</h3>
|
||||||
<div>
|
{isDesktop ? (
|
||||||
{(!Utils.isDesktop() && this.state.repoList.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
<div className="d-flex align-items-center">
|
||||||
|
<div className="mr-2">
|
||||||
|
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
||||||
</div>
|
</div>
|
||||||
|
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption} />
|
||||||
</div>
|
</div>
|
||||||
<div className="cur-view-content">
|
) : (
|
||||||
{this.state.isLoading && <Loading />}
|
<>
|
||||||
{!this.state.isLoading && this.state.errorMsg && <p className="error text-center mt-8">{this.state.errorMsg}</p>}
|
{repoList.length > 0 &&
|
||||||
{!this.state.isLoading && !this.state.errorMsg && this.state.repoList.length === 0 && this.emptyTip}
|
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
|
||||||
{!this.state.isLoading && !this.state.errorMsg && this.state.repoList.length > 0 &&
|
}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={classnames('cur-view-content', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}>
|
||||||
|
{isLoading
|
||||||
|
? <Loading />
|
||||||
|
: errorMsg
|
||||||
|
? <p className="error text-center mt-8">{errorMsg}</p>
|
||||||
|
: repoList.length == 0
|
||||||
|
? this.emptyTip
|
||||||
|
: (
|
||||||
<MylibRepoListView
|
<MylibRepoListView
|
||||||
sortBy={this.state.sortBy}
|
sortBy={sortBy}
|
||||||
sortOrder={this.state.sortOrder}
|
sortOrder={sortOrder}
|
||||||
repoList={this.state.repoList}
|
repoList={this.state.repoList}
|
||||||
onRenameRepo={this.onRenameRepo}
|
onRenameRepo={this.onRenameRepo}
|
||||||
onDeleteRepo={this.onDeleteRepo}
|
onDeleteRepo={this.onDeleteRepo}
|
||||||
onTransferRepo={this.onTransferRepo}
|
onTransferRepo={this.onTransferRepo}
|
||||||
onMonitorRepo={this.onMonitorRepo}
|
onMonitorRepo={this.onMonitorRepo}
|
||||||
sortRepoList={this.sortRepoList}
|
sortRepoList={this.sortRepoList}
|
||||||
|
currentViewMode={currentViewMode}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.state.isSortOptionsDialogOpen &&
|
{this.state.isSortOptionsDialogOpen &&
|
||||||
<SortOptionsDialog
|
<SortOptionsDialog
|
||||||
toggleDialog={this.toggleSortOptionsDialog}
|
toggleDialog={this.toggleSortOptionsDialog}
|
||||||
sortBy={this.state.sortBy}
|
sortBy={sortBy}
|
||||||
sortOrder={this.state.sortOrder}
|
sortOrder={sortOrder}
|
||||||
sortItems={this.sortRepoList}
|
sortItems={this.sortRepoList}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@@ -117,7 +117,7 @@ class MylibRepoListView extends React.Component {
|
|||||||
const sortIcon = this.props.sortOrder === 'asc' ? <span className="sf3-font sf3-font-down rotate-180 d-inline-block"></span> : <span className="sf3-font sf3-font-down"></span>;
|
const sortIcon = this.props.sortOrder === 'asc' ? <span className="sf3-font sf3-font-down rotate-180 d-inline-block"></span> : <span className="sf3-font sf3-font-down"></span>;
|
||||||
|
|
||||||
return currentViewMode == LIST_MODE ? (
|
return currentViewMode == LIST_MODE ? (
|
||||||
<table className={classNames({ 'table-thead-hidden': inAllLibs }, { 'repos-container': !inAllLibs })}>
|
<table className={classNames({ 'table-thead-hidden': inAllLibs })}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="4%"></th>
|
<th width="4%"></th>
|
||||||
|
177
frontend/src/pages/shared-libs/content.js
Normal file
177
frontend/src/pages/shared-libs/content.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import Loading from '../../components/loading';
|
||||||
|
import EmptyTip from '../../components/empty-tip';
|
||||||
|
import LibsMobileThead from '../../components/libs-mobile-thead';
|
||||||
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import ContextMenu from '../../components/context-menu/context-menu';
|
||||||
|
import { hideMenu, handleContextClick } from '../../components/context-menu/actions';
|
||||||
|
import Item from './item';
|
||||||
|
|
||||||
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false
|
||||||
|
};
|
||||||
|
this.libItems = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
freezeItem = (freezed) => {
|
||||||
|
this.setState({
|
||||||
|
isItemFreezed: freezed
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
sortByName = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const sortBy = 'name';
|
||||||
|
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
||||||
|
this.props.sortItems(sortBy, sortOrder);
|
||||||
|
};
|
||||||
|
|
||||||
|
sortByTime = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const sortBy = 'time';
|
||||||
|
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
||||||
|
this.props.sortItems(sortBy, sortOrder);
|
||||||
|
};
|
||||||
|
|
||||||
|
sortBySize = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const sortBy = 'size';
|
||||||
|
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
||||||
|
this.props.sortItems(sortBy, sortOrder);
|
||||||
|
};
|
||||||
|
|
||||||
|
onContextMenu = (event, repo) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const id = 'shared-libs-item-menu';
|
||||||
|
const menuList = Utils.getSharedLibsOperationList(repo);
|
||||||
|
handleContextClick(event, id, menuList, repo);
|
||||||
|
};
|
||||||
|
|
||||||
|
setLibItemRef = (index) => item => {
|
||||||
|
this.libItems[index] = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
getLibIndex = (lib) => {
|
||||||
|
return this.props.items.findIndex(item => {
|
||||||
|
return item.repo_id === lib.repo_id;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMenuItemClick = (operation, currentObject, event) => {
|
||||||
|
const index = this.getLibIndex(currentObject);
|
||||||
|
this.libItems[index].onMenuItemClick(operation, event);
|
||||||
|
|
||||||
|
hideMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading, errorMsg, items, sortBy, sortOrder, inAllLibs, currentViewMode } = this.props;
|
||||||
|
|
||||||
|
const emptyTip = inAllLibs ?
|
||||||
|
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No shared libraries')}</p> :
|
||||||
|
<EmptyTip
|
||||||
|
title={gettext('No shared libraries')}
|
||||||
|
text={gettext('No libraries have been shared directly with you. A shared library can be shared with full or restricted permission. If you need access to a library owned by another user, ask the user to share the library with you.')}
|
||||||
|
>
|
||||||
|
</EmptyTip>;
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
} else if (errorMsg) {
|
||||||
|
return <p className="error text-center">{errorMsg}</p>;
|
||||||
|
} else {
|
||||||
|
// sort
|
||||||
|
const sortByName = sortBy == 'name';
|
||||||
|
const sortByTime = sortBy == 'time';
|
||||||
|
const sortBySize = sortBy == 'size';
|
||||||
|
const sortIcon = sortOrder == 'asc' ? <span className="sf3-font sf3-font-down rotate-180 d-inline-block"></span> : <span className="sf3-font sf3-font-down"></span>;
|
||||||
|
|
||||||
|
const isDesktop = Utils.isDesktop();
|
||||||
|
const itemsContent = (
|
||||||
|
<>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
return <Item
|
||||||
|
ref={this.setLibItemRef(index)}
|
||||||
|
key={index}
|
||||||
|
data={item}
|
||||||
|
isDesktop={isDesktop}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
freezeItem={this.freezeItem}
|
||||||
|
onMonitorRepo={this.props.onMonitorRepo}
|
||||||
|
currentViewMode={currentViewMode}
|
||||||
|
onContextMenu={this.onContextMenu}
|
||||||
|
/>;
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
let content;
|
||||||
|
if (isDesktop) {
|
||||||
|
content = currentViewMode == LIST_MODE ? (
|
||||||
|
<table className={classNames({ 'table-thead-hidden': inAllLibs })}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="4%"></th>
|
||||||
|
<th width="3%"><span className="sr-only">{gettext('Library Type')}</span></th>
|
||||||
|
<th width="35%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
|
||||||
|
<th width="10%"><span className="sr-only">{gettext('Actions')}</span></th>
|
||||||
|
<th width="14%"><a className="d-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBySize && sortIcon}</a></th>
|
||||||
|
<th width="17%"><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>
|
||||||
|
<th width="17%">{gettext('Owner')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{itemsContent}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
) : (
|
||||||
|
<div className="d-flex justify-content-between flex-wrap">
|
||||||
|
{itemsContent}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// mobile
|
||||||
|
content = (
|
||||||
|
<table className="table-thead-hidden">
|
||||||
|
{<LibsMobileThead inAllLibs={inAllLibs} />}
|
||||||
|
<tbody>
|
||||||
|
{itemsContent}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.length ? (
|
||||||
|
<>
|
||||||
|
{content}
|
||||||
|
<ContextMenu
|
||||||
|
id="shared-libs-item-menu"
|
||||||
|
onMenuItemClick={this.onMenuItemClick}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : emptyTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Content.propTypes = {
|
||||||
|
currentViewMode: PropTypes.string,
|
||||||
|
inAllLibs: PropTypes.bool.isRequired,
|
||||||
|
loading: PropTypes.bool.isRequired,
|
||||||
|
errorMsg: PropTypes.string.isRequired,
|
||||||
|
items: PropTypes.array.isRequired,
|
||||||
|
sortBy: PropTypes.string.isRequired,
|
||||||
|
sortOrder: PropTypes.string.isRequired,
|
||||||
|
sortItems: PropTypes.func.isRequired,
|
||||||
|
onMonitorRepo: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Content;
|
178
frontend/src/pages/shared-libs/index.js
Normal file
178
frontend/src/pages/shared-libs/index.js
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import cookie from 'react-cookies';
|
||||||
|
import Repo from '../../models/repo';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import ViewModes from '../../components/view-modes';
|
||||||
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
|
import SortOptionsDialog from '../../components/dialog/sort-options';
|
||||||
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import Content from './content';
|
||||||
|
|
||||||
|
class SharedLibraries extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
errorMsg: '',
|
||||||
|
items: [],
|
||||||
|
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||||
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
||||||
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
||||||
|
isSortOptionsDialogOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (!this.props.repoList) {
|
||||||
|
seafileAPI.listRepos({ type: 'shared' }).then((res) => {
|
||||||
|
let repoList = res.data.repos.map((item) => {
|
||||||
|
return new Repo(item);
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
items: Utils.sortRepos(repoList, this.state.sortBy, this.state.sortOrder)
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
errorMsg: Utils.getErrorMsg(error, true)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
items: this.props.repoList
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortItems = (sortBy, sortOrder) => {
|
||||||
|
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
||||||
|
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
||||||
|
this.setState({
|
||||||
|
sortBy: sortBy,
|
||||||
|
sortOrder: sortOrder,
|
||||||
|
items: Utils.sortRepos(this.state.items, sortBy, sortOrder)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleSortOptionsDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isSortOptionsDialogOpen: !this.state.isSortOptionsDialogOpen
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMonitorRepo = (repo, monitored) => {
|
||||||
|
let items = this.state.items.map(item => {
|
||||||
|
if (item.repo_id === repo.repo_id) {
|
||||||
|
item.monitored = monitored;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
this.setState({ items: items });
|
||||||
|
};
|
||||||
|
|
||||||
|
renderContent = (currentViewMode) => {
|
||||||
|
const { inAllLibs = false, repoList } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
||||||
|
const { items } = this.state;
|
||||||
|
return (
|
||||||
|
<Content
|
||||||
|
loading={this.state.loading}
|
||||||
|
errorMsg={this.state.errorMsg}
|
||||||
|
items={inAllLibs ? repoList : items}
|
||||||
|
sortBy={this.state.sortBy}
|
||||||
|
sortOrder={this.state.sortOrder}
|
||||||
|
sortItems={this.sortItems}
|
||||||
|
onMonitorRepo={this.onMonitorRepo}
|
||||||
|
inAllLibs={inAllLibs}
|
||||||
|
currentViewMode={currentViewMode}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderSortIconInMobile = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{(!Utils.isDesktop() && this.state.items.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
switchViewMode = (newMode) => {
|
||||||
|
this.setState({
|
||||||
|
currentViewMode: newMode
|
||||||
|
}, () => {
|
||||||
|
localStorage.setItem('sf_repo_list_view_mode', newMode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectSortOption = (sortOption) => {
|
||||||
|
const [sortBy, sortOrder] = sortOption.value.split('-');
|
||||||
|
this.setState({ sortBy, sortOrder }, () => {
|
||||||
|
this.sortItems(sortBy, sortOrder);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { inAllLibs = false, currentViewMode: propCurrentViewMode } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
||||||
|
const { sortBy, sortOrder, currentViewMode: stateCurrentViewMode } = this.state;
|
||||||
|
const currentViewMode = inAllLibs ? propCurrentViewMode : stateCurrentViewMode;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{inAllLibs ? (
|
||||||
|
<>
|
||||||
|
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
|
||||||
|
<h4 className="sf-heading m-0">
|
||||||
|
<span className="sf3-font-share-with-me sf3-font nav-icon" aria-hidden="true"></span>
|
||||||
|
{gettext('Shared with me')}
|
||||||
|
</h4>
|
||||||
|
{this.renderSortIconInMobile()}
|
||||||
|
</div>
|
||||||
|
{this.renderContent(currentViewMode)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="main-panel-center">
|
||||||
|
<div className="cur-view-container">
|
||||||
|
<div className="cur-view-path">
|
||||||
|
<h3 className="sf-heading m-0">{gettext('Shared with me')}</h3>
|
||||||
|
{Utils.isDesktop() && (
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<div className="mr-2">
|
||||||
|
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
||||||
|
</div>
|
||||||
|
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption}/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{this.renderSortIconInMobile()}
|
||||||
|
</div>
|
||||||
|
<div className={classnames('cur-view-content', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}>
|
||||||
|
{this.renderContent(currentViewMode)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{this.state.isSortOptionsDialogOpen &&
|
||||||
|
<SortOptionsDialog
|
||||||
|
toggleDialog={this.toggleSortOptionsDialog}
|
||||||
|
sortBy={this.state.sortBy}
|
||||||
|
sortOrder={this.state.sortOrder}
|
||||||
|
sortItems={this.sortItems}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedLibraries.propTypes = {
|
||||||
|
currentViewMode: PropTypes.string,
|
||||||
|
inAllLibs: PropTypes.bool,
|
||||||
|
repoList: PropTypes.array,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SharedLibraries;
|
@@ -2,184 +2,19 @@ import React, { Component, Fragment } from 'react';
|
|||||||
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
|
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import classNames from 'classnames';
|
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import cookie from 'react-cookies';
|
|
||||||
import { Link, navigate } from '@gatsbyjs/reach-router';
|
import { Link, navigate } from '@gatsbyjs/reach-router';
|
||||||
import { gettext, siteRoot, isPro } from '../../utils/constants';
|
import { gettext, siteRoot, isPro } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import Repo from '../../models/repo';
|
|
||||||
import Loading from '../../components/loading';
|
|
||||||
import EmptyTip from '../../components/empty-tip';
|
|
||||||
import LibsMobileThead from '../../components/libs-mobile-thead';
|
|
||||||
import ModalPortal from '../../components/modal-portal';
|
import ModalPortal from '../../components/modal-portal';
|
||||||
import ShareDialog from '../../components/dialog/share-dialog';
|
import ShareDialog from '../../components/dialog/share-dialog';
|
||||||
import SortOptionsDialog from '../../components/dialog/sort-options';
|
|
||||||
import RepoMonitoredIcon from '../../components/repo-monitored-icon';
|
import RepoMonitoredIcon from '../../components/repo-monitored-icon';
|
||||||
import { GRID_MODE, LIST_MODE } from '../../components/dir-view-mode/constants';
|
import { GRID_MODE, LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
import ContextMenu from '../../components/context-menu/context-menu';
|
|
||||||
import { hideMenu, handleContextClick } from '../../components/context-menu/actions';
|
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
class Content extends Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isItemFreezed: false
|
|
||||||
};
|
|
||||||
this.libItems = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
freezeItem = (freezed) => {
|
|
||||||
this.setState({
|
|
||||||
isItemFreezed: freezed
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
sortByName = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const sortBy = 'name';
|
|
||||||
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
|
||||||
this.props.sortItems(sortBy, sortOrder);
|
|
||||||
};
|
|
||||||
|
|
||||||
sortByTime = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const sortBy = 'time';
|
|
||||||
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
|
||||||
this.props.sortItems(sortBy, sortOrder);
|
|
||||||
};
|
|
||||||
|
|
||||||
sortBySize = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const sortBy = 'size';
|
|
||||||
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
|
||||||
this.props.sortItems(sortBy, sortOrder);
|
|
||||||
};
|
|
||||||
|
|
||||||
onContextMenu = (event, repo) => {
|
|
||||||
event.preventDefault();
|
|
||||||
const id = 'shared-libs-item-menu';
|
|
||||||
const menuList = Utils.getSharedLibsOperationList(repo);
|
|
||||||
handleContextClick(event, id, menuList, repo);
|
|
||||||
};
|
|
||||||
|
|
||||||
setLibItemRef = (index) => item => {
|
|
||||||
this.libItems[index] = item;
|
|
||||||
};
|
|
||||||
|
|
||||||
getLibIndex = (lib) => {
|
|
||||||
return this.props.items.findIndex(item => {
|
|
||||||
return item.repo_id === lib.repo_id;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMenuItemClick = (operation, currentObject, event) => {
|
|
||||||
const index = this.getLibIndex(currentObject);
|
|
||||||
this.libItems[index].onMenuItemClick(operation, event);
|
|
||||||
|
|
||||||
hideMenu();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { loading, errorMsg, items, sortBy, sortOrder, theadHidden, inAllLibs, currentViewMode } = this.props;
|
|
||||||
|
|
||||||
const emptyTip = inAllLibs ?
|
|
||||||
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No shared libraries')}</p> :
|
|
||||||
<EmptyTip
|
|
||||||
title={gettext('No shared libraries')}
|
|
||||||
text={gettext('No libraries have been shared directly with you. A shared library can be shared with full or restricted permission. If you need access to a library owned by another user, ask the user to share the library with you.')}
|
|
||||||
>
|
|
||||||
</EmptyTip>;
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return <Loading />;
|
|
||||||
} else if (errorMsg) {
|
|
||||||
return <p className="error text-center">{errorMsg}</p>;
|
|
||||||
} else {
|
|
||||||
// sort
|
|
||||||
const sortByName = sortBy == 'name';
|
|
||||||
const sortByTime = sortBy == 'time';
|
|
||||||
const sortBySize = sortBy == 'size';
|
|
||||||
const sortIcon = sortOrder == 'asc' ? <span className="sf3-font sf3-font-down rotate-180 d-inline-block"></span> : <span className="sf3-font sf3-font-down"></span>;
|
|
||||||
|
|
||||||
const desktopThead = (
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th width="4%"></th>
|
|
||||||
<th width="3%"><span className="sr-only">{gettext('Library Type')}</span></th>
|
|
||||||
<th width="35%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
|
|
||||||
<th width="10%"><span className="sr-only">{gettext('Actions')}</span></th>
|
|
||||||
<th width="14%"><a className="d-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBySize && sortIcon}</a></th>
|
|
||||||
<th width="17%"><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>
|
|
||||||
<th width="17%">{gettext('Owner')}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
);
|
|
||||||
|
|
||||||
const isDesktop = Utils.isDesktop();
|
|
||||||
const itemsContent = (
|
|
||||||
<>
|
|
||||||
{items.map((item, index) => {
|
|
||||||
return <Item
|
|
||||||
ref={this.setLibItemRef(index)}
|
|
||||||
key={index}
|
|
||||||
data={item}
|
|
||||||
isDesktop={isDesktop}
|
|
||||||
isItemFreezed={this.state.isItemFreezed}
|
|
||||||
freezeItem={this.freezeItem}
|
|
||||||
onMonitorRepo={this.props.onMonitorRepo}
|
|
||||||
currentViewMode={currentViewMode}
|
|
||||||
onContextMenu={this.onContextMenu}
|
|
||||||
/>;
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
const content = currentViewMode == LIST_MODE ? (
|
|
||||||
<>
|
|
||||||
<table className={classNames({ 'repos-container': !inAllLibs }, { 'table-thead-hidden': !(isDesktop && !theadHidden) })}>
|
|
||||||
{isDesktop ? desktopThead : <LibsMobileThead inAllLibs={inAllLibs} />}
|
|
||||||
<tbody>
|
|
||||||
{itemsContent}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="d-flex justify-content-between flex-wrap">
|
|
||||||
{itemsContent}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return items.length ? (
|
|
||||||
<>
|
|
||||||
{content}
|
|
||||||
<ContextMenu
|
|
||||||
id="shared-libs-item-menu"
|
|
||||||
onMenuItemClick={this.onMenuItemClick}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : emptyTip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Content.propTypes = {
|
|
||||||
currentViewMode: PropTypes.string,
|
|
||||||
inAllLibs: PropTypes.bool.isRequired,
|
|
||||||
theadHidden: PropTypes.bool.isRequired,
|
|
||||||
loading: PropTypes.bool.isRequired,
|
|
||||||
errorMsg: PropTypes.string.isRequired,
|
|
||||||
items: PropTypes.array.isRequired,
|
|
||||||
sortBy: PropTypes.string.isRequired,
|
|
||||||
sortOrder: PropTypes.string.isRequired,
|
|
||||||
sortItems: PropTypes.func.isRequired,
|
|
||||||
onMonitorRepo: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
class Item extends Component {
|
class Item extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -530,141 +365,4 @@ Item.propTypes = {
|
|||||||
onContextMenu: PropTypes.func.isRequired,
|
onContextMenu: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedLibraries extends Component {
|
export default Item;
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
loading: true,
|
|
||||||
errorMsg: '',
|
|
||||||
items: [],
|
|
||||||
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
|
||||||
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
|
||||||
isSortOptionsDialogOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (!this.props.repoList) {
|
|
||||||
seafileAPI.listRepos({ type: 'shared' }).then((res) => {
|
|
||||||
let repoList = res.data.repos.map((item) => {
|
|
||||||
return new Repo(item);
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
items: Utils.sortRepos(repoList, this.state.sortBy, this.state.sortOrder)
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
errorMsg: Utils.getErrorMsg(error, true)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
items: this.props.repoList
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sortItems = (sortBy, sortOrder) => {
|
|
||||||
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
|
||||||
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
|
||||||
this.setState({
|
|
||||||
sortBy: sortBy,
|
|
||||||
sortOrder: sortOrder,
|
|
||||||
items: Utils.sortRepos(this.state.items, sortBy, sortOrder)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleSortOptionsDialog = () => {
|
|
||||||
this.setState({
|
|
||||||
isSortOptionsDialogOpen: !this.state.isSortOptionsDialogOpen
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMonitorRepo = (repo, monitored) => {
|
|
||||||
let items = this.state.items.map(item => {
|
|
||||||
if (item.repo_id === repo.repo_id) {
|
|
||||||
item.monitored = monitored;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
this.setState({ items: items });
|
|
||||||
};
|
|
||||||
|
|
||||||
renderContent = () => {
|
|
||||||
const { inAllLibs = false, currentViewMode = LIST_MODE, repoList } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
|
||||||
const { items } = this.state;
|
|
||||||
return (
|
|
||||||
<Content
|
|
||||||
loading={this.state.loading}
|
|
||||||
errorMsg={this.state.errorMsg}
|
|
||||||
items={inAllLibs ? repoList : items}
|
|
||||||
sortBy={this.state.sortBy}
|
|
||||||
sortOrder={this.state.sortOrder}
|
|
||||||
sortItems={this.sortItems}
|
|
||||||
onMonitorRepo={this.onMonitorRepo}
|
|
||||||
theadHidden={inAllLibs}
|
|
||||||
inAllLibs={inAllLibs}
|
|
||||||
currentViewMode={currentViewMode}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderSortIconInMobile = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{(!Utils.isDesktop() && this.state.items.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { inAllLibs = false, currentViewMode = LIST_MODE } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
{inAllLibs ? (
|
|
||||||
<>
|
|
||||||
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
|
|
||||||
<h4 className="sf-heading m-0">
|
|
||||||
<span className="sf3-font-share-with-me sf3-font nav-icon" aria-hidden="true"></span>
|
|
||||||
{gettext('Shared with me')}
|
|
||||||
</h4>
|
|
||||||
{this.renderSortIconInMobile()}
|
|
||||||
</div>
|
|
||||||
{this.renderContent()}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="main-panel-center">
|
|
||||||
<div className="cur-view-container">
|
|
||||||
<div className="cur-view-path">
|
|
||||||
<h3 className="sf-heading m-0">{gettext('Shared with me')}</h3>
|
|
||||||
{this.renderSortIconInMobile()}
|
|
||||||
</div>
|
|
||||||
<div className="cur-view-content">
|
|
||||||
{this.renderContent()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{this.state.isSortOptionsDialogOpen &&
|
|
||||||
<SortOptionsDialog
|
|
||||||
toggleDialog={this.toggleSortOptionsDialog}
|
|
||||||
sortBy={this.state.sortBy}
|
|
||||||
sortOrder={this.state.sortOrder}
|
|
||||||
sortItems={this.sortItems}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibraries.propTypes = {
|
|
||||||
currentViewMode: PropTypes.string,
|
|
||||||
inAllLibs: PropTypes.bool,
|
|
||||||
repoList: PropTypes.array,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SharedLibraries;
|
|
@@ -1,6 +1,7 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cookie from 'react-cookies';
|
import cookie from 'react-cookies';
|
||||||
|
import classnames from 'classnames';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext, canAddPublicRepo } from '../../utils/constants';
|
import { gettext, canAddPublicRepo } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
@@ -15,6 +16,8 @@ import ModalPortal from '../../components/modal-portal';
|
|||||||
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
|
||||||
import ShareRepoDialog from '../../components/dialog/share-repo-dialog';
|
import ShareRepoDialog from '../../components/dialog/share-repo-dialog';
|
||||||
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
import { LIST_MODE } from '../../components/dir-view-mode/constants';
|
||||||
|
import ViewModes from '../../components/view-modes';
|
||||||
|
import ReposSortMenu from '../../components/sort-menu';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
currentViewMode: PropTypes.string,
|
currentViewMode: PropTypes.string,
|
||||||
@@ -32,6 +35,7 @@ class SharedWithAll extends React.Component {
|
|||||||
repoList: [],
|
repoList: [],
|
||||||
isCreateRepoDialogOpen: false,
|
isCreateRepoDialogOpen: false,
|
||||||
isSelectRepoDialogOpen: false,
|
isSelectRepoDialogOpen: false,
|
||||||
|
currentViewMode: localStorage.getItem('sf_repo_list_view_mode') || LIST_MODE,
|
||||||
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time' or 'size'
|
||||||
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
||||||
isSortOptionsDialogOpen: false,
|
isSortOptionsDialogOpen: false,
|
||||||
@@ -120,11 +124,12 @@ class SharedWithAll extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
renderContent = () => {
|
renderContent = (currentViewMode) => {
|
||||||
const { inAllLibs = false, currentViewMode = LIST_MODE } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
const { inAllLibs = false } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
||||||
const { errMessage } = this.state;
|
const { isLoading, errMessage, repoList } = this.state;
|
||||||
const emptyTip = inAllLibs ?
|
const emptyTip = inAllLibs
|
||||||
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No public libraries')}</p> : (
|
? <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No public libraries')}</p>
|
||||||
|
: (
|
||||||
<EmptyTip
|
<EmptyTip
|
||||||
title={gettext('No public libraries')}
|
title={gettext('No public libraries')}
|
||||||
text={gettext('No public libraries have been created yet. A public library is accessible by all users. You can create a public library by clicking the "Add Library" item in the dropdown menu.')}
|
text={gettext('No public libraries have been created yet. A public library is accessible by all users. You can create a public library by clicking the "Add Library" item in the dropdown menu.')}
|
||||||
@@ -133,10 +138,13 @@ class SharedWithAll extends React.Component {
|
|||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{this.state.isLoading && <Loading />}
|
{isLoading
|
||||||
{(!this.state.isLoading && errMessage) && errMessage}
|
? <Loading />
|
||||||
{(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip}
|
: errMessage
|
||||||
{(!this.state.isLoading && this.state.repoList.length > 0) &&
|
? <p className="error text-center">{errMessage}</p>
|
||||||
|
: repoList.length == 0
|
||||||
|
? emptyTip
|
||||||
|
: (
|
||||||
<SharedRepoListView
|
<SharedRepoListView
|
||||||
key='public-shared-view'
|
key='public-shared-view'
|
||||||
libraryType={this.state.libraryType}
|
libraryType={this.state.libraryType}
|
||||||
@@ -146,11 +154,10 @@ class SharedWithAll extends React.Component {
|
|||||||
sortItems={this.sortItems}
|
sortItems={this.sortItems}
|
||||||
onItemUnshare={this.onItemUnshare}
|
onItemUnshare={this.onItemUnshare}
|
||||||
onItemDelete={this.onItemDelete}
|
onItemDelete={this.onItemDelete}
|
||||||
theadHidden={inAllLibs}
|
|
||||||
currentViewMode={currentViewMode}
|
currentViewMode={currentViewMode}
|
||||||
inAllLibs={inAllLibs}
|
inAllLibs={inAllLibs}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -203,8 +210,25 @@ class SharedWithAll extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switchViewMode = (newMode) => {
|
||||||
|
this.setState({
|
||||||
|
currentViewMode: newMode
|
||||||
|
}, () => {
|
||||||
|
localStorage.setItem('sf_repo_list_view_mode', newMode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectSortOption = (sortOption) => {
|
||||||
|
const [sortBy, sortOrder] = sortOption.value.split('-');
|
||||||
|
this.setState({ sortBy, sortOrder }, () => {
|
||||||
|
this.sortItems(sortBy, sortOrder);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { inAllLibs = false, currentViewMode = LIST_MODE } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
const { inAllLibs = false, currentViewMode: propCurrentViewMode } = this.props; // inAllLibs: in 'All Libs'('Files') page
|
||||||
|
const { sortBy, sortOrder, currentViewMode: stateCurrentViewMode } = this.state;
|
||||||
|
const currentViewMode = inAllLibs ? propCurrentViewMode : stateCurrentViewMode;
|
||||||
|
|
||||||
if (inAllLibs) {
|
if (inAllLibs) {
|
||||||
return (
|
return (
|
||||||
@@ -216,7 +240,7 @@ class SharedWithAll extends React.Component {
|
|||||||
</h4>
|
</h4>
|
||||||
{this.renderSortIconInMobile()}
|
{this.renderSortIconInMobile()}
|
||||||
</div>
|
</div>
|
||||||
{this.renderContent()}
|
{this.renderContent(currentViewMode)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -237,10 +261,18 @@ class SharedWithAll extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</h3>
|
</h3>
|
||||||
|
{Utils.isDesktop() && (
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<div className="mr-2">
|
||||||
|
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
|
||||||
|
</div>
|
||||||
|
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption}/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{this.renderSortIconInMobile()}
|
{this.renderSortIconInMobile()}
|
||||||
</div>
|
</div>
|
||||||
<div className="cur-view-content">
|
<div className={classnames('cur-view-content', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}>
|
||||||
{this.renderContent()}
|
{this.renderContent(currentViewMode)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user