1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-17 07:41:26 +00:00

Merge branch '7.0'

This commit is contained in:
plt
2019-07-22 20:39:11 +08:00
9 changed files with 165 additions and 40 deletions

View File

@@ -39,10 +39,10 @@ class InternalLinkDialog extends React.Component {
this.setState({
isOpen: true,
smartLink: res.data.smart_link
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}

View File

@@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'reactstrap';
import toaster from '../toast';
import copy from '@seafile/seafile-editor/dist/utils/copy-to-clipboard';
import { gettext } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
const propTypes = {
path: PropTypes.string.isRequired,
repoID: PropTypes.string.isRequired,
};
class InternalLink extends React.Component {
constructor(props) {
super(props);
this.state = {
smartLink: '',
};
}
componentDidMount() {
let repoID = this.props.repoID;
let path = this.props.path;
seafileAPI.getInternalLink(repoID, path).then(res => {
this.setState({
smartLink: res.data.smart_link
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
copyToClipBoard = () => {
copy(this.state.smartLink);
let message = gettext('Internal link has been copied to clipboard');
toaster.success(message), {
duration: 2
};
}
render() {
return (
<div>
<p className="tip mb-1">
{gettext('An internal link is a link to a file or folder that can be accessed by users with read permission to the file or folder.')}
</p>
<p>
<a target="_blank" href={this.state.smartLink}>{this.state.smartLink}</a>
</p>
<Button onClick={this.copyToClipBoard} color="primary" className="mt-2">{gettext('Copy')}</Button>
</div>
);
}
}
InternalLink.propTypes = propTypes;
export default InternalLink;

View File

@@ -6,6 +6,7 @@ import ShareToUser from './share-to-user';
import ShareToGroup from './share-to-group';
import GenerateShareLink from './generate-share-link';
import GenerateUploadLink from './generate-upload-link';
import InternalLink from './internal-link';
import { seafileAPI } from '../../utils/seafile-api';
import Loading from '../loading';
import { Utils } from '../../utils/utils';
@@ -78,7 +79,7 @@ class ShareDialog extends React.Component {
const {repoEncrypted, userPerm, enableDirPrivateShare} = this.props;
const enableShareLink = !repoEncrypted && canGenerateShareLink;
const enableUploadLink = !repoEncrypted && canGenerateUploadLink && userPerm == 'rw';
return (
<Fragment>
<div className="share-dialog-side">
@@ -150,16 +151,22 @@ class ShareDialog extends React.Component {
}
renderFileContent = () => {
let activeTab = this.state.activeTab;
return (
<Fragment>
<div className="share-dialog-side">
<Nav pills vertical>
<NavItem>
<NavLink
className="active" onClick={() => {this.toggle.bind(this, 'shareLink');}}>
<NavLink className={activeTab === 'shareLink' ? 'active' : ''} onClick={(this.toggle.bind(this, 'shareLink'))}>
{gettext('Share Link')}
</NavLink>
</NavItem>
<NavItem>
<NavLink className={activeTab === 'internalLink' ? 'active' : ''} onClick={this.toggle.bind(this, 'internalLink')}>
{gettext('Internal Link')}
</NavLink>
</NavItem>
</Nav>
</div>
<div className="share-dialog-main">
@@ -171,6 +178,12 @@ class ShareDialog extends React.Component {
closeShareDialog={this.props.toggleDialog}
/>
</TabPane>
<TabPane tabId="internalLink">
<InternalLink
repoID={this.props.repoID}
path={this.props.itemPath}
/>
</TabPane>
</TabContent>
</div>
</Fragment>

View File

@@ -1,7 +1,8 @@
import React, { Component, Fragment } from 'react';
import { Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
import PropTypes from 'prop-types';
import moment from 'moment';
import { siteRoot } from '../../utils/constants';
import { siteRoot, gettext } from '../../utils/constants';
// import { seafileAPI } from '../../utils/seafile-api';
// import Toast from '../toast';
import ModalPortal from '../modal-portal';
@@ -23,6 +24,7 @@ class WikiListItem extends Component {
constructor(props) {
super(props);
this.state = {
isOpMenuOpen: false, // for mobile
isShowDeleteDialog: false,
// isRenameing: false,
highlight: false,
@@ -30,6 +32,12 @@ class WikiListItem extends Component {
};
}
toggleOpMenu = () => {
this.setState({
isOpMenuOpen: !this.state.isOpMenuOpen
});
}
// clickMenuToggle = (e) => {
// e.preventDefault();
// this.onMenuToggle(e);
@@ -130,23 +138,55 @@ class WikiListItem extends Component {
let fileIconUrl = Utils.getDefaultLibIconUrl(false);
let deleteIcon = `action-icon sf2-icon-x3 ${this.state.highlight ? '' : 'invisible'}`;
return (
<Fragment>
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<td><img src={fileIconUrl} width="24" alt="" /></td>
<td className="name">
<a href={wiki.link}>{wiki.name}</a>
{/*this.state.isRenameing ?
const desktopItem = (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<td><img src={fileIconUrl} width="24" alt="" /></td>
<td className="name">
<a href={wiki.link}>{wiki.name}</a>
{/*this.state.isRenameing ?
<Rename wiki={wiki} name={wiki.name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel}/> :
<a href={wiki.link}>{wiki.name}</a>
*/}
</td>
<td><a href={userProfileURL} target='_blank'>{wiki.owner_nickname}</a></td>
<td>{moment(wiki.updated_at).fromNow()}</td>
<td className="text-center cursor-pointer">
<span className={deleteIcon} onClick={this.onDeleteToggle}></span>
</td>
</tr>
</td>
<td><a href={userProfileURL} target='_blank'>{wiki.owner_nickname}</a></td>
<td>{moment(wiki.updated_at).fromNow()}</td>
<td className="text-center cursor-pointer">
<span className={deleteIcon} onClick={this.onDeleteToggle}></span>
</td>
</tr>
);
const mobileItem = (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<td><img src={fileIconUrl} width="24" alt="" /></td>
<td>
<a href={wiki.link}>{wiki.name}</a><br />
<a href={userProfileURL} target='_blank' className="item-meta-info">{wiki.owner_nickname}</a>
<span className="item-meta-info">{moment(wiki.updated_at).fromNow()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle fa fa-ellipsis-v ml-0"
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<div className={this.state.isOpMenuOpen ? '' : 'd-none'} onClick={this.toggleOpMenu}>
<div className="mobile-operation-menu-bg-layer"></div>
<div className="mobile-operation-menu">
<DropdownItem className="mobile-menu-item" onClick={this.onDeleteToggle}>{gettext('Unpublish')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
);
return (
<Fragment>
{window.innerWidth >= 768 ? desktopItem : mobileItem}
{this.state.isShowDeleteDialog &&
<ModalPortal>
<WikiDeleteDialog

View File

@@ -1,8 +1,8 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import MediaQuery from 'react-responsive';
import { gettext } from '../../utils/constants';
import WikiListItem from './wiki-list-item';
import LibsMobileThead from '../libs-mobile-thead';
const propTypes = {
data: PropTypes.object.isRequired,
@@ -35,23 +35,20 @@ class WikiListView extends Component {
} else if (errorMsg) {
return <p className="error text-center">{errorMsg}</p>;
} else {
const desktopThead = (
<thead>
<tr>
<th width="4%"></th>
<th width="36%">{gettext('Name')}</th>
<th width="25%">{gettext('Owner')}</th>
<th width="25%">{gettext('Last Update')}</th>
<th width="10%">{/* operation */}</th>
</tr>
</thead>
);
return (
<table>
<thead>
<tr>
<MediaQuery query="(min-width: 768px)">
<th width="4%"></th>
<th width="36%">{gettext('Name')}</th>
</MediaQuery>
<MediaQuery query="(max-width: 767.8px)">
<th width="10%"></th>
<th width="30%">{gettext('Name')}</th>
</MediaQuery>
<th width="25%">{gettext('Owner')}</th>
<th width="25%">{gettext('Last Update')}</th>
<th width="10%">{/* operation */}</th>
</tr>
</thead>
<table className={window.innerWidth >= 768 ? '' : 'table-thead-hidden'}>
{window.innerWidth >= 768 ? desktopThead : <LibsMobileThead />}
<tbody>
{wikis.map((wiki, index) => {
return (

View File

@@ -46,6 +46,7 @@
.seafile-comment-list .comment-vacant {
padding: 1em;
text-align: center;
list-style: none;
}
.seafile-comment-item {
padding: 15px 10px;

View File

@@ -4,6 +4,7 @@
position: relative;
display: flex;
flex: 1;
align-items: center;
}
.border-left-show:before {

View File

@@ -135,7 +135,7 @@ class Wikis extends Component {
<Button className="btn btn-secondary operation-item" onClick={this.onSelectToggle}>{gettext('Publish a Library')}</Button>
</MediaQuery>
<MediaQuery query="(max-width: 767.8px)">
<Button className="btn btn-secondary operation-item my-1" onClick={this.onSelectToggle}>{gettext('Publish a Library')}</Button>
<span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('Publish a Library')} onClick={this.onSelectToggle}></span>
</MediaQuery>
</Fragment>}
</div>