1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-07 18:03:48 +00:00

File history improve (#2707)

This commit is contained in:
杨顺强
2018-12-25 10:39:57 +08:00
committed by Daniel Pan
parent fbc9f2a9de
commit e1524f01a5
10 changed files with 218 additions and 279 deletions

View File

@@ -180,7 +180,7 @@
"dependencies": { "dependencies": {
"reactstrap": { "reactstrap": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz", "resolved": "http://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz",
"integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==", "integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==",
"requires": { "requires": {
"classnames": "^2.2.3", "classnames": "^2.2.3",
@@ -640,7 +640,7 @@
}, },
"axios": { "axios": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": { "requires": {
"follow-redirects": "^1.3.0", "follow-redirects": "^1.3.0",
@@ -2507,9 +2507,9 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
}, },
"codemirror": { "codemirror": {
"version": "5.42.0", "version": "5.42.2",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.42.0.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.42.2.tgz",
"integrity": "sha512-pbApC8zDzItP3HRphD6kQVwS976qB5Qi0hU3MZMixLk+AyugOW1RF+8XJEjeyl5yWsHNe88tDUxzeRh5AOxPRw==" "integrity": "sha512-Tkv6im39VuhduFMsDA3MlXcC/kKas3Z0PI1/8N88QvFQbtOeiiwnfFJE4juGyC8/a4sb1BSxQlzsil8XLQdxRw=="
}, },
"collapse-white-space": { "collapse-white-space": {
"version": "1.0.4", "version": "1.0.4",
@@ -9964,7 +9964,7 @@
}, },
"react-popper": { "react-popper": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-0.8.3.tgz", "resolved": "http://registry.npmjs.org/react-popper/-/react-popper-0.8.3.tgz",
"integrity": "sha1-D3MzMTfJ+wr27EB00tBYWgoEYeE=", "integrity": "sha1-D3MzMTfJ+wr27EB00tBYWgoEYeE=",
"requires": { "requires": {
"popper.js": "^1.12.9", "popper.js": "^1.12.9",

View File

@@ -1,17 +1,20 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import moment from 'moment'; import moment from 'moment';
import MenuControl from '../menu-control'; import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem} from 'reactstrap';
import { gettext, filePath } from '../../utils/constants';
import URLDecorator from '../../utils/url-decorator';
moment.locale(window.app.config.lang); moment.locale(window.app.config.lang);
const propTypes = { const propTypes = {
isItemFrezeed: PropTypes.bool.isRequired, index: PropTypes.number.isRequired,
isFirstItem: PropTypes.bool.isRequired,
preCommitID: PropTypes.string.isRequired,
item: PropTypes.object.isRequired, item: PropTypes.object.isRequired,
currentItem: PropTypes.object.isRequired, currentItem: PropTypes.object,
onMenuControlClick: PropTypes.func.isRequired, isItemFreezed: PropTypes.bool.isRequired,
onHistoryItemClick: PropTypes.func.isRequired, onItemClick: PropTypes.func.isRequired,
onItemRestore: PropTypes.func.isRequired,
onFreezedItemToggle: PropTypes.func.isRequired,
}; };
class HistoryListItem extends React.Component { class HistoryListItem extends React.Component {
@@ -19,42 +22,57 @@ class HistoryListItem extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isShowOperationIcon: false isShowOperationIcon: false,
isMenuShow: false,
}; };
} }
onMouseEnter = () => { onMouseEnter = () => {
if (!this.props.isItemFrezeed) { if (!this.props.isItemFreezed) {
this.setState({isShowOperationIcon: true}); this.setState({isShowOperationIcon: true});
} }
} }
onMouseLeave = () => { onMouseLeave = () => {
if (!this.props.isItemFrezeed) { if (!this.props.isItemFreezed) {
this.setState({isShowOperationIcon: false}); this.setState({isShowOperationIcon: false});
} }
} }
onToggleClick = (e) => {
this.setState({isMenuShow: !this.state.isMenuShow});
this.props.onFreezedItemToggle();
}
onItemClick = () => { onItemClick = () => {
this.setState({isShowOperationIcon: false}); //restore to default state
if (this.props.item.commit_id === this.props.currentItem.commit_id) { if (this.props.item.commit_id === this.props.currentItem.commit_id) {
return; return;
} }
this.setState({isShowOperationIcon: false}); //restore to default state let currentIndex = this.props.index;
this.props.onHistoryItemClick(this.props.item, this.props.preCommitID); this.props.onItemClick(this.props.item, currentIndex);
} }
onMenuControlClick = (e) => { onItemRestore = () => {
e.nativeEvent.stopImmediatePropagation(); this.props.onItemRestore(this.props.currentItem);
this.props.onMenuControlClick(e, this.props.item , this.props.isFirstItem); }
onItemDownload = () => {
// nothing todo
} }
render() { render() {
if (!this.props.currentItem) {
return '';
}
let item = this.props.item; let item = this.props.item;
let time = moment.parseZone(item.ctime).format('YYYY-MM-DD HH:mm'); let time = moment(item.ctime).format('YYYY-MM-DD HH:mm');
let isHigtlightItem = false; let isHigtlightItem = false;
if (this.props.item && this.props.currentItem) { if (this.props.item && this.props.currentItem) {
isHigtlightItem = this.props.item.commit_id === this.props.currentItem.commit_id; isHigtlightItem = this.props.item.commit_id === this.props.currentItem.commit_id;
} }
let objID = this.props.currentItem.rev_file_id;
let url = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: objID});
return ( return (
<li <li
className={`history-list-item ${isHigtlightItem ? 'item-active' : ''}`} className={`history-list-item ${isHigtlightItem ? 'item-active' : ''}`}
@@ -70,10 +88,19 @@ class HistoryListItem extends React.Component {
</div> </div>
</div> </div>
<div className="history-operation"> <div className="history-operation">
<MenuControl <Dropdown isOpen={this.state.isMenuShow} toggle={this.onToggleClick}>
isShow={this.state.isShowOperationIcon || isHigtlightItem} <DropdownToggle
onClick={this.onMenuControlClick} tag='a'
/> className={`fas fa-ellipsis-v ${(this.state.isShowOperationIcon || isHigtlightItem) ? '' : 'invisible'}`}
data-toggle="dropdown"
aria-expanded={this.state.isMenuShow}
alt={gettext('More Operations')}
/>
<DropdownMenu>
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemRestore}>{gettext('Restore')}</DropdownItem>}
<DropdownItem tag='a' href={url} onClick={this.onItemDownLoad}>{gettext('Download')}</DropdownItem>
</DropdownMenu>
</Dropdown>
</div> </div>
</li> </li>
); );

View File

@@ -1,63 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { gettext, filePath } from '../../utils/constants';
import URLDecorator from '../../utils/url-decorator';
const propTypes = {
isFirstItem: PropTypes.bool.isRequired,
isListMenuShow: PropTypes.bool.isRequired,
menuPosition: PropTypes.object.isRequired,
currentItem: PropTypes.object,
onDownloadFile: PropTypes.func.isRequired,
onRestoreFile: PropTypes.func.isRequired,
};
class HistoryListMenu extends React.Component {
onDownloadFile = () => {
this.props.onDownloadFile();
}
onRestoreFile = () => {
this.props.onRestoreFile();
}
render() {
let style = {};
let position = this.props.menuPosition;
if (this.props.isListMenuShow) {
style = {position: 'fixed',left: position.left + 'px',top: position.top + 'px',display: 'block'};
}
if (!this.props.currentItem) {
return '';
}
let objID = this.props.currentItem.rev_file_id;
let url = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: objID});
if (this.props.isFirstItem) {
return (
<ul className="dropdown-menu" style={style}>
<li className="dropdown-item" onClick={this.onDownloadFile}>
<a href={url}>{gettext('Download')}</a>
</li>
</ul>
);
}
return (
<ul className="dropdown-menu" style={style}>
<li className="dropdown-item" onClick={this.onRestoreFile}>{gettext('Restore')}</li>
<li className="dropdown-item" onClick={this.onDownloadFile}>
<a href={url}>{gettext('Download')}</a>
</li>
</ul>
);
}
}
HistoryListMenu.propTypes = propTypes;
export default HistoryListMenu;

View File

@@ -2,25 +2,41 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import HisotyListItem from './history-list-item'; import HisotyListItem from './history-list-item';
import Loading from '../loading'; import Loading from '../loading';
import axios from 'axios';
import editUtilties from '../../utils/editor-utilties';
import URLDecorator from '../../utils/url-decorator';
import { filePath } from '../../utils/constants';
const propTypes = { const propTypes = {
hasMore: PropTypes.bool.isRequired, hasMore: PropTypes.bool.isRequired,
isReloadingData: PropTypes.bool.isRequired, isReloadingData: PropTypes.bool.isRequired,
isItemFrezeed: PropTypes.bool.isRequired,
historyList: PropTypes.array.isRequired, historyList: PropTypes.array.isRequired,
currentItem: PropTypes.object,
reloadMore: PropTypes.func.isRequired, reloadMore: PropTypes.func.isRequired,
onMenuControlClick: PropTypes.func.isRequired, onItemClick: PropTypes.func.isRequired,
onHistoryItemClick: PropTypes.func.isRequired,
setDiffContent: PropTypes.func.isRequired,
}; };
class HistoryListView extends React.Component { class HistoryListView extends React.Component {
constructor(props) {
super(props);
this.state = {
isItemFreezed: false,
currentItem: null,
};
}
componentDidMount = () => {
let historyList = this.props.historyList;
if (historyList.length > 0) {
this.setState({currentItem: historyList[0]});
if (historyList === 1) {
this.props.onItemClick(historyList[0]);
} else {
this.props.onItemClick(historyList[0], historyList[1]);
}
}
}
onFreezedItemToggle = () => {
this.setState({isItemFreezed: !this.state.isItemFreezed});
}
onScrollHandler = (event) => { onScrollHandler = (event) => {
const clientHeight = event.target.clientHeight; const clientHeight = event.target.clientHeight;
const scrollHeight = event.target.scrollHeight; const scrollHeight = event.target.scrollHeight;
@@ -32,46 +48,30 @@ class HistoryListView extends React.Component {
} }
} }
componentDidMount() { onItemClick = (item, currentIndex) => {
let historyList = this.props.historyList; this.setState({currentItem: item});
if (historyList.length > 1) { if (currentIndex !== this.props.historyList.length) {
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[0].rev_file_id}); let preItem = this.props.historyList[currentIndex + 1];
let downLoadURL1 = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[1].rev_file_id}); this.props.onItemClick(item, preItem);
axios.all([
editUtilties.getFileContent(downLoadURL),
editUtilties.getFileContent(downLoadURL1)
]).then(axios.spread((res1, res2) => {
this.props.setDiffContent(res1.data, res2.data);
}));
} else { } else {
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[0].rev_file_id}); this.props.onItemClick(item);
axios.all([
editUtilties.getFileContent(downLoadURL),
]).then(axios.spread((res1) => {
this.props.setDiffContent(res1.data, '');
}));
} }
} }
render() { render() {
return ( return (
<ul className="history-list-container" onScroll={this.onScrollHandler}> <ul className="history-list-container" onScroll={this.onScrollHandler}>
{this.props.historyList.map((item, index, historyList) => { {this.props.historyList.map((item, index) => {
let preItemIndex = index + 1;
if (preItemIndex === historyList.length) {
preItemIndex = index;
}
return ( return (
<HisotyListItem <HisotyListItem
key={index} key={index}
item={item} item={item}
isFirstItem={index === 0} index={index}
preCommitID={historyList[preItemIndex].rev_file_id} currentItem={this.state.currentItem}
currentItem={this.props.currentItem} isItemFreezed={this.state.isItemFreezed}
isItemFrezeed={this.props.isItemFrezeed} onItemClick={this.onItemClick}
onMenuControlClick={this.props.onMenuControlClick} onItemRestore={this.props.onItemRestore}
onHistoryItemClick={this.props.onHistoryItemClick} onFreezedItemToggle={this.onFreezedItemToggle}
/> />
); );
})} })}

View File

@@ -1,38 +1,54 @@
.history-main { .history-header .title {
font-size: 1.5rem;
line-height: 1rem;
}
.history-header .title .go-back {
margin-right: 0.75rem;
color: #c0c0c0;
}
.history-header .title .go-back:hover {
color:#ff9933;
text-decoration: none;
}
.content-viewer {
background-color: #fafaf9; background-color: #fafaf9;
border-radius: 10px; border-radius: 10px;
overflow: auto;
} }
.history, .markdown-viewer-render-content { .markdown-viewer-render-content {
background-color: #fff; background-color: #fff;
word-break: break-word; word-break: break-word;
margin: 20px 40px;
border: 1px solid #e6e6dd;
} }
.history-heading { .panel-header {
font-size: 25px;
}
.panel-heading {
position: relative; position: relative;
padding: .5rem 0rem; padding: .5rem 0;
width: 100%; width: 100%;
border-bottom: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8;
font-size: 1rem; font-size: 1rem;
font-weight: normal; font-weight: 400;
line-height: 1.5; line-height: 1.5;
height: 36px; height: 36px;
text-align: center; text-align: center;
} }
.history .history-body { .history-body {
flex: 1;
display: flex; display: flex;
flex: 1;
overflow: hidden;
min-height: 0; min-height: 0;
} }
.history-list-container { .history-list-container {
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0;
overflow: auto; overflow: auto;
} }
@@ -93,14 +109,3 @@
text-decoration: none; text-decoration: none;
color: #6e7687; color: #6e7687;
} }
.history-viewer-contanier {
flex: 1;
overflow: auto;
}
.markdown-viewer-render-content {
margin: 20px 40px;
border: 1px solid #e6e6dd;
}

View File

@@ -8,6 +8,12 @@
/* for top bottom layout*/ /* for top bottom layout*/
#header { #header {
display: flex; display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 1rem;
border-bottom: 1px solid #e8e8e8;
background-color: #f4f4f7;
font-size: 1rem;
} }
/* for left right layout */ /* for left right layout */

View File

@@ -1,11 +1,14 @@
import React from 'react'; import React, { Fragment } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import axios from 'axios';
import editUtilties from './utils/editor-utilties'; import editUtilties from './utils/editor-utilties';
import { filePath } from './utils/constants'; import { siteRoot, filePath, fileName } from './utils/constants';
import { Utils } from './utils/utils';
import URLDecorator from './utils/url-decorator'; import URLDecorator from './utils/url-decorator';
import CommonToolbar from './components/toolbar/common-toolbar';
import SidePanel from './pages/file-history/side-panel'; import SidePanel from './pages/file-history/side-panel';
import MainPanel from './pages/file-history/main-panel'; import MainPanel from './pages/file-history/main-panel';
import axios from 'axios';
import './assets/css/fa-solid.css'; import './assets/css/fa-solid.css';
import './assets/css/fa-regular.css'; import './assets/css/fa-regular.css';
import './assets/css/fontawesome.css'; import './assets/css/fontawesome.css';
@@ -19,52 +22,80 @@ class FileHistory extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
content: '',
renderingContent: true, renderingContent: true,
fileOwner: '', newMarkdownContent: '',
markdownContent: '', oldMarkdownContent: ''
markdownContentOld: ''
}; };
} }
onSearchedClick = (selectedItem) => {
if (selectedItem.is_dir === true) {
let url = siteRoot + 'library/' + selectedItem.repo_id + '/' + selectedItem.repo_name + selectedItem.path;
let newWindow = window.open('about:blank');
newWindow.location.href = url;
} else {
let url = siteRoot + 'lib/' + selectedItem.repo_id + '/file' + Utils.encodePath(selectedItem.path);
let newWindow = window.open('about:blank');
newWindow.location.href = url;
}
}
setDiffContent = (markdownContent, markdownContentOld)=> { setDiffContent = (newmarkdownContent, oldMarkdownContent)=> {
this.setState({ this.setState({
renderingContent: false, renderingContent: false,
markdownContent: markdownContent, newmarkdownContent: newmarkdownContent,
markdownContentOld: markdownContentOld oldMarkdownContent: oldMarkdownContent,
}); });
} }
onHistoryItemClick = (item, preCommitID)=> { onHistoryItemClick = (item, preItem)=> {
let objID = item.rev_file_id;
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: objID});
let downLoadURL1 = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: preCommitID});
this.setState({renderingContent: true}); this.setState({renderingContent: true});
axios.all([ if (preItem) {
editUtilties.getFileContent(downLoadURL), let currID = item.rev_file_id;
editUtilties.getFileContent(downLoadURL1) let preID = preItem.rev_file_id;
]).then(axios.spread((res1, res2) => { let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: currID});
this.setDiffContent(res1.data, res2.data); let downLoadURL1 = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: preID});
})); axios.all([
editUtilties.getFileContent(downLoadURL),
editUtilties.getFileContent(downLoadURL1)
]).then(axios.spread((res1, res2) => {
this.setDiffContent(res1.data, res2.data);
}));
} else {
let currID = item.rev_file_id;
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: currID});
axios.all([
editUtilties.getFileContent(downLoadURL),
]).then(axios.spread((res1) => {
this.setDiffContent(res1.data, '');
}));
}
} }
render() { render() {
return( return(
<div id="main" className="history-main"> <Fragment>
<SidePanel <div id="header" className="history-header">
fileOwner={this.state.fileOwner} <div className="title">
onHistoryItemClick={this.onHistoryItemClick} <a href="javascript:window.history.back()" className="go-back" title="Back">
setDiffContent={this.setDiffContent} <span className="fas fa-chevron-left"></span>
/> </a>
<MainPanel <span className="name">{fileName}</span>
markdownContent={this.state.markdownContent} </div>
markdownContentOld={this.state.markdownContentOld} <div className='toolbar'>
renderingContent={this.state.renderingContent} <CommonToolbar onSearchedClick={this.onSearchedClick} />
/> </div>
</div>
</div> <div id="main" className="history-content">
<SidePanel onItemClick={this.onHistoryItemClick}/>
<MainPanel
newMarkdownContent={this.state.newMarkdownContent}
oldMarkdownContent={this.state.oldMarkdownContent}
renderingContent={this.state.renderingContent}
/>
</div>
</Fragment>
); );
} }
} }

View File

@@ -2,7 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Prism from 'prismjs'; import Prism from 'prismjs';
import Loading from '../../components/loading'; import Loading from '../../components/loading';
import CommonToolbar from '../../components/toolbar/common-toolbar';
import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer'; import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer';
import '../../css/initial-style.css'; import '../../css/initial-style.css';
@@ -12,8 +11,8 @@ const contentClass = 'markdown-viewer-render-content';
const propTypes = { const propTypes = {
renderingContent: PropTypes.bool.isRequired, renderingContent: PropTypes.bool.isRequired,
content: PropTypes.string, content: PropTypes.string,
markdownContent: PropTypes.string.isRequired, newMarkdownContent: PropTypes.string.isRequired,
markdownContentOld: PropTypes.string.isRequired, oldMarkdownContent: PropTypes.string.isRequired,
}; };
class MainPanel extends React.Component { class MainPanel extends React.Component {
@@ -28,18 +27,18 @@ class MainPanel extends React.Component {
render() { render() {
return ( return (
<div className="main-panel viewer"> <div className="main-panel">
<div className="main-panel-north"> <div className="main-panel-center content-viewer">
<CommonToolbar onSearchedClick={this.onSearchedClick} /> {
</div> this.props.renderingContent ?
<div className="main-panel-center history-viewer-contanier"> (<div className={contentClass + ' article'}><Loading /></div>) :
<div className="content-viewer"> (<div className={contentClass + ' article'}>
{ <DiffViewer
this.props.renderingContent ? newMarkdownContent={this.props.newMarkdownContent}
(<div className={contentClass + ' article'}><Loading /></div>) : oldMarkdownContent={this.props.oldMarkdownContent}
(<div className={contentClass + ' article'}><DiffViewer markdownContent={this.props.markdownContent} markdownContent1={this.props.markdownContentOld}/></div>) />
} </div>)
</div> }
</div> </div>
</div> </div>
); );

View File

@@ -1,14 +1,12 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { gettext, PER_PAGE, filePath, fileName } from '../../utils/constants'; import { gettext, PER_PAGE, filePath } from '../../utils/constants';
import editUtilties from '../../utils/editor-utilties'; import editUtilties from '../../utils/editor-utilties';
import Loading from '../../components/loading'; import Loading from '../../components/loading';
import HistoryListView from '../../components/history-list-view/history-list-view'; import HistoryListView from '../../components/history-list-view/history-list-view';
import HistoryListMenu from '../../components/history-list-view/history-list-menu';
const propTypes = { const propTypes = {
onHistoryItemClick: PropTypes.func.isRequired, onItemClick: PropTypes.func.isRequired,
setDiffContent: PropTypes.func.isRequired,
}; };
class SidePanel extends React.Component { class SidePanel extends React.Component {
@@ -22,26 +20,21 @@ class SidePanel extends React.Component {
isLoading: true, isLoading: true,
isError: false, isError: false,
fileOwner: '', fileOwner: '',
isListMenuShow: false,
isFirstItem: false,
currentItem: null,
menuPosition: {top: '', left: ''},
isItemFrezeed: false,
isReloadingData: false, isReloadingData: false,
}; };
} }
componentDidMount() { componentDidMount() {
editUtilties.listFileHistoryRecords(filePath, 1, PER_PAGE).then(res => { editUtilties.listFileHistoryRecords(filePath, 1, PER_PAGE).then(res => {
let historyList = res.data;
if (historyList.length === 0) {
this.setState({isLoading: false});
throw Error('there has an error in server');
}
this.initResultState(res.data); this.initResultState(res.data);
document.addEventListener('click', this.onHideContextMenu);
}); });
} }
componentWillUnmount() {
document.removeEventListener('click', this.onHideContextMenu);
}
refershFileList() { refershFileList() {
editUtilties.listFileHistoryRecords(filePath, 1, PER_PAGE).then(res => { editUtilties.listFileHistoryRecords(filePath, 1, PER_PAGE).then(res => {
this.initResultState(res.data); this.initResultState(res.data);
@@ -57,7 +50,6 @@ class SidePanel extends React.Component {
isLoading: false, isLoading: false,
isError: false, isError: false,
fileOwner: result.data[0].creator_email, fileOwner: result.data[0].creator_email,
currentItem: result.data[0],
}); });
} }
} }
@@ -75,25 +67,6 @@ class SidePanel extends React.Component {
} }
} }
onShowContenxtMenu = (e, item, isFirstItem) => {
let left = e.clientX - 8*16;
let top = e.clientY + 10;
this.setState({
currentItem: item,
isFirstItem: isFirstItem,
isListMenuShow: !this.state.isListMenuShow,
menuPosition: {top: top, left: left},
isItemFrezeed: !this.state.isItemFrezeed,
});
}
onHideContextMenu = (e) => {
this.setState({
isListMenuShow: false,
isItemFrezeed: false
});
}
reloadMore = () => { reloadMore = () => {
if (!this.state.isReloadingData) { if (!this.state.isReloadingData) {
let currentPage = this.state.currentPage + 1; let currentPage = this.state.currentPage + 1;
@@ -103,16 +76,13 @@ class SidePanel extends React.Component {
}); });
editUtilties.listFileHistoryRecords(filePath, currentPage, PER_PAGE).then(res => { editUtilties.listFileHistoryRecords(filePath, currentPage, PER_PAGE).then(res => {
this.updateResultState(res.data); this.updateResultState(res.data);
this.setState({ this.setState({isReloadingData: false});
isReloadingData: false
});
}); });
} }
} }
onRestoreFile = () => { onItemRestore = (currentItem) => {
this.onHideContextMenu(); let commitId = currentItem.commit_id;
let commitId = this.state.currentItem.commit_id;
editUtilties.revertFile(filePath, commitId).then(res => { editUtilties.revertFile(filePath, commitId).then(res => {
if (res.data.success) { if (res.data.success) {
this.setState({isLoading: true}); this.setState({isLoading: true});
@@ -121,28 +91,15 @@ class SidePanel extends React.Component {
}); });
} }
onDownloadFile = () => { onItemClick =(item, preItem) => {
this.onHideContextMenu(); this.props.onItemClick(item, preItem);
}
onHistoryItemClick =(item, preCommitID) => {
this.setState({currentItem: item});
this.props.onHistoryItemClick(item, preCommitID);
} }
render() { render() {
return ( return (
<div className="side-panel"> <div className="side-panel">
<div className="side-panel-north"> <div className="side-panel-center">
<div className="history-heading"> <div className="panel-header">{gettext('History Versions')}</div>
<a href="javascript:window.history.back()" className="go-back" title="Back">
<span className="fas fa-chevron-left"></span>
</a>
<span className="history-doc-name">{fileName}</span>
</div>
</div>
<div className="side-panel-center history">
<div className="panel-heading history-heading">{gettext('History Versions')}</div>
<div className="history-body"> <div className="history-body">
{this.state.isLoading && <Loading />} {this.state.isLoading && <Loading />}
{this.state.historyInfo && {this.state.historyInfo &&
@@ -150,22 +107,11 @@ class SidePanel extends React.Component {
hasMore={this.state.hasMore} hasMore={this.state.hasMore}
isReloadingData={this.state.isReloadingData} isReloadingData={this.state.isReloadingData}
historyList={this.state.historyInfo} historyList={this.state.historyInfo}
onMenuControlClick={this.onShowContenxtMenu}
isItemFrezeed={this.state.isItemFrezeed}
reloadMore={this.reloadMore} reloadMore={this.reloadMore}
currentItem={this.state.currentItem} onItemClick={this.onItemClick}
onHistoryItemClick={this.onHistoryItemClick} onItemRestore={this.onItemRestore}
setDiffContent={this.props.setDiffContent}
/> />
} }
<HistoryListMenu
isListMenuShow={this.state.isListMenuShow}
menuPosition={this.state.menuPosition}
isFirstItem={this.state.isFirstItem}
currentItem={this.state.currentItem}
onRestoreFile={this.onRestoreFile}
onDownloadFile={this.onDownloadFile}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -732,18 +732,6 @@ a.sf-popover-item:hover {
background-color: #f8f8f8; background-color: #f8f8f8;
} }
/* for go-back */
.go-back {
font-size: 25px;
padding-right: 0.75rem;
color:#ccc;
}
.go-back:hover {
color:#ff9933;
text-decoration: none;
}
/* basic layout */ /* basic layout */
.side-panel-top { .side-panel-top {
padding: .5rem 1rem; padding: .5rem 1rem;