mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-05 17:02:47 +00:00
Draft menu improve (#2981)
* [update]draft menu implement method * update menu style * repair word error
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { siteRoot, lang } from '../../utils/constants';
|
|
||||||
import { Utils } from '../../utils/utils';
|
|
||||||
import MenuControl from '../menu-control';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||||
|
import { gettext, siteRoot, lang } from '../../utils/constants';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
moment.locale(lang);
|
moment.locale(lang);
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
isItemFreezed: PropTypes.bool.isRequired,
|
|
||||||
onMenuToggleClick: PropTypes.func.isRequired,
|
|
||||||
draft: PropTypes.object.isRequired,
|
draft: PropTypes.object.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
onDeleteHandler: PropTypes.func.isRequired,
|
||||||
|
onReviewHandler: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DraftListItem extends React.Component {
|
class DraftListItem extends React.Component {
|
||||||
@@ -17,16 +20,17 @@ class DraftListItem extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isMenuControlShow: false,
|
isMenuIconShow: false,
|
||||||
highlight: '',
|
isItemMenuShow: false,
|
||||||
|
highlight: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
if (!this.props.isItemFreezed) {
|
if (!this.props.isItemFreezed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isMenuControlShow: true,
|
isMenuIconShow: true,
|
||||||
highlight: 'tr-highlight'
|
highlight: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,16 +38,40 @@ class DraftListItem extends React.Component {
|
|||||||
onMouseLeave = () => {
|
onMouseLeave = () => {
|
||||||
if (!this.props.isItemFreezed) {
|
if (!this.props.isItemFreezed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isMenuControlShow: false,
|
isMenuIconShow: false,
|
||||||
highlight: ''
|
highlight: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMenuToggleClick = (e) => {
|
onDropdownToggleClick = (e) => {
|
||||||
e.nativeEvent.stopImmediatePropagation();
|
e.preventDefault();
|
||||||
let draft = this.props.draft;
|
this.toggleOperationMenu(e);
|
||||||
this.props.onMenuToggleClick(e, draft);
|
}
|
||||||
|
|
||||||
|
toggleOperationMenu = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState(
|
||||||
|
{isItemMenuShow: !this.state.isItemMenuShow }, () => {
|
||||||
|
if (this.state.isItemMenuShow) {
|
||||||
|
this.props.onFreezedItem();
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
highlight: false,
|
||||||
|
isMenuIconShow: false,
|
||||||
|
});
|
||||||
|
this.props.onUnfreezedItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteHandler = () => {
|
||||||
|
this.props.onDeleteHandler(this.props.draft);
|
||||||
|
}
|
||||||
|
|
||||||
|
onReviewHandler = () => {
|
||||||
|
this.props.onReviewHandler(this.props.draft);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -59,7 +87,7 @@ class DraftListItem extends React.Component {
|
|||||||
|
|
||||||
let iconUrl = Utils.getFileIconUrl(fileName);
|
let iconUrl = Utils.getFileIconUrl(fileName);
|
||||||
return (
|
return (
|
||||||
<tr className={this.state.highlight} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td className="text-center"><img src={iconUrl} width="24" alt='' /></td>
|
<td className="text-center"><img src={iconUrl} width="24" alt='' /></td>
|
||||||
<td className="name" >
|
<td className="name" >
|
||||||
<a href={draftUrl} target="_blank">{fileName}</a>
|
<a href={draftUrl} target="_blank">{fileName}</a>
|
||||||
@@ -74,14 +102,23 @@ class DraftListItem extends React.Component {
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td className="update">{localTime}</td>
|
<td className="update">{localTime}</td>
|
||||||
<td className="text-center cursor-pointer">
|
<td className="text-center">
|
||||||
{
|
{(this.props.draft.review_status !== 'open' && this.state.isMenuIconShow) && (
|
||||||
this.props.draft.review_status !== 'open' &&
|
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
|
||||||
<MenuControl
|
<DropdownToggle
|
||||||
isShow={this.state.isMenuControlShow}
|
tag="i"
|
||||||
onClick={this.onMenuToggleClick}
|
className="fas fa-ellipsis-v attr-action-icon"
|
||||||
|
title={gettext('More Operations')}
|
||||||
|
onClick={this.onDropdownToggleClick}
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-expanded={this.state.isItemMenuShow}
|
||||||
/>
|
/>
|
||||||
}
|
<DropdownMenu>
|
||||||
|
<DropdownItem onClick={this.onDeleteHandler}>{gettext('Delete')}</DropdownItem>
|
||||||
|
<DropdownItem onClick={this.onReviewHandler}>{gettext('Ask for review')}</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
@@ -4,13 +4,28 @@ import { gettext } from '../../utils/constants';
|
|||||||
import DraftListItem from './draft-list-item';
|
import DraftListItem from './draft-list-item';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
isItemFreezed: PropTypes.bool.isRequired,
|
|
||||||
draftList: PropTypes.array.isRequired,
|
draftList: PropTypes.array.isRequired,
|
||||||
onMenuToggleClick: PropTypes.func.isRequired,
|
onDeleteHandler: PropTypes.func.isRequired,
|
||||||
|
onReviewHandler: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DraftListView extends React.Component {
|
class DraftListView extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isItemFreezed: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onFreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: false});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let drafts = this.props.draftList;
|
let drafts = this.props.draftList;
|
||||||
return (
|
return (
|
||||||
@@ -31,8 +46,11 @@ class DraftListView extends React.Component {
|
|||||||
<DraftListItem
|
<DraftListItem
|
||||||
key={draft.id}
|
key={draft.id}
|
||||||
draft={draft}
|
draft={draft}
|
||||||
onMenuToggleClick={this.props.onMenuToggleClick}
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
isItemFreezed={this.props.isItemFreezed}
|
onFreezedItem={this.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
onDeleteHandler={this.props.onDeleteHandler}
|
||||||
|
onReviewHandler={this.props.onReviewHandler}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { siteRoot, gettext } from '../../utils/constants';
|
import { siteRoot, gettext } from '../../utils/constants';
|
||||||
import editUtilties from '../../utils/editor-utilties';
|
import editUtilties from '../../utils/editor-utilties';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
@@ -6,38 +6,22 @@ import PropTypes from 'prop-types';
|
|||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import DraftListView from '../../components/draft-list-view/draft-list-view';
|
import DraftListView from '../../components/draft-list-view/draft-list-view';
|
||||||
import DraftListMenu from '../../components/draft-list-view/draft-list-menu';
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
updateDraftsList: PropTypes.func.isRequired,
|
|
||||||
isLoadingDraft: PropTypes.bool.isRequired,
|
isLoadingDraft: PropTypes.bool.isRequired,
|
||||||
draftList: PropTypes.arrayOf(PropTypes.object),
|
updateDraftsList: PropTypes.func.isRequired,
|
||||||
|
draftList: PropTypes.array.isRequired,
|
||||||
getDrafts: PropTypes.func.isRequired,
|
getDrafts: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DraftContent extends React.Component {
|
class DraftContent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isMenuShow: false,
|
|
||||||
menuPosition: {top:'', left: ''},
|
|
||||||
currentDraft: null,
|
|
||||||
isItemFreezed: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.getDrafts();
|
this.props.getDrafts();
|
||||||
document.addEventListener('click', this.onHideContextMenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
onDeleteHandler = (draft) => {
|
||||||
document.removeEventListener('click', this.onHideContextMenu);
|
// let draft = this.state.currentDraft;
|
||||||
}
|
|
||||||
|
|
||||||
onDeleteHandler = () => {
|
|
||||||
let draft = this.state.currentDraft;
|
|
||||||
let draft_name = Utils.getFileName(draft.draft_file_path);
|
let draft_name = Utils.getFileName(draft.draft_file_path);
|
||||||
editUtilties.deleteDraft(draft.id).then(res => {
|
editUtilties.deleteDraft(draft.id).then(res => {
|
||||||
this.props.updateDraftsList(draft.id);
|
this.props.updateDraftsList(draft.id);
|
||||||
@@ -51,6 +35,17 @@ class DraftContent extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onReviewHandler = (draft) => {
|
||||||
|
editUtilties.createDraftReview(draft.id).then(res => {
|
||||||
|
const w = window.open();
|
||||||
|
w.location = siteRoot + 'drafts/review/' + res.data.id;
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.status == '409') {
|
||||||
|
toaster.danger(gettext('Review already exists.'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onPublishHandler = () => {
|
onPublishHandler = () => {
|
||||||
let draft = this.state.currentDraft;
|
let draft = this.state.currentDraft;
|
||||||
let draft_name = Utils.getFileName(draft.draft_file_path);
|
let draft_name = Utils.getFileName(draft.draft_file_path);
|
||||||
@@ -66,74 +61,27 @@ class DraftContent extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onReviewHandler = () => {
|
|
||||||
let draft = this.state.currentDraft;
|
|
||||||
|
|
||||||
editUtilties.createDraftReview(draft.id).then(res => {
|
|
||||||
const w = window.open();
|
|
||||||
w.location = siteRoot + 'drafts/review/' + res.data.id;
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.response.status == '409') {
|
|
||||||
toaster.danger(gettext('Review already exists.'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMenuToggleClick = (e, draft) => {
|
|
||||||
if (this.state.isMenuShow) {
|
|
||||||
this.onHideContextMenu();
|
|
||||||
} else {
|
|
||||||
this.onShowContextMenu(e, draft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowContextMenu = (e, draft) => {
|
|
||||||
let left = e.clientX - 8*16;
|
|
||||||
let top = e.clientY + 10;
|
|
||||||
let position = {top: top, left: left};
|
|
||||||
this.setState({
|
|
||||||
isMenuShow: true,
|
|
||||||
menuPosition: position,
|
|
||||||
currentDraft: draft,
|
|
||||||
isItemFreezed: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onHideContextMenu = () => {
|
|
||||||
this.setState({
|
|
||||||
isMenuShow: false,
|
|
||||||
currentDraft: null,
|
|
||||||
isItemFreezed: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
{this.props.isLoadingDraft && <Loading /> }
|
{this.props.isLoadingDraft && <Loading />}
|
||||||
{(!this.props.isLoadingDraft && this.props.draftList.length !==0) &&
|
{!this.props.isLoadingDraft && (
|
||||||
<DraftListView
|
<Fragment>
|
||||||
draftList={this.props.draftList}
|
{this.props.draftList.length === 0 && (
|
||||||
isItemFreezed={this.state.isItemFreezed}
|
|
||||||
onMenuToggleClick={this.onMenuToggleClick}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{(!this.props.isLoadingDraft && this.props.draftList.length === 0) &&
|
|
||||||
<div className="message empty-tip">
|
<div className="message empty-tip">
|
||||||
<h2>{gettext('No draft yet')}</h2>
|
<h2>{gettext('No draft yet')}</h2>
|
||||||
<p>{gettext('Draft is a way to let you collaborate with others on files. You can create a draft from a file, edit the draft and then ask for a review. The original file will be updated only after the draft be reviewed.')}</p>
|
<p>{gettext('Draft is a way to let you collaborate with others on files. You can create a draft from a file, edit the draft and then ask for a review. The original file will be updated only after the draft be reviewed.')}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
{this.state.isMenuShow &&
|
{this.props.draftList.length !==0 && (
|
||||||
<DraftListMenu
|
<DraftListView
|
||||||
isMenuShow={this.state.isMenuShow}
|
draftList={this.props.draftList}
|
||||||
currentDraft={this.state.currentDraft}
|
|
||||||
menuPosition={this.state.menuPosition}
|
|
||||||
onPublishHandler={this.onPublishHandler}
|
|
||||||
onDeleteHandler={this.onDeleteHandler}
|
onDeleteHandler={this.onDeleteHandler}
|
||||||
onReviewHandler={this.onReviewHandler}
|
onReviewHandler={this.onReviewHandler}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user