1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-09 19:01:42 +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:
llj
2024-11-25 10:23:42 +08:00
committed by GitHub
parent e7a4e29239
commit bacc9e2aa5
13 changed files with 653 additions and 505 deletions

View File

@@ -24,7 +24,7 @@ import ShareAdminLibraries from './pages/share-admin/libraries';
import ShareAdminFolders from './pages/share-admin/folders';
import ShareAdminShareLinks from './pages/share-admin/share-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 OCMViaWebdav from './pages/ocm-via-webdav/ocm-via-webdav';
import OCMRepoDir from './pages/share-with-ocm/remote-dir-view';

View File

@@ -7,7 +7,7 @@ import TextTranslation from '../../utils/text-translation';
import SeahubPopover from '../common/seahub-popover';
import ListTagPopover from '../popover/list-tag-popover';
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 { PRIVATE_FILE_TYPE } from '../../constants';
import { DIRENT_DETAIL_MODE } from '../dir-view-mode/constants';
@@ -36,13 +36,6 @@ class DirTool extends React.Component {
isRepoTagDialogOpen: 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 = () => {
@@ -111,13 +104,6 @@ class DirTool extends React.Component {
const isFileExtended = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_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) {
return (
<div className="dir-tool">
@@ -142,7 +128,7 @@ class DirTool extends React.Component {
<React.Fragment>
<div className="dir-tool d-flex">
<ViewModes currentViewMode={currentMode} switchViewMode={this.props.switchViewMode} />
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
<SortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption} />
{(!isCustomPermission) &&
<div className="cur-view-path-btn" onClick={this.showDirentDetail}>
<span className="sf3-font sf3-font-info" aria-label={propertiesText} title={propertiesText}></span>

View File

@@ -25,7 +25,6 @@ const propTypes = {
onItemRename: PropTypes.func,
hasNextPage: PropTypes.bool,
onMonitorRepo: PropTypes.func,
theadHidden: PropTypes.bool,
inAllLibs: PropTypes.bool,
onTransferRepo: PropTypes.func,
};
@@ -119,7 +118,7 @@ class SharedRepoListView extends React.Component {
};
renderRepoListView = () => {
const { currentViewMode = LIST_MODE } = this.props;
const { currentViewMode } = this.props;
return (
<Fragment>
{this.props.repoList.map((repo, index) => {
@@ -148,28 +147,26 @@ class SharedRepoListView extends React.Component {
};
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 content = currentViewMode == LIST_MODE ? (
<>
<table className={classNames({ 'table-thead-hidden': theadHidden }, { 'repos-container': !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>
{this.renderRepoListView()}
</tbody>
</table>
</>
<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>
{this.renderRepoListView()}
</tbody>
</table>
) : (
<div className="d-flex justify-content-between flex-wrap">
{this.renderRepoListView()}

View File

@@ -4,14 +4,21 @@ import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap
import { gettext } from '../utils/constants';
const propTypes = {
sortOptions: PropTypes.array,
sortBy: PropTypes.string,
sortOrder: PropTypes.string,
onSelectSortOption: PropTypes.func.isRequired
};
class ReposSortMenu extends React.Component {
class SortMenu extends React.Component {
constructor(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 = {
isDropdownMenuOpen: false
};
@@ -25,7 +32,13 @@ class ReposSortMenu extends React.Component {
render() {
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 (
<Dropdown
isOpen={isDropdownMenuOpen}
@@ -59,6 +72,6 @@ class ReposSortMenu extends React.Component {
}
ReposSortMenu.propTypes = propTypes;
SortMenu.propTypes = propTypes;
export default ReposSortMenu;
export default SortMenu;

View File

@@ -169,7 +169,7 @@
}
.repos-container {
margin-bottom: 10rem;
padding-bottom: 10rem;
}
.table-drop-active::before {

View File

@@ -1,6 +1,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import cookie from 'react-cookies';
import classnames from 'classnames';
import { gettext, username, canAddRepo } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
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 SortOptionsDialog from '../../components/dialog/sort-options';
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';
@@ -41,6 +45,7 @@ class GroupView extends React.Component {
currentRepo: null,
isStaff: 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'
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
isSortOptionsDialogOpen: false,
@@ -386,8 +391,27 @@ class GroupView extends React.Component {
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() {
const { errMessage, emptyTip, currentGroup, isDepartmentGroup, isMembersDialogOpen } = this.state;
const {
isLoading, repoList, errMessage, emptyTip,
currentGroup, isDepartmentGroup, isMembersDialogOpen,
currentViewMode, sortBy, sortOrder
} = this.state;
let useRate = 0;
if (isDepartmentGroup && currentGroup.group_quota) {
@@ -409,11 +433,11 @@ class GroupView extends React.Component {
<span>{currentGroup.name}</span>
<SingleDropdownToolbar opList={opList} />
</div>
<div className="path-tool">
<div className="path-tool d-flex align-items-center">
{isDepartmentGroup && (
<>
{currentGroup.group_quota > 0 &&
<div className="department-usage-container">
<div className="department-usage-container mr-3">
<div className="department-usage">
<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>
@@ -422,38 +446,54 @@ 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) &&
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
{this.state.isSortOptionsDialogOpen &&
<SortOptionsDialog
toggleDialog={this.toggleSortOptionsDialog}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortBy={sortBy}
sortOrder={sortOrder}
sortItems={this.sortItems}
toggleDialog={this.toggleSortOptionsDialog}
/>
}
</div>
</Fragment>
)}
</div>
<div className="cur-view-content d-block" onScroll={this.handleScroll}>
{this.state.isLoading && <Loading />}
{(!this.state.isLoading && errMessage) && <div className="error text-center mt-2">{errMessage}</div>}
{(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip}
{(!this.state.isLoading && this.state.repoList.length > 0) &&
<SharedRepoListView
repoList={this.state.repoList}
hasNextPage={this.state.hasNextPage}
currentGroup={this.state.currentGroup}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete}
onItemRename={this.onItemRename}
onMonitorRepo={this.onMonitorRepo}
onTransferRepo={this.onItemTransfer}
/>
<div
className={classnames('cur-view-content', 'd-block', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}
onScroll={this.handleScroll}
>
{isLoading
? <Loading />
: errMessage
? <p className="error text-center mt-2">{errMessage}</p>
: repoList.length == 0
? emptyTip
: (
<SharedRepoListView
repoList={this.state.repoList}
hasNextPage={this.state.hasNextPage}
currentGroup={this.state.currentGroup}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete}
onItemRename={this.onItemRename}
onMonitorRepo={this.onMonitorRepo}
onTransferRepo={this.onItemTransfer}
currentViewMode={currentViewMode}
/>
)
}
</div>
</div>

View File

@@ -1,20 +1,20 @@
import React, { Component } from 'react';
import cookie from 'react-cookies';
import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api';
import { gettext, canAddRepo, canViewOrg } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
import Repo from '../../models/repo';
import Group from '../../models/group';
import toaster from '../../components/toast';
import Loading from '../../components/loading';
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 SortOptionsDialog from '../../components/dialog/sort-options';
import GuideForNewDialog from '../../components/dialog/guide-for-new-dialog';
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
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 GroupItem from '../../pages/groups/group-item';
import { LIST_MODE } from '../../components/dir-view-mode/constants';
@@ -24,13 +24,6 @@ import '../../css/files.css';
class Libraries extends Component {
constructor(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 = {
// for 'my libs'
errorMsg: '',
@@ -250,12 +243,6 @@ class Libraries extends Component {
const { isLoading, currentViewMode, sortBy, sortOrder, groupList } = this.state;
const isDesktop = Utils.isDesktop();
const sortOptions = this.sortOptions.map(item => {
return {
...item,
isSelected: item.value == `${sortBy}-${sortOrder}`
};
});
return (
<>
<div className="main-panel-center flex-row">
@@ -267,73 +254,75 @@ class Libraries extends Component {
<div className="mr-2">
<ViewModes currentViewMode={currentViewMode} switchViewMode={this.switchViewMode} />
</div>
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
<ReposSortMenu sortBy={sortBy} sortOrder={sortOrder} onSelectSortOption={this.onSelectSortOption} />
</div>
}
</div>
{isLoading ?
<Loading /> :
<div className="cur-view-content" id="files-content-container">
<div className="cur-view-content repos-container" id="files-content-container">
{isLoading ? <Loading /> : (
<>
{(Utils.isDesktop() && currentViewMode == LIST_MODE) && (
<table aria-hidden={true} className="my-3">
<thead>
<tr>
<th width="4%"></th>
<th width="3%"><span className="sr-only">{gettext('Library Type')}</span></th>
<th width="35%">{gettext('Name')}</th>
<th width="10%"><span className="sr-only">{gettext('Actions')}</span></th>
<th width="14%">{gettext('Size')}</th>
<th width="17%">{gettext('Last Update')}</th>
<th width="17%">{gettext('Owner')}</th>
</tr>
</thead>
</table>
)}
{(Utils.isDesktop() && currentViewMode == LIST_MODE) && (
<table aria-hidden={true} className="my-3">
<thead>
<tr>
<th width="4%"></th>
<th width="3%"><span className="sr-only">{gettext('Library Type')}</span></th>
<th width="35%">{gettext('Name')}</th>
<th width="10%"><span className="sr-only">{gettext('Actions')}</span></th>
<th width="14%">{gettext('Size')}</th>
<th width="17%">{gettext('Last Update')}</th>
<th width="17%">{gettext('Owner')}</th>
</tr>
</thead>
</table>
)}
{canAddRepo && (
<div className="pb-3">
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
<h4 className="sf-heading m-0 d-flex align-items-center">
<span className="sf3-font-mine sf3-font nav-icon" aria-hidden="true"></span>
{gettext('My Libraries')}
<SingleDropdownToolbar
opList={[{ 'text': gettext('New Library'), 'onClick': this.toggleCreateRepoDialog }]}
/>
</h4>
{(!Utils.isDesktop() && this.state.repoList.length > 0) &&
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
{canAddRepo && (
<div className="pb-3">
<div className={`d-flex justify-content-between mt-3 py-1 ${currentViewMode == LIST_MODE ? 'sf-border-bottom' : ''}`}>
<h4 className="sf-heading m-0 d-flex align-items-center">
<span className="sf3-font-mine sf3-font nav-icon" aria-hidden="true"></span>
{gettext('My Libraries')}
<SingleDropdownToolbar
opList={[{ 'text': gettext('New Library'), 'onClick': this.toggleCreateRepoDialog }]}
/>
</h4>
{(!Utils.isDesktop() && this.state.repoList.length > 0) &&
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
}
</div>
{this.state.errorMsg
? <p className="error text-center mt-8">{this.state.errorMsg}</p>
: this.state.repoList.length == 0
? <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>
: (
<MylibRepoListView
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
repoList={this.state.repoList}
onRenameRepo={this.onRenameRepo}
onDeleteRepo={this.onDeleteRepo}
onTransferRepo={this.onTransferRepo}
onMonitorRepo={this.onMonitorRepo}
onRepoClick={this.onRepoClick}
sortRepoList={this.sortRepoList}
inAllLibs={true}
currentViewMode={currentViewMode}
/>
)
}
</div>
{this.state.errorMsg ? <p className="error text-center mt-8">{this.state.errorMsg}</p> : (
this.state.repoList.length === 0 ? (
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No libraries')}</p>
) : (
<MylibRepoListView
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
repoList={this.state.repoList}
onRenameRepo={this.onRenameRepo}
onDeleteRepo={this.onDeleteRepo}
onTransferRepo={this.onTransferRepo}
onMonitorRepo={this.onMonitorRepo}
onRepoClick={this.onRepoClick}
sortRepoList={this.sortRepoList}
inAllLibs={true}
currentViewMode={currentViewMode}
/>
))
}
)}
<div className="pb-3">
<SharedLibraries
repoList={this.state.sharedRepoList}
inAllLibs={true}
currentViewMode={currentViewMode}
/>
</div>
)}
<div className="pb-3">
<SharedLibraries
repoList={this.state.sharedRepoList}
inAllLibs={true}
currentViewMode={currentViewMode}
/>
</div>
{canViewOrg &&
{canViewOrg &&
<div className="pb-3">
<SharedWithAll
repoList={this.state.publicRepoList}
@@ -341,8 +330,8 @@ class Libraries extends Component {
currentViewMode={currentViewMode}
/>
</div>
}
<div className="repos-container">
}
{groupList.length > 0 && groupList.map((group) => {
return (
<GroupItem
@@ -355,9 +344,9 @@ class Libraries extends Component {
/>
);
})}
</div>
</div>
}
</>
)}
</div>
</div>
{!isLoading && !this.state.errorMsg && this.state.isGuideForNewDialogOpen &&
<GuideForNewDialog

View File

@@ -1,18 +1,22 @@
import React, { Component, Fragment } from 'react';
import cookie from 'react-cookies';
import classnames from 'classnames';
import Repo from '../../models/repo';
import { seafileAPI } from '../../utils/seafile-api';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
import Repo from '../../models/repo';
import Loading from '../../components/loading';
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 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 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 {
constructor(props) {
@@ -24,6 +28,7 @@ class MyLibraries extends Component {
isDeletedReposDialogOpen: false,
isCreateRepoDialogOpen: 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'
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() {
const { isLoading, errorMsg, currentViewMode, sortBy, sortOrder, repoList } = this.state;
const isDesktop = Utils.isDesktop();
return (
<Fragment>
<div className="main-panel-center flex-row">
@@ -150,33 +172,49 @@ class MyLibraries extends Component {
]}
/>
</h3>
<div>
{(!Utils.isDesktop() && this.state.repoList.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
</div>
{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>
) : (
<>
{repoList.length > 0 &&
<span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>
}
</>
)}
</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>}
{!this.state.isLoading && !this.state.errorMsg && this.state.repoList.length === 0 && this.emptyTip}
{!this.state.isLoading && !this.state.errorMsg && this.state.repoList.length > 0 &&
<MylibRepoListView
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
repoList={this.state.repoList}
onRenameRepo={this.onRenameRepo}
onDeleteRepo={this.onDeleteRepo}
onTransferRepo={this.onTransferRepo}
onMonitorRepo={this.onMonitorRepo}
sortRepoList={this.sortRepoList}
/>
<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
sortBy={sortBy}
sortOrder={sortOrder}
repoList={this.state.repoList}
onRenameRepo={this.onRenameRepo}
onDeleteRepo={this.onDeleteRepo}
onTransferRepo={this.onTransferRepo}
onMonitorRepo={this.onMonitorRepo}
sortRepoList={this.sortRepoList}
currentViewMode={currentViewMode}
/>
)
}
</div>
</div>
{this.state.isSortOptionsDialogOpen &&
<SortOptionsDialog
toggleDialog={this.toggleSortOptionsDialog}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortBy={sortBy}
sortOrder={sortOrder}
sortItems={this.sortRepoList}
/>
}

View File

@@ -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>;
return currentViewMode == LIST_MODE ? (
<table className={classNames({ 'table-thead-hidden': inAllLibs }, { 'repos-container': !inAllLibs })}>
<table className={classNames({ 'table-thead-hidden': inAllLibs })}>
<thead>
<tr>
<th width="4%"></th>

View 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;

View 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;

View File

@@ -2,184 +2,19 @@ import React, { Component, Fragment } from 'react';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import PropTypes from 'prop-types';
import dayjs from 'dayjs';
import classNames from 'classnames';
import relativeTime from 'dayjs/plugin/relativeTime';
import cookie from 'react-cookies';
import { Link, navigate } from '@gatsbyjs/reach-router';
import { gettext, siteRoot, isPro } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
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 ShareDialog from '../../components/dialog/share-dialog';
import SortOptionsDialog from '../../components/dialog/sort-options';
import RepoMonitoredIcon from '../../components/repo-monitored-icon';
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);
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 {
constructor(props) {
@@ -530,141 +365,4 @@ Item.propTypes = {
onContextMenu: PropTypes.func.isRequired,
};
class SharedLibraries extends Component {
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;
export default Item;

View File

@@ -1,6 +1,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import cookie from 'react-cookies';
import classnames from 'classnames';
import { seafileAPI } from '../../utils/seafile-api';
import { gettext, canAddPublicRepo } from '../../utils/constants';
import { Utils } from '../../utils/utils';
@@ -15,6 +16,8 @@ import ModalPortal from '../../components/modal-portal';
import CreateRepoDialog from '../../components/dialog/create-repo-dialog';
import ShareRepoDialog from '../../components/dialog/share-repo-dialog';
import { LIST_MODE } from '../../components/dir-view-mode/constants';
import ViewModes from '../../components/view-modes';
import ReposSortMenu from '../../components/sort-menu';
const propTypes = {
currentViewMode: PropTypes.string,
@@ -32,6 +35,7 @@ class SharedWithAll extends React.Component {
repoList: [],
isCreateRepoDialogOpen: 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'
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
isSortOptionsDialogOpen: false,
@@ -120,11 +124,12 @@ class SharedWithAll extends React.Component {
});
};
renderContent = () => {
const { inAllLibs = false, currentViewMode = LIST_MODE } = this.props; // inAllLibs: in 'All Libs'('Files') page
const { errMessage } = this.state;
const emptyTip = inAllLibs ?
<p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No public libraries')}</p> : (
renderContent = (currentViewMode) => {
const { inAllLibs = false } = this.props; // inAllLibs: in 'All Libs'('Files') page
const { isLoading, errMessage, repoList } = this.state;
const emptyTip = inAllLibs
? <p className={`libraries-empty-tip-in-${currentViewMode}-mode`}>{gettext('No public libraries')}</p>
: (
<EmptyTip
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.')}
@@ -133,24 +138,26 @@ class SharedWithAll extends React.Component {
);
return (
<>
{this.state.isLoading && <Loading />}
{(!this.state.isLoading && errMessage) && errMessage}
{(!this.state.isLoading && this.state.repoList.length === 0) && emptyTip}
{(!this.state.isLoading && this.state.repoList.length > 0) &&
<SharedRepoListView
key='public-shared-view'
libraryType={this.state.libraryType}
repoList={this.state.repoList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete}
theadHidden={inAllLibs}
currentViewMode={currentViewMode}
inAllLibs={inAllLibs}
/>
}
{isLoading
? <Loading />
: errMessage
? <p className="error text-center">{errMessage}</p>
: repoList.length == 0
? emptyTip
: (
<SharedRepoListView
key='public-shared-view'
libraryType={this.state.libraryType}
repoList={this.state.repoList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onItemUnshare={this.onItemUnshare}
onItemDelete={this.onItemDelete}
currentViewMode={currentViewMode}
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() {
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) {
return (
@@ -216,7 +240,7 @@ class SharedWithAll extends React.Component {
</h4>
{this.renderSortIconInMobile()}
</div>
{this.renderContent()}
{this.renderContent(currentViewMode)}
</>
);
}
@@ -237,10 +261,18 @@ class SharedWithAll extends React.Component {
/>
}
</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="cur-view-content">
{this.renderContent()}
<div className={classnames('cur-view-content', 'repos-container', { 'pt-3': currentViewMode != LIST_MODE })}>
{this.renderContent(currentViewMode)}
</div>
</div>
</div>