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:
12
frontend/package-lock.json
generated
12
frontend/package-lock.json
generated
@@ -180,7 +180,7 @@
|
||||
"dependencies": {
|
||||
"reactstrap": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.3",
|
||||
@@ -640,7 +640,7 @@
|
||||
},
|
||||
"axios": {
|
||||
"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=",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.3.0",
|
||||
@@ -2507,9 +2507,9 @@
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.42.0.tgz",
|
||||
"integrity": "sha512-pbApC8zDzItP3HRphD6kQVwS976qB5Qi0hU3MZMixLk+AyugOW1RF+8XJEjeyl5yWsHNe88tDUxzeRh5AOxPRw=="
|
||||
"version": "5.42.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.42.2.tgz",
|
||||
"integrity": "sha512-Tkv6im39VuhduFMsDA3MlXcC/kKas3Z0PI1/8N88QvFQbtOeiiwnfFJE4juGyC8/a4sb1BSxQlzsil8XLQdxRw=="
|
||||
},
|
||||
"collapse-white-space": {
|
||||
"version": "1.0.4",
|
||||
@@ -9964,7 +9964,7 @@
|
||||
},
|
||||
"react-popper": {
|
||||
"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=",
|
||||
"requires": {
|
||||
"popper.js": "^1.12.9",
|
||||
|
@@ -1,17 +1,20 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
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);
|
||||
|
||||
const propTypes = {
|
||||
isItemFrezeed: PropTypes.bool.isRequired,
|
||||
isFirstItem: PropTypes.bool.isRequired,
|
||||
preCommitID: PropTypes.string.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
currentItem: PropTypes.object.isRequired,
|
||||
onMenuControlClick: PropTypes.func.isRequired,
|
||||
onHistoryItemClick: PropTypes.func.isRequired,
|
||||
currentItem: PropTypes.object,
|
||||
isItemFreezed: PropTypes.bool.isRequired,
|
||||
onItemClick: PropTypes.func.isRequired,
|
||||
onItemRestore: PropTypes.func.isRequired,
|
||||
onFreezedItemToggle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class HistoryListItem extends React.Component {
|
||||
@@ -19,42 +22,57 @@ class HistoryListItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isShowOperationIcon: false
|
||||
isShowOperationIcon: false,
|
||||
isMenuShow: false,
|
||||
};
|
||||
}
|
||||
|
||||
onMouseEnter = () => {
|
||||
if (!this.props.isItemFrezeed) {
|
||||
if (!this.props.isItemFreezed) {
|
||||
this.setState({isShowOperationIcon: true});
|
||||
}
|
||||
}
|
||||
|
||||
onMouseLeave = () => {
|
||||
if (!this.props.isItemFrezeed) {
|
||||
if (!this.props.isItemFreezed) {
|
||||
this.setState({isShowOperationIcon: false});
|
||||
}
|
||||
}
|
||||
|
||||
onToggleClick = (e) => {
|
||||
this.setState({isMenuShow: !this.state.isMenuShow});
|
||||
this.props.onFreezedItemToggle();
|
||||
}
|
||||
|
||||
onItemClick = () => {
|
||||
this.setState({isShowOperationIcon: false}); //restore to default state
|
||||
if (this.props.item.commit_id === this.props.currentItem.commit_id) {
|
||||
return;
|
||||
}
|
||||
this.setState({isShowOperationIcon: false}); //restore to default state
|
||||
this.props.onHistoryItemClick(this.props.item, this.props.preCommitID);
|
||||
let currentIndex = this.props.index;
|
||||
this.props.onItemClick(this.props.item, currentIndex);
|
||||
}
|
||||
|
||||
onMenuControlClick = (e) => {
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
this.props.onMenuControlClick(e, this.props.item , this.props.isFirstItem);
|
||||
onItemRestore = () => {
|
||||
this.props.onItemRestore(this.props.currentItem);
|
||||
}
|
||||
|
||||
onItemDownload = () => {
|
||||
// nothing todo
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.currentItem) {
|
||||
return '';
|
||||
}
|
||||
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;
|
||||
if (this.props.item && this.props.currentItem) {
|
||||
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 (
|
||||
<li
|
||||
className={`history-list-item ${isHigtlightItem ? 'item-active' : ''}`}
|
||||
@@ -70,10 +88,19 @@ class HistoryListItem extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div className="history-operation">
|
||||
<MenuControl
|
||||
isShow={this.state.isShowOperationIcon || isHigtlightItem}
|
||||
onClick={this.onMenuControlClick}
|
||||
<Dropdown isOpen={this.state.isMenuShow} toggle={this.onToggleClick}>
|
||||
<DropdownToggle
|
||||
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>
|
||||
</li>
|
||||
);
|
||||
|
@@ -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;
|
@@ -2,25 +2,41 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import HisotyListItem from './history-list-item';
|
||||
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 = {
|
||||
hasMore: PropTypes.bool.isRequired,
|
||||
isReloadingData: PropTypes.bool.isRequired,
|
||||
isItemFrezeed: PropTypes.bool.isRequired,
|
||||
historyList: PropTypes.array.isRequired,
|
||||
currentItem: PropTypes.object,
|
||||
reloadMore: PropTypes.func.isRequired,
|
||||
onMenuControlClick: PropTypes.func.isRequired,
|
||||
onHistoryItemClick: PropTypes.func.isRequired,
|
||||
setDiffContent: PropTypes.func.isRequired,
|
||||
onItemClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
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) => {
|
||||
const clientHeight = event.target.clientHeight;
|
||||
const scrollHeight = event.target.scrollHeight;
|
||||
@@ -32,46 +48,30 @@ class HistoryListView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let historyList = this.props.historyList;
|
||||
if (historyList.length > 1) {
|
||||
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[0].rev_file_id});
|
||||
let downLoadURL1 = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[1].rev_file_id});
|
||||
axios.all([
|
||||
editUtilties.getFileContent(downLoadURL),
|
||||
editUtilties.getFileContent(downLoadURL1)
|
||||
]).then(axios.spread((res1, res2) => {
|
||||
this.props.setDiffContent(res1.data, res2.data);
|
||||
}));
|
||||
onItemClick = (item, currentIndex) => {
|
||||
this.setState({currentItem: item});
|
||||
if (currentIndex !== this.props.historyList.length) {
|
||||
let preItem = this.props.historyList[currentIndex + 1];
|
||||
this.props.onItemClick(item, preItem);
|
||||
} else {
|
||||
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: historyList[0].rev_file_id});
|
||||
axios.all([
|
||||
editUtilties.getFileContent(downLoadURL),
|
||||
]).then(axios.spread((res1) => {
|
||||
this.props.setDiffContent(res1.data, '');
|
||||
}));
|
||||
this.props.onItemClick(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ul className="history-list-container" onScroll={this.onScrollHandler}>
|
||||
{this.props.historyList.map((item, index, historyList) => {
|
||||
let preItemIndex = index + 1;
|
||||
if (preItemIndex === historyList.length) {
|
||||
preItemIndex = index;
|
||||
}
|
||||
{this.props.historyList.map((item, index) => {
|
||||
return (
|
||||
<HisotyListItem
|
||||
key={index}
|
||||
item={item}
|
||||
isFirstItem={index === 0}
|
||||
preCommitID={historyList[preItemIndex].rev_file_id}
|
||||
currentItem={this.props.currentItem}
|
||||
isItemFrezeed={this.props.isItemFrezeed}
|
||||
onMenuControlClick={this.props.onMenuControlClick}
|
||||
onHistoryItemClick={this.props.onHistoryItemClick}
|
||||
index={index}
|
||||
currentItem={this.state.currentItem}
|
||||
isItemFreezed={this.state.isItemFreezed}
|
||||
onItemClick={this.onItemClick}
|
||||
onItemRestore={this.props.onItemRestore}
|
||||
onFreezedItemToggle={this.onFreezedItemToggle}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@@ -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;
|
||||
border-radius: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.history, .markdown-viewer-render-content {
|
||||
.markdown-viewer-render-content {
|
||||
background-color: #fff;
|
||||
word-break: break-word;
|
||||
margin: 20px 40px;
|
||||
border: 1px solid #e6e6dd;
|
||||
}
|
||||
|
||||
.history-heading {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
.panel-header {
|
||||
position: relative;
|
||||
padding: .5rem 0rem;
|
||||
padding: .5rem 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.history .history-body {
|
||||
flex: 1;
|
||||
.history-body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.history-list-container {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -93,14 +109,3 @@
|
||||
text-decoration: none;
|
||||
color: #6e7687;
|
||||
}
|
||||
|
||||
.history-viewer-contanier {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.markdown-viewer-render-content {
|
||||
margin: 20px 40px;
|
||||
border: 1px solid #e6e6dd;
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,12 @@
|
||||
/* for top bottom layout*/
|
||||
#header {
|
||||
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 */
|
||||
|
@@ -1,11 +1,14 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import axios from 'axios';
|
||||
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 CommonToolbar from './components/toolbar/common-toolbar';
|
||||
import SidePanel from './pages/file-history/side-panel';
|
||||
import MainPanel from './pages/file-history/main-panel';
|
||||
import axios from 'axios';
|
||||
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
@@ -19,52 +22,80 @@ class FileHistory extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
content: '',
|
||||
renderingContent: true,
|
||||
fileOwner: '',
|
||||
markdownContent: '',
|
||||
markdownContentOld: ''
|
||||
newMarkdownContent: '',
|
||||
oldMarkdownContent: ''
|
||||
};
|
||||
}
|
||||
|
||||
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({
|
||||
renderingContent: false,
|
||||
markdownContent: markdownContent,
|
||||
markdownContentOld: markdownContentOld
|
||||
newmarkdownContent: newmarkdownContent,
|
||||
oldMarkdownContent: oldMarkdownContent,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onHistoryItemClick = (item, preCommitID)=> {
|
||||
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});
|
||||
onHistoryItemClick = (item, preItem)=> {
|
||||
this.setState({renderingContent: true});
|
||||
if (preItem) {
|
||||
let currID = item.rev_file_id;
|
||||
let preID = preItem.rev_file_id;
|
||||
let downLoadURL = URLDecorator.getUrl({type: 'download_historic_file', filePath: filePath, objID: currID});
|
||||
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() {
|
||||
return(
|
||||
<div id="main" className="history-main">
|
||||
<SidePanel
|
||||
fileOwner={this.state.fileOwner}
|
||||
onHistoryItemClick={this.onHistoryItemClick}
|
||||
setDiffContent={this.setDiffContent}
|
||||
/>
|
||||
<Fragment>
|
||||
<div id="header" className="history-header">
|
||||
<div className="title">
|
||||
<a href="javascript:window.history.back()" className="go-back" title="Back">
|
||||
<span className="fas fa-chevron-left"></span>
|
||||
</a>
|
||||
<span className="name">{fileName}</span>
|
||||
</div>
|
||||
<div className='toolbar'>
|
||||
<CommonToolbar onSearchedClick={this.onSearchedClick} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="main" className="history-content">
|
||||
<SidePanel onItemClick={this.onHistoryItemClick}/>
|
||||
<MainPanel
|
||||
markdownContent={this.state.markdownContent}
|
||||
markdownContentOld={this.state.markdownContentOld}
|
||||
newMarkdownContent={this.state.newMarkdownContent}
|
||||
oldMarkdownContent={this.state.oldMarkdownContent}
|
||||
renderingContent={this.state.renderingContent}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Prism from 'prismjs';
|
||||
import Loading from '../../components/loading';
|
||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||
import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer';
|
||||
import '../../css/initial-style.css';
|
||||
|
||||
@@ -12,8 +11,8 @@ const contentClass = 'markdown-viewer-render-content';
|
||||
const propTypes = {
|
||||
renderingContent: PropTypes.bool.isRequired,
|
||||
content: PropTypes.string,
|
||||
markdownContent: PropTypes.string.isRequired,
|
||||
markdownContentOld: PropTypes.string.isRequired,
|
||||
newMarkdownContent: PropTypes.string.isRequired,
|
||||
oldMarkdownContent: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
class MainPanel extends React.Component {
|
||||
@@ -28,20 +27,20 @@ class MainPanel extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="main-panel viewer">
|
||||
<div className="main-panel-north">
|
||||
<CommonToolbar onSearchedClick={this.onSearchedClick} />
|
||||
</div>
|
||||
<div className="main-panel-center history-viewer-contanier">
|
||||
<div className="content-viewer">
|
||||
<div className="main-panel">
|
||||
<div className="main-panel-center content-viewer">
|
||||
{
|
||||
this.props.renderingContent ?
|
||||
(<div className={contentClass + ' article'}><Loading /></div>) :
|
||||
(<div className={contentClass + ' article'}><DiffViewer markdownContent={this.props.markdownContent} markdownContent1={this.props.markdownContentOld}/></div>)
|
||||
(<div className={contentClass + ' article'}>
|
||||
<DiffViewer
|
||||
newMarkdownContent={this.props.newMarkdownContent}
|
||||
oldMarkdownContent={this.props.oldMarkdownContent}
|
||||
/>
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import React from 'react';
|
||||
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 Loading from '../../components/loading';
|
||||
import HistoryListView from '../../components/history-list-view/history-list-view';
|
||||
import HistoryListMenu from '../../components/history-list-view/history-list-menu';
|
||||
|
||||
const propTypes = {
|
||||
onHistoryItemClick: PropTypes.func.isRequired,
|
||||
setDiffContent: PropTypes.func.isRequired,
|
||||
onItemClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class SidePanel extends React.Component {
|
||||
@@ -22,24 +20,19 @@ class SidePanel extends React.Component {
|
||||
isLoading: true,
|
||||
isError: false,
|
||||
fileOwner: '',
|
||||
isListMenuShow: false,
|
||||
isFirstItem: false,
|
||||
currentItem: null,
|
||||
menuPosition: {top: '', left: ''},
|
||||
isItemFrezeed: false,
|
||||
isReloadingData: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
editUtilties.listFileHistoryRecords(filePath, 1, PER_PAGE).then(res => {
|
||||
this.initResultState(res.data);
|
||||
document.addEventListener('click', this.onHideContextMenu);
|
||||
});
|
||||
let historyList = res.data;
|
||||
if (historyList.length === 0) {
|
||||
this.setState({isLoading: false});
|
||||
throw Error('there has an error in server');
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.onHideContextMenu);
|
||||
this.initResultState(res.data);
|
||||
});
|
||||
}
|
||||
|
||||
refershFileList() {
|
||||
@@ -57,7 +50,6 @@ class SidePanel extends React.Component {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
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 = () => {
|
||||
if (!this.state.isReloadingData) {
|
||||
let currentPage = this.state.currentPage + 1;
|
||||
@@ -103,16 +76,13 @@ class SidePanel extends React.Component {
|
||||
});
|
||||
editUtilties.listFileHistoryRecords(filePath, currentPage, PER_PAGE).then(res => {
|
||||
this.updateResultState(res.data);
|
||||
this.setState({
|
||||
isReloadingData: false
|
||||
});
|
||||
this.setState({isReloadingData: false});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onRestoreFile = () => {
|
||||
this.onHideContextMenu();
|
||||
let commitId = this.state.currentItem.commit_id;
|
||||
onItemRestore = (currentItem) => {
|
||||
let commitId = currentItem.commit_id;
|
||||
editUtilties.revertFile(filePath, commitId).then(res => {
|
||||
if (res.data.success) {
|
||||
this.setState({isLoading: true});
|
||||
@@ -121,28 +91,15 @@ class SidePanel extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
onDownloadFile = () => {
|
||||
this.onHideContextMenu();
|
||||
}
|
||||
|
||||
onHistoryItemClick =(item, preCommitID) => {
|
||||
this.setState({currentItem: item});
|
||||
this.props.onHistoryItemClick(item, preCommitID);
|
||||
onItemClick =(item, preItem) => {
|
||||
this.props.onItemClick(item, preItem);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="side-panel">
|
||||
<div className="side-panel-north">
|
||||
<div className="history-heading">
|
||||
<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="side-panel-center">
|
||||
<div className="panel-header">{gettext('History Versions')}</div>
|
||||
<div className="history-body">
|
||||
{this.state.isLoading && <Loading />}
|
||||
{this.state.historyInfo &&
|
||||
@@ -150,22 +107,11 @@ class SidePanel extends React.Component {
|
||||
hasMore={this.state.hasMore}
|
||||
isReloadingData={this.state.isReloadingData}
|
||||
historyList={this.state.historyInfo}
|
||||
onMenuControlClick={this.onShowContenxtMenu}
|
||||
isItemFrezeed={this.state.isItemFrezeed}
|
||||
reloadMore={this.reloadMore}
|
||||
currentItem={this.state.currentItem}
|
||||
onHistoryItemClick={this.onHistoryItemClick}
|
||||
setDiffContent={this.props.setDiffContent}
|
||||
onItemClick={this.onItemClick}
|
||||
onItemRestore={this.onItemRestore}
|
||||
/>
|
||||
}
|
||||
<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>
|
||||
|
@@ -732,18 +732,6 @@ a.sf-popover-item:hover {
|
||||
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 */
|
||||
.side-panel-top {
|
||||
padding: .5rem 1rem;
|
||||
|
Reference in New Issue
Block a user