1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-27 15:54:39 +00:00

Change share link dialog UI (#7881)

* 01 Add qr-code in share link item

* 02 Show access scope and password in share list

* 03 optimise style
This commit is contained in:
Michael An
2025-06-03 18:00:00 +08:00
committed by GitHub
parent d9a78effa1
commit 76d15b03b8
3 changed files with 85 additions and 12 deletions

View File

@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import classnames from 'classnames'; import classnames from 'classnames';
import { QRCodeSVG } from 'qrcode.react';
import { Popover, PopoverBody } from 'reactstrap';
import toaster from '../toast'; import toaster from '../toast';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
@@ -22,10 +24,31 @@ class LinkItem extends React.Component {
this.state = { this.state = {
isHighlighted: false, isHighlighted: false,
isItemOpVisible: false, isItemOpVisible: false,
isDeleteShareLinkDialogOpen: false isDeleteShareLinkDialogOpen: false,
isQRCodePopoverOpen: false
}; };
this.qrCodeBtn = null;
this.popoverContainerRef = React.createRef();
} }
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
handleClickOutside = (event) => {
if (this.state.isQRCodePopoverOpen && this.popoverContainerRef.current &&
!this.popoverContainerRef.current.contains(event.target) &&
this.qrCodeBtn && !this.qrCodeBtn.contains(event.target)) {
this.setState({
isQRCodePopoverOpen: false
});
}
};
onMouseOver = () => { onMouseOver = () => {
this.setState({ this.setState({
isHighlighted: true, isHighlighted: true,
@@ -81,8 +104,33 @@ class LinkItem extends React.Component {
this.props.deleteLink(item.token); this.props.deleteLink(item.token);
}; };
toggleQRCodePopover = () => {
this.setState({
isQRCodePopoverOpen: !this.state.isQRCodePopoverOpen
});
};
onQRCodeIconClicked = (e) => {
e.preventDefault();
e.stopPropagation();
this.toggleQRCodePopover();
};
translateScope = (scope) => {
if (scope === 'all_users') {
return gettext('Anyone with the link');
}
if (scope === 'specific_users') {
return gettext('Specific users in the team');
}
if (scope === 'specific_emails') {
return gettext('Specific people with email address');
}
return '';
};
render() { render() {
const { isHighlighted, isItemOpVisible } = this.state; const { isHighlighted, isItemOpVisible, isQRCodePopoverOpen } = this.state;
const { item } = this.props; const { item } = this.props;
const { isSelected = false, permissions, link, expire_date } = item; const { isSelected = false, permissions, link, expire_date } = item;
const currentPermission = Utils.getShareLinkPermissionStr(permissions); const currentPermission = Utils.getShareLinkPermissionStr(permissions);
@@ -113,12 +161,25 @@ class LinkItem extends React.Component {
<td> <td>
{permissions && Utils.getShareLinkPermissionObject(currentPermission).text} {permissions && Utils.getShareLinkPermissionObject(currentPermission).text}
</td> </td>
<td>{this.translateScope(item.user_scope)}</td>
<td> <td>
{expire_date ? dayjs(expire_date).format('YYYY-MM-DD HH:mm') : '--'} {expire_date ? dayjs(expire_date).format('YYYY-MM-DD HH:mm') : '--'}
</td> </td>
<td>{item.password && <i className='sf2-icon-tick'></i>}</td>
<td> <td>
<a href="#" role="button" onClick={this.onCopyIconClicked} className={`sf3-font sf3-font-copy1 op-icon ${isItemOpVisible ? '' : 'invisible'}`} title={gettext('Copy')} aria-label={gettext('Copy')}></a> <a href="#" role="button" onClick={this.onCopyIconClicked} className={`sf3-font sf3-font-copy1 op-icon ${isItemOpVisible ? '' : 'invisible'}`} title={gettext('Copy')} aria-label={gettext('Copy')}></a>
<a href="#" role="button" onClick={this.onDeleteIconClicked} className={`sf3-font-delete1 sf3-font op-icon ${isItemOpVisible ? '' : 'invisible'}`} title={gettext('Delete')} aria-label={gettext('Delete')}></a> <a href="#" role="button" onClick={this.onDeleteIconClicked} className={`sf3-font-delete1 sf3-font op-icon ${isItemOpVisible ? '' : 'invisible'}`} title={gettext('Delete')} aria-label={gettext('Delete')}></a>
<a href="#" role="button" ref={ref => this.qrCodeBtn = ref} onClick={this.onQRCodeIconClicked} className={`sf3-font sf3-font-qr-code op-icon ${isItemOpVisible ? '' : 'invisible'}`} title={gettext('QR Code')} aria-label={gettext('QR Code')}></a>
{this.qrCodeBtn && (
<div ref={this.popoverContainerRef}>
<Popover className="link-item-qrcode-popover" placement="bottom" isOpen={isQRCodePopoverOpen} target={this.qrCodeBtn}>
<PopoverBody>
<QRCodeSVG value={link} size={128} />
<p className="link-item-qrcode-tip">{gettext('Scan the QR code to view the shared content directly')}</p>
</PopoverBody>
</Popover>
</div>
)}
</td> </td>
</tr> </tr>
{this.state.isDeleteShareLinkDialogOpen && ( {this.state.isDeleteShareLinkDialogOpen && (

View File

@@ -79,12 +79,14 @@ class LinkList extends React.Component {
<table className="table-place-header"> <table className="table-place-header">
<thead> <thead>
<tr> <tr>
<th width="5%" className="text-center"> <th width="3%" className="text-center">
<input type="checkbox" checked={isAllLinksSelected} className="vam" onChange={this.toggleSelectAllLinks} /> <input type="checkbox" checked={isAllLinksSelected} className="vam" onChange={this.toggleSelectAllLinks} />
</th> </th>
<th width="26%">{gettext('Link')}</th> <th width="18%">{gettext('Link')}</th>
<th width="30%">{gettext('Permission')}</th> <th width="25%">{gettext('Permission')}</th>
<th width="25%">{gettext('Expiration')}</th> <th width="20%">{gettext('Access scope')}</th>
<th width="20%">{gettext('Expiration')}</th>
<th width="11%">{gettext('Password')}</th>
<th width="14%"></th> <th width="14%"></th>
</tr> </tr>
</thead> </thead>
@@ -93,10 +95,12 @@ class LinkList extends React.Component {
<table className="table-real-content table-thead-hidden"> <table className="table-real-content table-thead-hidden">
<thead> <thead>
<tr> <tr>
<th width="5%" className="text-center"></th> <th width="3%" className="text-center"></th>
<th width="26%">{gettext('Link')}</th> <th width="18%">{gettext('Link')}</th>
<th width="30%">{gettext('Permission')}</th> <th width="25%">{gettext('Permission')}</th>
<th width="25%">{gettext('Expiration')}</th> <th width="20%">{gettext('Access scope')}</th>
<th width="20%">{gettext('Expiration')}</th>
<th width="11%">{gettext('Password')}</th>
<th width="14%"></th> <th width="14%"></th>
</tr> </tr>
</thead> </thead>

View File

@@ -6,7 +6,7 @@
} }
.share-dialog-content .share-dialog-side { .share-dialog-content .share-dialog-side {
flex-basis: 22%; flex-basis: 18%;
padding: 1rem; padding: 1rem;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
} }
@@ -69,7 +69,7 @@
.share-dialog-content .share-dialog-main { .share-dialog-content .share-dialog-main {
display: flex; display: flex;
flex-basis: 78%; flex-basis: 82%;
padding: 1rem; padding: 1rem;
} }
@@ -210,3 +210,11 @@ input.expire-input {
max-height: 350px; max-height: 350px;
overflow-y: scroll; overflow-y: scroll;
} }
.link-item-qrcode-popover .link-item-qrcode-tip {
margin: 0;
margin-top: 0.25rem;
text-align: center;
max-width: 128px;
color: #666;
}