mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 23:02:26 +00:00
Admin new sort (#8002)
* [system admin] Libraries - 'All' & 'Wikis': removed the sort in the table head, added a sort menu * [org admin] libraries - 'all': removed the sort in the table head, and added a sort menu * [org admin] users - 'all': removed the sort in the table head, and added a sort menu * [system admin] Users - 'Database' & 'LDAP(imported)': removed the sort in the table head, added a sort menu * [system admin] Links - Share Links: removed the sort in the table head, and added a sort menu * [system admin] Departments - department - members: removed the sort in the table head, added a sort menu, and bugfix * [org admin] Departments - department - members: removed the sort in the table head, added a sort menu, and bugfix * [sort menu] fixed the default menu options
This commit is contained in:
@@ -17,12 +17,12 @@ class SortMenu extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.sortOptions = this.props.sortOptions || [
|
||||
{ value: 'name-asc', text: gettext('By name ascending') },
|
||||
{ value: 'name-desc', text: gettext('By name descending') },
|
||||
{ value: 'size-asc', text: gettext('By size ascending') },
|
||||
{ value: 'size-desc', text: gettext('By size descending') },
|
||||
{ value: 'time-asc', text: gettext('By time ascending') },
|
||||
{ value: 'time-desc', text: gettext('By time descending') }
|
||||
{ value: 'name-asc', text: gettext('Ascending by name') },
|
||||
{ value: 'name-desc', text: gettext('Descending by name') },
|
||||
{ value: 'size-asc', text: gettext('Ascending by size') },
|
||||
{ value: 'size-desc', text: gettext('Descending by size') },
|
||||
{ value: 'time-asc', text: gettext('Ascending by time') },
|
||||
{ value: 'time-desc', text: gettext('Descending by time') }
|
||||
];
|
||||
this.state = {
|
||||
isDropdownMenuOpen: false
|
||||
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { Dropdown, DropdownToggle } from 'reactstrap';
|
||||
import Loading from '../../../components/loading';
|
||||
import EmptyTip from '../../../components/empty-tip';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
import { gettext } from '../../../utils/constants';
|
||||
import MemberItem from './member-item';
|
||||
import RepoItem from './repo-item';
|
||||
@@ -31,6 +32,13 @@ class Department extends React.Component {
|
||||
repos: [],
|
||||
dropdownOpen: false,
|
||||
};
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'name-asc', text: gettext('Ascending by name') },
|
||||
{ value: 'name-desc', text: gettext('Descending by name') },
|
||||
{ value: 'role-asc', text: gettext('Ascending by role') },
|
||||
{ value: 'role-desc', text: gettext('Descending by role') }
|
||||
];
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -67,19 +75,8 @@ class Department extends React.Component {
|
||||
return currentDepartment;
|
||||
};
|
||||
|
||||
sortByName = (e) => {
|
||||
e.preventDefault();
|
||||
const sortBy = 'name';
|
||||
let { sortOrder } = this.props;
|
||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
sortByRole = (e) => {
|
||||
e.preventDefault();
|
||||
const sortBy = 'role';
|
||||
let { sortOrder } = this.props;
|
||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy, sortOrder] = item.value.split('-');
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
@@ -106,9 +103,7 @@ class Department extends React.Component {
|
||||
render() {
|
||||
const { activeNav, repos } = this.state;
|
||||
const { membersList, isMembersListLoading, sortBy, sortOrder } = this.props;
|
||||
const sortByName = sortBy === 'name';
|
||||
const sortByRole = sortBy === 'role';
|
||||
const sortIcon = <span className={`sort-dirent sf3-font sf3-font-down ${sortOrder === 'asc' ? 'rotate-180' : ''}`}></span>;
|
||||
const showSortIcon = activeNav == 'members';
|
||||
const currentDepartment = this.getCurrentDepartment();
|
||||
|
||||
return (
|
||||
@@ -150,6 +145,14 @@ class Department extends React.Component {
|
||||
<span className={`nav-link ${activeNav === 'repos' ? 'active' : ''}`} onClick={() => this.changeActiveNav('repos')}>{gettext('Libraries')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
{activeNav === 'members' &&
|
||||
@@ -161,8 +164,8 @@ class Department extends React.Component {
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60px"></th>
|
||||
<th width="25%" onClick={this.sortByName}>{gettext('Name')}{' '}{sortByName && sortIcon}</th>
|
||||
<th width="23%" onClick={this.sortByRole}>{gettext('Role')}{' '}{sortByRole && sortIcon}</th>
|
||||
<th width="25%">{gettext('Name')}</th>
|
||||
<th width="23%">{gettext('Role')}</th>
|
||||
<th width="35%">{gettext('Contact email')}</th>
|
||||
<th width="calc(17% - 60px)">{/* Operations */}</th>
|
||||
</tr>
|
||||
|
@@ -35,8 +35,8 @@ class Departments extends React.Component {
|
||||
membersList: [],
|
||||
isTopDepartmentLoading: false,
|
||||
isMembersListLoading: false,
|
||||
sortBy: 'name', // 'name' or 'role'
|
||||
sortOrder: 'asc', // 'asc' or 'desc',
|
||||
sortBy: '', // 'name' or 'role'
|
||||
sortOrder: '', // 'asc' or 'desc',
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -52,8 +52,7 @@ class Content extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
// offer 'sort' only for 'all repos'
|
||||
const { loading, errorMsg, items, pageInfo, curPerPage, sortBy } = this.props;
|
||||
const { loading, errorMsg, items, pageInfo, curPerPage } = this.props;
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
} else if (errorMsg) {
|
||||
@@ -62,8 +61,6 @@ class Content extends Component {
|
||||
const emptyTip = (
|
||||
<EmptyTip text={gettext('No libraries')}/>
|
||||
);
|
||||
const initialSortIcon = <span className="sf3-font sf3-font-sort3"></span>;
|
||||
const sortIcon = <span className="sf3-font sf3-font-down"></span>;
|
||||
const table = (
|
||||
<Fragment>
|
||||
<table>
|
||||
@@ -71,15 +68,7 @@ class Content extends Component {
|
||||
<tr>
|
||||
<th width="5%">{/* icon*/}</th>
|
||||
<th width="25%">{gettext('Name')}</th>
|
||||
<th width="15%">
|
||||
{sortBy != undefined ?
|
||||
<Fragment>
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByFileCount}>{gettext('Files')} {sortBy == 'file_count' ? sortIcon : initialSortIcon}</a>{' / '}
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBy == 'size' ? sortIcon : initialSortIcon}</a>
|
||||
</Fragment> :
|
||||
gettext('Files') / gettext('Size')
|
||||
}
|
||||
</th>
|
||||
<th width="15%">{gettext('Files')} / {gettext('Size')}</th>
|
||||
<th width="32%">ID</th>
|
||||
<th width="18%">{gettext('Owner')}</th>
|
||||
<th width="5%">{/* Operations*/}</th>
|
||||
@@ -128,8 +117,6 @@ Content.propTypes = {
|
||||
resetPerPage: PropTypes.func,
|
||||
pageInfo: PropTypes.object,
|
||||
curPerPage: PropTypes.number,
|
||||
sortItems: PropTypes.func,
|
||||
sortBy: PropTypes.string,
|
||||
transferRepoItem: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -389,14 +376,16 @@ class OrgAllRepos extends Component {
|
||||
<MainPanelTopbar />
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<ReposNav currentItem="all" />
|
||||
<ReposNav
|
||||
currentItem="all"
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
/>
|
||||
<div className="cur-view-content">
|
||||
<Content
|
||||
loading={this.state.loading}
|
||||
errorMsg={this.state.errorMsg}
|
||||
items={this.state.repos}
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
pageInfo={this.state.pageInfo}
|
||||
curPerPage={this.state.perPage}
|
||||
getListByPage={this.getReposByPage}
|
||||
|
@@ -2,9 +2,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { siteRoot, gettext } from '../../../utils/constants';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
|
||||
const propTypes = {
|
||||
currentItem: PropTypes.string.isRequired
|
||||
currentItem: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string,
|
||||
sortItems: PropTypes.func
|
||||
};
|
||||
|
||||
class Nav extends React.Component {
|
||||
@@ -15,10 +18,21 @@ class Nav extends React.Component {
|
||||
{ name: 'all', urlPart: 'repoadmin', text: gettext('All') },
|
||||
{ name: 'trash', urlPart: 'repoadmin-trash', text: gettext('Trash') }
|
||||
];
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'file_count-desc', text: gettext('Descending by files') },
|
||||
{ value: 'size-desc', text: gettext('Descending by size') }
|
||||
];
|
||||
}
|
||||
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy,] = item.value.split('-');
|
||||
this.props.sortItems(sortBy);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentItem } = this.props;
|
||||
const { currentItem, sortBy, sortOrder = 'desc' } = this.props;
|
||||
const showSortIcon = currentItem == 'all';
|
||||
return (
|
||||
<div className="cur-view-path tab-nav-container">
|
||||
<ul className="nav">
|
||||
@@ -30,6 +44,14 @@ class Nav extends React.Component {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -9,10 +9,7 @@ const propTypes = {
|
||||
changeStatus: PropTypes.func.isRequired,
|
||||
orgUsers: PropTypes.array.isRequired,
|
||||
page: PropTypes.number.isRequired,
|
||||
pageNext: PropTypes.bool.isRequired,
|
||||
sortByQuotaUsage: PropTypes.func.isRequired,
|
||||
sortOrder: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string.isRequired,
|
||||
pageNext: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
class OrgUsersList extends React.Component {
|
||||
@@ -49,21 +46,8 @@ class OrgUsersList extends React.Component {
|
||||
this.props.initOrgUsersData(page);
|
||||
};
|
||||
|
||||
sortByQuotaUsage = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.sortByQuotaUsage();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { sortBy, sortOrder } = this.props;
|
||||
let sortIcon;
|
||||
if (sortBy == '') {
|
||||
// initial sort icon
|
||||
sortIcon = <span className="sf3-font sf3-font-sort3"></span>;
|
||||
} else {
|
||||
sortIcon = <span className={`sf3-font ${sortOrder == 'asc' ? 'sf3-font-down rotate-180 d-inline-block' : 'sf3-font-down'}`}></span>;
|
||||
}
|
||||
let { orgUsers, page, pageNext } = this.props;
|
||||
const { orgUsers, page, pageNext } = this.props;
|
||||
return (
|
||||
<div className="cur-view-content">
|
||||
<table>
|
||||
@@ -71,9 +55,7 @@ class OrgUsersList extends React.Component {
|
||||
<tr>
|
||||
<th width="30%">{gettext('Name')}</th>
|
||||
<th width="15%">{gettext('Status')}</th>
|
||||
<th width="20%">
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByQuotaUsage}>{gettext('Space Used')} {sortIcon}</a> / {gettext('Quota')}
|
||||
</th>
|
||||
<th width="20%">{gettext('Space Used')} / {gettext('Quota')}</th>
|
||||
<th width="25%">{gettext('Created At')} / {gettext('Last Login')}</th>
|
||||
<th width="10%">{/* Operations*/}</th>
|
||||
</tr>
|
||||
|
@@ -2,9 +2,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { siteRoot, gettext } from '../../utils/constants';
|
||||
import SortMenu from '../../components/sort-menu';
|
||||
|
||||
const propTypes = {
|
||||
currentItem: PropTypes.string.isRequired
|
||||
currentItem: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string,
|
||||
sortItems: PropTypes.func
|
||||
};
|
||||
|
||||
class Nav extends React.Component {
|
||||
@@ -15,10 +18,21 @@ class Nav extends React.Component {
|
||||
{ name: 'all', urlPart: 'useradmin', text: gettext('All') },
|
||||
{ name: 'admins', urlPart: 'useradmin/admins', text: gettext('Admin') }
|
||||
];
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'quota_usage-asc', text: gettext('Ascending by space used') },
|
||||
{ value: 'quota_usage-desc', text: gettext('Descending by space used') }
|
||||
];
|
||||
}
|
||||
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy, sortOrder] = item.value.split('-');
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentItem } = this.props;
|
||||
const { currentItem, sortBy, sortOrder } = this.props;
|
||||
const showSortIcon = currentItem == 'all';
|
||||
return (
|
||||
<div className="cur-view-path tab-nav-container">
|
||||
<ul className="nav">
|
||||
@@ -30,6 +44,14 @@ class Nav extends React.Component {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -102,10 +102,10 @@ class OrgUsers extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
sortByQuotaUsage = () => {
|
||||
sortByQuotaUsage = (sortBy, sortOrder) => {
|
||||
this.setState({
|
||||
sortBy: 'quota_usage',
|
||||
sortOrder: this.state.sortOrder == 'asc' ? 'desc' : 'asc',
|
||||
sortBy: sortBy,
|
||||
sortOrder: sortOrder,
|
||||
page: 1
|
||||
}, () => {
|
||||
let url = new URL(location.href);
|
||||
@@ -309,7 +309,12 @@ class OrgUsers extends Component {
|
||||
<MainPanelTopbar children={topbarChildren} search={this.getSearch()}/>
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<Nav currentItem="all" />
|
||||
<Nav
|
||||
currentItem="all"
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortItems={this.sortByQuotaUsage}
|
||||
/>
|
||||
<OrgUsersList
|
||||
initOrgUsersData={this.initOrgUsersData}
|
||||
toggleDelete={this.toggleOrgUsersDelete}
|
||||
@@ -317,9 +322,6 @@ class OrgUsers extends Component {
|
||||
orgUsers={this.state.orgUsers}
|
||||
page={this.state.page}
|
||||
pageNext={this.state.pageNext}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortByQuotaUsage={this.sortByQuotaUsage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Dropdown, DropdownToggle } from 'reactstrap';
|
||||
import { gettext } from '../../../utils/constants';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
import Paginator from '../../../components/paginator';
|
||||
import Loading from '../../../components/loading';
|
||||
import EmptyTip from '../../../components/empty-tip';
|
||||
@@ -41,6 +42,13 @@ class Department extends React.Component {
|
||||
showDeleteRepoDialog: false,
|
||||
dropdownOpen: false,
|
||||
};
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'name-asc', text: gettext('Ascending by name') },
|
||||
{ value: 'name-desc', text: gettext('Descending by name') },
|
||||
{ value: 'role-asc', text: gettext('Ascending by role') },
|
||||
{ value: 'role-desc', text: gettext('Descending by role') }
|
||||
];
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -95,19 +103,8 @@ class Department extends React.Component {
|
||||
return currentDepartment;
|
||||
};
|
||||
|
||||
sortByName = (e) => {
|
||||
e.preventDefault();
|
||||
const sortBy = 'name';
|
||||
let { sortOrder } = this.props;
|
||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
sortByRole = (e) => {
|
||||
e.preventDefault();
|
||||
const sortBy = 'role';
|
||||
let { sortOrder } = this.props;
|
||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy, sortOrder] = item.value.split('-');
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
@@ -129,9 +126,7 @@ class Department extends React.Component {
|
||||
render() {
|
||||
const { activeNav, repos } = this.state;
|
||||
const { membersList, isMembersListLoading, sortBy, sortOrder } = this.props;
|
||||
const sortByName = sortBy === 'name';
|
||||
const sortByRole = sortBy === 'role';
|
||||
const sortIcon = <span className={`sort-dirent sf3-font sf3-font-down ${sortOrder === 'asc' ? 'rotate-180' : ''}`}></span>;
|
||||
const showSortIcon = activeNav == 'members';
|
||||
const currentDepartment = this.getCurrentDepartment();
|
||||
|
||||
return (
|
||||
@@ -173,6 +168,15 @@ class Department extends React.Component {
|
||||
<span className={`nav-link ${activeNav === 'repos' ? 'active' : ''}`} onClick={() => this.changeActiveNav('repos')}>{gettext('Libraries')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
{activeNav === 'members' && (
|
||||
@@ -187,8 +191,8 @@ class Department extends React.Component {
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="10%"></th>
|
||||
<th width="25%" onClick={this.sortByName}>{gettext('Name')}{' '}{sortByName && sortIcon}</th>
|
||||
<th width="25%" onClick={this.sortByRole}>{gettext('Role')}{' '}{sortByRole && sortIcon}</th>
|
||||
<th width="25%">{gettext('Name')}</th>
|
||||
<th width="25%">{gettext('Role')}</th>
|
||||
<th width="30%">{gettext('Contact email')}</th>
|
||||
<th width="10%">{/* Operations */}</th>
|
||||
</tr>
|
||||
|
@@ -35,8 +35,8 @@ class Departments extends React.Component {
|
||||
membersList: [],
|
||||
isTopDepartmentLoading: false,
|
||||
isMembersListLoading: false,
|
||||
sortBy: 'name', // 'name' or 'role'
|
||||
sortOrder: 'asc', // 'asc' or 'desc',
|
||||
sortBy: '', // 'name' or 'role'
|
||||
sortOrder: '', // 'asc' or 'desc',
|
||||
currentPageInfo: null,
|
||||
currentPage: 1,
|
||||
perPage: 100
|
||||
|
@@ -2,9 +2,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { siteRoot, gettext } from '../../../utils/constants';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
|
||||
const propTypes = {
|
||||
currentItem: PropTypes.string.isRequired
|
||||
currentItem: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string,
|
||||
sortOrder: PropTypes.string,
|
||||
sortItems: PropTypes.func
|
||||
};
|
||||
|
||||
class Nav extends React.Component {
|
||||
@@ -15,10 +19,23 @@ class Nav extends React.Component {
|
||||
{ name: 'shareLinks', urlPart: 'share-links', text: gettext('Share Links') },
|
||||
{ name: 'uploadLinks', urlPart: 'upload-links', text: gettext('Upload Links') },
|
||||
];
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'ctime-asc', text: gettext('Ascending by creation time') },
|
||||
{ value: 'ctime-desc', text: gettext('Descending by creation time') },
|
||||
{ value: 'view_cnt-asc', text: gettext('Ascending by visit count') },
|
||||
{ value: 'view_cnt-desc', text: gettext('Descending by visit count') }
|
||||
];
|
||||
}
|
||||
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy, sortOrder] = item.value.split('-');
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentItem } = this.props;
|
||||
const { currentItem, sortBy, sortOrder } = this.props;
|
||||
const showSortIcon = currentItem == 'shareLinks';
|
||||
return (
|
||||
<div className="cur-view-path tab-nav-container">
|
||||
<ul className="nav">
|
||||
@@ -30,6 +47,14 @@ class Nav extends React.Component {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -31,21 +31,10 @@ class Content extends Component {
|
||||
this.props.getShareLinksByPage(this.props.currentPage + 1);
|
||||
};
|
||||
|
||||
sortByTime = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.sortItems('ctime');
|
||||
};
|
||||
|
||||
sortByCount = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.sortItems('view_cnt');
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
loading, errorMsg, items,
|
||||
perPage, currentPage, hasNextPage,
|
||||
sortBy, sortOrder
|
||||
perPage, currentPage, hasNextPage
|
||||
} = this.props;
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
@@ -57,8 +46,6 @@ class Content extends Component {
|
||||
</EmptyTip>
|
||||
);
|
||||
|
||||
const initialSortIcon = <span className="sf3-font sf3-font-sort3"></span>;
|
||||
const sortIcon = <span className={`sf3-font ${sortOrder == 'asc' ? 'sf3-font-down rotate-180 d-inline-block' : 'sf3-font-down'}`}></span>;
|
||||
const table = (
|
||||
<Fragment>
|
||||
<table className="table-hover">
|
||||
@@ -67,12 +54,8 @@ class Content extends Component {
|
||||
<th width="18%">{gettext('Name')}</th>
|
||||
<th width="18%">{gettext('Token')}</th>
|
||||
<th width="18%">{gettext('Owner')}</th>
|
||||
<th width="15%">
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Created At')} {sortBy == 'ctime' ? sortIcon : initialSortIcon}</a>
|
||||
</th>
|
||||
<th width="10%">
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByCount}>{gettext('Visit count')} {sortBy == 'view_cnt' ? sortIcon : initialSortIcon}</a>
|
||||
</th>
|
||||
<th width="15%">{gettext('Created At')}</th>
|
||||
<th width="10%">{gettext('Visit count')}</th>
|
||||
<th width="11%">{gettext('Expiration')}</th>
|
||||
<th width="10%">{/* Operations*/}</th>
|
||||
</tr>
|
||||
@@ -115,9 +98,6 @@ Content.propTypes = {
|
||||
pageInfo: PropTypes.object,
|
||||
hasNextPage: PropTypes.bool,
|
||||
getShareLinksByPage: PropTypes.func.isRequired,
|
||||
sortItems: PropTypes.func.isRequired,
|
||||
sortBy: PropTypes.string.isRequired,
|
||||
sortOrder: PropTypes.string.isRequired,
|
||||
deleteShareLink: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -242,11 +222,11 @@ class ShareLinks extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
sortItems = (sortBy) => {
|
||||
sortItems = (sortBy, sortOrder) => {
|
||||
this.setState({
|
||||
currentPage: 1,
|
||||
sortBy: sortBy,
|
||||
sortOrder: this.state.sortOrder == 'asc' ? 'desc' : 'asc'
|
||||
sortOrder: sortOrder
|
||||
}, () => {
|
||||
let url = new URL(location.href);
|
||||
let searchParams = new URLSearchParams(url.search);
|
||||
@@ -285,7 +265,12 @@ class ShareLinks extends Component {
|
||||
<MainPanelTopbar {...this.props} />
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<LinksNav currentItem="shareLinks" />
|
||||
<LinksNav
|
||||
currentItem="shareLinks"
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortItems={this.sortItems}
|
||||
/>
|
||||
<div className="cur-view-content">
|
||||
<Content
|
||||
loading={this.state.loading}
|
||||
@@ -296,9 +281,6 @@ class ShareLinks extends Component {
|
||||
hasNextPage={hasNextPage}
|
||||
getShareLinksByPage={this.getShareLinksByPage}
|
||||
resetPerPage={this.resetPerPage}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortItems={this.sortItems}
|
||||
deleteShareLink={this.deleteShareLink}
|
||||
/>
|
||||
</div>
|
||||
|
@@ -155,14 +155,16 @@ class AllRepos extends Component {
|
||||
</MainPanelTopbar>
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<ReposNav currentItem="all" />
|
||||
<ReposNav
|
||||
currentItem="all"
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
/>
|
||||
<div className="cur-view-content">
|
||||
<Content
|
||||
loading={this.state.loading}
|
||||
errorMsg={this.state.errorMsg}
|
||||
items={this.state.repos}
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
pageInfo={this.state.pageInfo}
|
||||
curPerPage={this.state.perPage}
|
||||
getListByPage={this.getReposByPage}
|
||||
|
@@ -96,14 +96,16 @@ class AllWikis extends Component {
|
||||
<MainPanelTopbar {...this.props} />
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<ReposNav currentItem="wikis" />
|
||||
<ReposNav
|
||||
currentItem="wikis"
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
/>
|
||||
<div className="cur-view-content">
|
||||
<Content
|
||||
loading={this.state.loading}
|
||||
errorMsg={this.state.errorMsg}
|
||||
items={this.state.wikis}
|
||||
sortBy={this.state.sortBy}
|
||||
sortItems={this.sortItems}
|
||||
pageInfo={this.state.pageInfo}
|
||||
curPerPage={this.state.perPage}
|
||||
getListByPage={this.getWikisByPage}
|
||||
|
@@ -2,9 +2,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { siteRoot, gettext } from '../../../utils/constants';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
|
||||
const propTypes = {
|
||||
currentItem: PropTypes.string.isRequired
|
||||
currentItem: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string,
|
||||
sortItems: PropTypes.func
|
||||
};
|
||||
|
||||
class Nav extends React.Component {
|
||||
@@ -17,10 +20,20 @@ class Nav extends React.Component {
|
||||
{ name: 'system', urlPart: 'system-library', text: gettext('System') },
|
||||
{ name: 'trash', urlPart: 'trash-libraries', text: gettext('Trash') }
|
||||
];
|
||||
this.sortOptions = [
|
||||
{ value: 'file_count-desc', text: gettext('Descending by files') },
|
||||
{ value: 'size-desc', text: gettext('Descending by size') }
|
||||
];
|
||||
}
|
||||
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy,] = item.value.split('-');
|
||||
this.props.sortItems(sortBy);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentItem } = this.props;
|
||||
const { currentItem, sortBy, sortOrder = 'desc' } = this.props;
|
||||
const showSortIcon = currentItem == 'all' || currentItem == 'wikis';
|
||||
return (
|
||||
<div className="cur-view-path tab-nav-container">
|
||||
<ul className="nav">
|
||||
@@ -32,6 +45,14 @@ class Nav extends React.Component {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -43,19 +43,8 @@ class Content extends Component {
|
||||
this.props.getListByPage(this.props.pageInfo.current_page + 1);
|
||||
};
|
||||
|
||||
sortByFileCount = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.sortItems('file_count');
|
||||
};
|
||||
|
||||
sortBySize = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.sortItems('size');
|
||||
};
|
||||
|
||||
render() {
|
||||
// offer 'sort' only for 'all repos'
|
||||
const { loading, errorMsg, items, pageInfo, curPerPage, sortBy } = this.props;
|
||||
const { loading, errorMsg, items, pageInfo, curPerPage } = this.props;
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
} else if (errorMsg) {
|
||||
@@ -65,8 +54,6 @@ class Content extends Component {
|
||||
<EmptyTip text={gettext('No libraries')}>
|
||||
</EmptyTip>
|
||||
);
|
||||
const initialSortIcon = <span className="sf3-font sf3-font-sort3"></span>;
|
||||
const sortIcon = <span className="sf3-font sf3-font-down"></span>;
|
||||
const table = (
|
||||
<Fragment>
|
||||
<table>
|
||||
@@ -74,20 +61,10 @@ class Content extends Component {
|
||||
<tr>
|
||||
<th width="5%">{/* icon*/}</th>
|
||||
<th width="25%">{gettext('Name')}</th>
|
||||
<th width="15%">
|
||||
{sortBy != undefined ?
|
||||
<Fragment>
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByFileCount}>{gettext('Files')} {sortBy == 'file_count' ? sortIcon : initialSortIcon}</a>{' / '}
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBy == 'size' ? sortIcon : initialSortIcon}</a>
|
||||
</Fragment> :
|
||||
<>{gettext('Files')}{' / '}{gettext('Size')}</>
|
||||
}
|
||||
</th>
|
||||
<Fragment>
|
||||
<th width="15%">{gettext('Files')} / {gettext('Size')}</th>
|
||||
<th width="32%">ID</th>
|
||||
<th width="18%">{gettext('Owner')}</th>
|
||||
<th width="5%">{/* Operations*/}</th>
|
||||
</Fragment>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -134,8 +111,6 @@ Content.propTypes = {
|
||||
resetPerPage: PropTypes.func,
|
||||
pageInfo: PropTypes.object,
|
||||
curPerPage: PropTypes.number,
|
||||
sortItems: PropTypes.func,
|
||||
sortBy: PropTypes.string,
|
||||
onTransferRepo: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
@@ -57,8 +57,7 @@ class Content extends Component {
|
||||
render() {
|
||||
const {
|
||||
isAdmin, loading, errorMsg, items, isAllUsersSelected,
|
||||
curPerPage, hasNextPage, currentPage,
|
||||
sortBy, sortOrder
|
||||
curPerPage, hasNextPage, currentPage
|
||||
} = this.props;
|
||||
|
||||
if (loading) {
|
||||
@@ -68,20 +67,7 @@ class Content extends Component {
|
||||
} else {
|
||||
let columns = [];
|
||||
|
||||
let sortIcon;
|
||||
if (sortBy == '') {
|
||||
// initial sort icon
|
||||
sortIcon = <span className="sf3-font sf3-font-sort3"></span>;
|
||||
} else {
|
||||
sortIcon = <span className={`sf3-font ${sortOrder == 'asc' ? 'sf3-font-down rotate-180 d-inline-block' : 'sf3-font-down'}`}></span>;
|
||||
}
|
||||
const spaceText = gettext('Space Used');
|
||||
const spaceEl =
|
||||
sortBy != undefined ? // only offer 'sort' for 'DB' & 'LDAPImported' users
|
||||
<a className="d-inline-block table-sort-op" href="#" onClick={this.sortByQuotaUsage}>{spaceText} {sortIcon}</a> :
|
||||
spaceText;
|
||||
const colSpaceText = <Fragment>{spaceEl}{` / ${gettext('Quota')}`}</Fragment>;
|
||||
|
||||
const colSpaceText = `${gettext('Space Used')} / ${gettext('Quota')}`;
|
||||
const colNameText = `${gettext('Name')} / ${gettext('Contact Email')}`;
|
||||
const colCreatedText = `${gettext('Created At')} / ${gettext('Last Login')} / ${gettext('Last Access')}`;
|
||||
if (isPro) {
|
||||
|
@@ -2,9 +2,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { siteRoot, gettext, haveLDAP, isDefaultAdmin } from '../../../utils/constants';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
|
||||
const propTypes = {
|
||||
currentItem: PropTypes.string.isRequired
|
||||
currentItem: PropTypes.string.isRequired,
|
||||
sortBy: PropTypes.string,
|
||||
sortOrder: PropTypes.string,
|
||||
sortItems: PropTypes.func
|
||||
};
|
||||
|
||||
class Nav extends React.Component {
|
||||
@@ -25,10 +29,21 @@ class Nav extends React.Component {
|
||||
{ name: 'admin', urlPart: 'users/admins', text: gettext('Admin') }
|
||||
);
|
||||
}
|
||||
|
||||
this.sortOptions = [
|
||||
{ value: 'quota_usage-asc', text: gettext('Ascending by space used') },
|
||||
{ value: 'quota_usage-desc', text: gettext('Descending by space used') }
|
||||
];
|
||||
}
|
||||
|
||||
onSelectSortOption = (item) => {
|
||||
const [sortBy, sortOrder] = item.value.split('-');
|
||||
this.props.sortItems(sortBy, sortOrder);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentItem } = this.props;
|
||||
const { currentItem, sortBy, sortOrder } = this.props;
|
||||
const showSortIcon = currentItem == 'database' || currentItem == 'ldap-imported';
|
||||
return (
|
||||
<div className="cur-view-path tab-nav-container">
|
||||
<ul className="nav">
|
||||
@@ -40,6 +55,14 @@ class Nav extends React.Component {
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{showSortIcon &&
|
||||
<SortMenu
|
||||
sortBy={sortBy}
|
||||
sortOrder={sortOrder}
|
||||
sortOptions={this.sortOptions}
|
||||
onSelectSortOption={this.onSelectSortOption}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -227,10 +227,10 @@ class Users extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
sortByQuotaUsage = () => {
|
||||
sortByQuotaUsage = (sortBy, sortOrder) => {
|
||||
this.setState({
|
||||
sortBy: 'quota_usage',
|
||||
sortOrder: this.state.sortOrder == 'asc' ? 'desc' : 'asc',
|
||||
sortBy: sortBy,
|
||||
sortOrder: sortOrder,
|
||||
currentPage: 1
|
||||
}, () => {
|
||||
const { currentPage, perPage, sortBy, sortOrder } = this.state;
|
||||
@@ -504,7 +504,12 @@ class Users extends Component {
|
||||
</MainPanelTopbar>
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<UsersNav currentItem={curTab} />
|
||||
<UsersNav
|
||||
currentItem={curTab}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortItems={this.sortByQuotaUsage}
|
||||
/>
|
||||
<div className="cur-view-content">
|
||||
{curTab == 'database' &&
|
||||
<UsersFilterBar
|
||||
@@ -520,9 +525,6 @@ class Users extends Component {
|
||||
loading={this.state.loading}
|
||||
errorMsg={this.state.errorMsg}
|
||||
items={this.state.userList}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
sortByQuotaUsage={this.sortByQuotaUsage}
|
||||
currentPage={this.state.currentPage}
|
||||
hasNextPage={this.state.hasNextPage}
|
||||
curPerPage={this.state.perPage}
|
||||
|
Reference in New Issue
Block a user