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

[Refactor] Do not run mobile functions on PC devices (#6408)

* 01 refactor dirent-list-item

* 02 refactor upload links

* 03 refactor linked devices

* 04 refactor user-settings linked-devices

* 05 refactor invitation view

* 06 refactor share-links

* 07 refactor starred page

* 08 refactor share-admin folders

* 09 refactor share-admin libraries

* 10 refactor shared-libs
This commit is contained in:
Michael An
2024-07-25 11:04:36 +08:00
committed by GitHub
parent 5f99c77596
commit 113a88d850
10 changed files with 752 additions and 721 deletions

View File

@@ -708,138 +708,146 @@ class DirentListItem extends React.Component {
const { canDrag } = this.state;
const lockedImageUrl = `${mediaUrl}img/file-${dirent.is_freezed ? 'freezed-32.svg' : 'locked-32.png'}`;
const lockedMessage = dirent.is_freezed ? gettext('freezed') : gettext('locked');
const desktopItem = (
<tr
className={trClass}
draggable={canDrag}
onFocus={this.onMouseEnter}
onMouseEnter={this.onMouseEnter}
onMouseOver={this.onMouseOver}
onMouseLeave={this.onMouseLeave}
onClick={this.onDirentClick}
onDragStart={this.onItemDragStart}
onDragEnter={this.onItemDragEnter}
onDragOver={this.onItemDragOver}
onDragLeave={this.onItemDragLeave}
onDrop={this.onItemDragDrop}
onMouseDown={this.onItemMouseDown}
onContextMenu={this.onItemContextMenu}
>
<td className={`pl10 ${this.state.isDragTipShow ? 'tr-drag-effect' : ''}`}>
<input
type="checkbox"
className="vam"
onChange={this.onItemSelected}
checked={isActive}
aria-label={isActive ? gettext('Unselect this item') : gettext('Select this item')}
/>
</td>
<td className="pl10">
{dirent.starred !== undefined &&
<a href="#" role="button" aria-label={dirent.starred ? gettext('Unstar') : gettext('Star')} onClick={this.onItemStarred}>
<i className={`sf3-font ${dirent.starred ? 'sf3-font-star' : 'sf3-font-star-empty'}`}></i>
</a>
}
</td>
<td className="pl10">
<div className="dir-icon">
{(this.canPreview && dirent.encoded_thumbnail_src) ?
<img ref='drag_icon' src={`${siteRoot}${dirent.encoded_thumbnail_src}`} className="thumbnail cursor-pointer" onClick={this.onItemClick} alt="" /> :
<img ref='drag_icon' src={iconUrl} width="24" alt='' />
}
{dirent.is_locked && <img className="locked" src={lockedImageUrl} alt={lockedMessage} title={lockedInfo}/>}
<div ref="empty_content" style={{ position: 'absolute', width: '1px', height: '1px' }}></div>
</div>
</td>
<td className="name">
{this.state.isRenameing && <Rename hasSuffix={dirent.type !== 'dir'} name={dirent.name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel} />}
{!this.state.isRenameing && (
<Fragment>
{(!dirent.isDir() && !this.canPreview) ?
<a className="sf-link" onClick={this.onItemClick}>{dirent.name}</a> :
<a href={dirent.type === 'dir' ? dirHref : fileHref} onClick={this.onItemClick}>{dirent.name}</a>
}
</Fragment>
)}
</td>
<td className="tag-list-title">
{(dirent.type !== 'dir' && dirent.file_tags && dirent.file_tags.length > 0) && (
<div id={this.tagListTitleID} className="dirent-item tag-list tag-list-stacked">
{dirent.file_tags.map((fileTag, index) => {
return (
<FileTag fileTag={fileTag} length={dirent.file_tags.length} key={index} index={index}/>
);
})}
</div>
)}
{(dirent.type !== 'dir' && (!dirent.file_tags || dirent.file_tags.length == 0)) && (
<div id={this.tagListTitleID} className="dirent-item tag-list tag-list-stacked"></div>
)}
</td>
<td className="operation">{this.renderItemOperation()}</td>
<td className="file-size">{dirent.size && dirent.size}</td>
<td className="last-update" title={moment.unix(dirent.mtime).format('llll')}>{dirent.mtime_relative}</td>
</tr>
);
const mobileItem = (
<tr>
<td onClick={this.onItemClick}>
<div className="dir-icon">
{(this.canPreview && dirent.encoded_thumbnail_src) ?
<img src={`${siteRoot}${dirent.encoded_thumbnail_src}`} className="thumbnail cursor-pointer" alt="" /> :
<img src={iconUrl} width="24" alt="" />
}
{dirent.is_locked && <img className="locked" src={lockedImageUrl} alt={lockedMessage} title={lockedInfo}/>}
</div>
</td>
<td onClick={this.onItemClick}>
{this.state.isRenameing && <Rename hasSuffix={dirent.type !== 'dir'} name={dirent.name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel} /> }
{!this.state.isRenameing && (
<Fragment>
{(!dirent.isDir() && !this.canPreview) ?
<a className="sf-link">{dirent.name}</a> :
<a href={dirent.type === 'dir' ? dirHref : fileHref}>{dirent.name}</a>
}
</Fragment>
)}
<br />
{dirent.size && <span className="item-meta-info">{dirent.size}</span>}
<span className="item-meta-info">{dirent.mtime_relative}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{dirent.starred !== undefined &&
<DropdownItem className="mobile-menu-item" onClick={this.onItemStarred}>{dirent.starred ? gettext('Unstar') : gettext('Star')}</DropdownItem>}
{this.props.getDirentItemMenuList(dirent, true).map((item, index) => {
if (item != 'Divider' && item.key != 'Open via Client') {
return (
<DropdownItem className="mobile-menu-item" key={index} data-op={item.key} onClick={this.onMobileMenuItemClick}>{item.value}</DropdownItem>
);
} else {
return null;
}
})}
</div>
</div>
</Dropdown>
</td>
</tr>
);
return (
<Fragment>
{isDesktop ? desktopItem : mobileItem}
{isDesktop ?
<tr
className={trClass}
draggable={canDrag}
onFocus={this.onMouseEnter}
onMouseEnter={this.onMouseEnter}
onMouseOver={this.onMouseOver}
onMouseLeave={this.onMouseLeave}
onClick={this.onDirentClick}
onDragStart={this.onItemDragStart}
onDragEnter={this.onItemDragEnter}
onDragOver={this.onItemDragOver}
onDragLeave={this.onItemDragLeave}
onDrop={this.onItemDragDrop}
onMouseDown={this.onItemMouseDown}
onContextMenu={this.onItemContextMenu}
>
<td className={`pl10 ${this.state.isDragTipShow ? 'tr-drag-effect' : ''}`}>
<input
type="checkbox"
className="vam"
onChange={this.onItemSelected}
checked={isActive}
aria-label={isActive ? gettext('Unselect this item') : gettext('Select this item')}
/>
</td>
<td className="pl10">
{dirent.starred !== undefined &&
<a href="#" role="button" aria-label={dirent.starred ? gettext('Unstar') : gettext('Star')} onClick={this.onItemStarred}>
<i className={`sf3-font ${dirent.starred ? 'sf3-font-star' : 'sf3-font-star-empty'}`}></i>
</a>
}
</td>
<td className="pl10">
<div className="dir-icon">
{(this.canPreview && dirent.encoded_thumbnail_src) ?
<img ref='drag_icon' src={`${siteRoot}${dirent.encoded_thumbnail_src}`} className="thumbnail cursor-pointer" onClick={this.onItemClick} alt="" /> :
<img ref='drag_icon' src={iconUrl} width="24" alt='' />
}
{dirent.is_locked && <img className="locked" src={lockedImageUrl} alt={lockedMessage} title={lockedInfo}/>}
<div ref="empty_content" style={{ position: 'absolute', width: '1px', height: '1px' }}></div>
</div>
</td>
<td className="name">
{this.state.isRenameing && <Rename hasSuffix={dirent.type !== 'dir'} name={dirent.name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel} />}
{!this.state.isRenameing && (
<Fragment>
{(!dirent.isDir() && !this.canPreview) ?
<a className="sf-link" onClick={this.onItemClick}>{dirent.name}</a> :
<a href={dirent.type === 'dir' ? dirHref : fileHref} onClick={this.onItemClick}>{dirent.name}</a>
}
</Fragment>
)}
</td>
<td className="tag-list-title">
{(dirent.type !== 'dir' && dirent.file_tags && dirent.file_tags.length > 0) && (
<div id={this.tagListTitleID} className="dirent-item tag-list tag-list-stacked">
{dirent.file_tags.map((fileTag, index) => {
return (
<FileTag fileTag={fileTag} length={dirent.file_tags.length} key={index} index={index}/>
);
})}
</div>
)}
{(dirent.type !== 'dir' && (!dirent.file_tags || dirent.file_tags.length == 0)) && (
<div id={this.tagListTitleID} className="dirent-item tag-list tag-list-stacked"></div>
)}
</td>
<td className="operation">{this.renderItemOperation()}</td>
<td className="file-size">{dirent.size && dirent.size}</td>
<td className="last-update" title={moment.unix(dirent.mtime).format('llll')}>{dirent.mtime_relative}</td>
</tr>
:
<tr>
<td onClick={this.onItemClick}>
<div className="dir-icon">
{(this.canPreview && dirent.encoded_thumbnail_src) ?
<img src={`${siteRoot}${dirent.encoded_thumbnail_src}`} className="thumbnail cursor-pointer" alt="" /> :
<img src={iconUrl} width="24" alt="" />
}
{dirent.is_locked && <img className="locked" src={lockedImageUrl} alt={lockedMessage} title={lockedInfo}/>}
</div>
</td>
<td onClick={this.onItemClick}>
{this.state.isRenameing && <Rename hasSuffix={dirent.type !== 'dir'} name={dirent.name} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel} /> }
{!this.state.isRenameing && (
<Fragment>
{(!dirent.isDir() && !this.canPreview) ?
<a className="sf-link">{dirent.name}</a> :
<a href={dirent.type === 'dir' ? dirHref : fileHref}>{dirent.name}</a>
}
</Fragment>
)}
<br />
{dirent.size && <span className="item-meta-info">{dirent.size}</span>}
<span className="item-meta-info">{dirent.mtime_relative}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{dirent.starred !== undefined &&
<DropdownItem className="mobile-menu-item" onClick={this.onItemStarred}>
{dirent.starred ? gettext('Unstar') : gettext('Star')}
</DropdownItem>
}
{this.props.getDirentItemMenuList(dirent, true).map((item, index) => {
if (item != 'Divider' && item.key != 'Open via Client') {
return (
<DropdownItem
className="mobile-menu-item"
key={index}
data-op={item.key}
onClick={this.onMobileMenuItemClick}
>
{item.value}
</DropdownItem>
);
} else {
return null;
}
})}
</div>
</div>
</Dropdown>
</td>
</tr>
}
{this.state.isMoveDialogShow &&
<ModalPortal>
<MoveDirentDialog

View File

@@ -126,17 +126,11 @@ class Item extends Component {
});
};
render() {
if (this.state.unlinked) {
return null;
}
renderDesktop = () => {
const data = this.props.data;
let opClasses = 'sf3-font-delete1 sf3-font unlink-device action-icon';
opClasses += this.state.isOpIconShown ? '' : ' invisible';
const desktopItem = (
return (
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td>{data.platform}</td>
<td>{data.device_name}</td>
@@ -147,8 +141,11 @@ class Item extends Component {
</td>
</tr>
);
};
const mobileItem = (
renderMobile = () => {
const data = this.props.data;
return (
<tr>
<td>
{data.device_name}<br />
@@ -176,10 +173,15 @@ class Item extends Component {
</td>
</tr>
);
};
render() {
if (this.state.unlinked) {
return null;
}
return (
<React.Fragment>
{this.props.isDesktop ? desktopItem : mobileItem}
{this.props.isDesktop ? this.renderDesktop() : this.renderMobile()}
{this.state.isConfirmUnlinkDialogOpen &&
<ConfirmUnlinkDeviceDialog
executeOperation={this.unlinkDevice}

View File

@@ -82,69 +82,65 @@ class Item extends React.Component {
const item = this.props.invitation;
const desktopItem = (
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter} tabIndex="0">
<td>{item.accepter}</td>
<td>{moment(item.invite_time).format('YYYY-MM-DD')}</td>
<td>{moment(item.expire_time).format('YYYY-MM-DD')}</td>
<td>{item.accept_time && <i className="sf2-icon-tick invite-accept-icon"></i>}</td>
<td>
{isOpIconShown && (
item.accept_time ?
<a href="#"
role="button"
className="action-icon sf3-font sf3-font-cancel-invitation"
title={gettext('Revoke Access')}
aria-label={gettext('Revoke Access')}
onClick={this.toggleRevokeDialog}>
</a> :
<a href="#"
role="button"
className="action-icon sf2-icon-x3"
title={gettext('Delete')}
aria-label={gettext('Delete')}
onClick={this.deleteItem}>
</a>
)}
</td>
</tr>
);
const mobileItem = (
<tr>
<td>
{item.accepter}<br />
<span className="item-meta-info">{moment(item.invite_time).format('YYYY-MM-DD')}<span className="small">({gettext('Invite Time')})</span></span>
<span className="item-meta-info">{moment(item.expire_time).format('YYYY-MM-DD')}<span className="small">({gettext('Expiration')})</span></span>
<span className="item-meta-info">{item.accept_time && gettext('Accepted')}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{item.accept_time ?
<DropdownItem className="mobile-menu-item" onClick={this.toggleRevokeDialog}>{gettext('Revoke Access')}</DropdownItem> :
<DropdownItem className="mobile-menu-item" onClick={this.deleteItem}>{gettext('Delete')}</DropdownItem>
}
</div>
</div>
</Dropdown>
</td>
</tr>
);
return (
<Fragment>
{this.props.isDesktop ? desktopItem : mobileItem}
{this.props.isDesktop ?
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter} tabIndex="0">
<td>{item.accepter}</td>
<td>{moment(item.invite_time).format('YYYY-MM-DD')}</td>
<td>{moment(item.expire_time).format('YYYY-MM-DD')}</td>
<td>{item.accept_time && <i className="sf2-icon-tick invite-accept-icon"></i>}</td>
<td>
{isOpIconShown && (
item.accept_time ?
<a href="#"
role="button"
className="action-icon sf3-font sf3-font-cancel-invitation"
title={gettext('Revoke Access')}
aria-label={gettext('Revoke Access')}
onClick={this.toggleRevokeDialog}>
</a> :
<a href="#"
role="button"
className="action-icon sf2-icon-x3"
title={gettext('Delete')}
aria-label={gettext('Delete')}
onClick={this.deleteItem}>
</a>
)}
</td>
</tr>
:
<tr>
<td>
{item.accepter}<br />
<span className="item-meta-info">{moment(item.invite_time).format('YYYY-MM-DD')}<span className="small">({gettext('Invite Time')})</span></span>
<span className="item-meta-info">{moment(item.expire_time).format('YYYY-MM-DD')}<span className="small">({gettext('Expiration')})</span></span>
<span className="item-meta-info">{item.accept_time && gettext('Accepted')}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{item.accept_time ?
<DropdownItem className="mobile-menu-item" onClick={this.toggleRevokeDialog}>{gettext('Revoke Access')}</DropdownItem> :
<DropdownItem className="mobile-menu-item" onClick={this.deleteItem}>{gettext('Delete')}</DropdownItem>
}
</div>
</div>
</Dropdown>
</td>
</tr>
}
{isRevokeDialogOpen &&
<InvitationRevokeDialog
accepter={item.accepter}

View File

@@ -128,17 +128,11 @@ class Item extends Component {
});
};
render() {
if (this.state.unlinked) {
return null;
}
renderDesktopItem = () => {
const data = this.props.data;
let opClasses = 'sf3-font-delete1 sf3-font unlink-device action-icon';
opClasses += this.state.isOpIconShown ? '' : ' invisible';
const desktopItem = (
return (
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td>{data.platform}</td>
<td>{data.device_name}</td>
@@ -149,8 +143,11 @@ class Item extends Component {
</td>
</tr>
);
};
const mobileItem = (
renderMobileItem = () => {
const data = this.props.data;
return (
<tr>
<td>
{data.device_name}<br />
@@ -178,10 +175,15 @@ class Item extends Component {
</td>
</tr>
);
};
render() {
if (this.state.unlinked) {
return null;
}
return (
<React.Fragment>
{this.props.isDesktop ? desktopItem : mobileItem}
{this.props.isDesktop ? this.renderDesktopItem() : this.renderMobileItem()}
{this.state.isConfirmUnlinkDialogOpen &&
<ConfirmUnlinkDeviceDialog
executeOperation={this.unlinkDevice}

View File

@@ -209,89 +209,90 @@ class Item extends Component {
if (share_permission.startsWith('custom-')) {
share_permission = share_permission.slice(7);
}
const desktopItem = (
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter}>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td><Link to={folderUrl}>{item.folder_name}</Link></td>
<td>
{item.share_type == 'personal' ?
<span title={item.contact_email}>{item.user_name}</span> : item.group_name}
</td>
<td>
{!isShowPermEditor && (
<div>
<span>{Utils.sharePerms(share_permission) || share_permission_name}</span>
{isOpIconShown && (
<a href="#"
role="button"
aria-label={gettext('Edit')}
title={gettext('Edit')}
className="sf3-font sf3-font-rename attr-action-icon"
onClick={this.onEditPermission}>
</a>
)}
</div>
)}
{isShowPermEditor && (
<SharePermissionEditor
if (this.props.isDesktop) {
return (
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter}>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td><Link to={folderUrl}>{item.folder_name}</Link></td>
<td>
{item.share_type == 'personal' ?
<span title={item.contact_email}>{item.user_name}</span> : item.group_name}
</td>
<td>
{!isShowPermEditor && (
<div>
<span>{Utils.sharePerms(share_permission) || share_permission_name}</span>
{isOpIconShown && (
<a href="#"
role="button"
aria-label={gettext('Edit')}
title={gettext('Edit')}
className="sf3-font sf3-font-rename attr-action-icon"
onClick={this.onEditPermission}>
</a>
)}
</div>
)}
{isShowPermEditor && (
<SharePermissionEditor
repoID={item.repo_id}
isTextMode={true}
isEditIconShow={isOpIconShown}
isEditing={true}
autoFocus={true}
currentPermission={share_permission}
permissions={this.permissions}
onPermissionChanged={this.changePerm}
/>
)}
</td>
<td><a href="#" role="button" aria-label={gettext('Unshare')} className={`action-icon sf2-icon-x3 ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Unshare')} onClick={this.unshare}></a></td>
</tr>
);
} else {
return (
<Fragment>
<tr>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td>
<Link to={folderUrl}>{item.folder_name}</Link>
<span className="item-meta-info-highlighted">{Utils.sharePerms(share_permission)}</span>
<br />
<span className="item-meta-info">{`${gettext('Share To:')} ${item.share_type == 'personal' ? item.user_name : item.group_name}`}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>
<DropdownItem className="mobile-menu-item" onClick={this.unshare}>{gettext('Unshare')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen && (
<PermSelect
repoID={item.repo_id}
isTextMode={true}
isEditIconShow={isOpIconShown}
isEditing={true}
autoFocus={true}
currentPermission={share_permission}
currentPerm={share_permission}
permissions={this.permissions}
onPermissionChanged={this.changePerm}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
)}
</td>
<td><a href="#" role="button" aria-label={gettext('Unshare')} className={`action-icon sf2-icon-x3 ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Unshare')} onClick={this.unshare}></a></td>
</tr>
);
const mobileItem = (
<Fragment>
<tr>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td>
<Link to={folderUrl}>{item.folder_name}</Link>
<span className="item-meta-info-highlighted">{Utils.sharePerms(share_permission)}</span>
<br />
<span className="item-meta-info">{`${gettext('Share To:')} ${item.share_type == 'personal' ? item.user_name : item.group_name}`}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>
<DropdownItem className="mobile-menu-item" onClick={this.unshare}>{gettext('Unshare')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen && (
<PermSelect
repoID={item.repo_id}
currentPerm={share_permission}
permissions={this.permissions}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
)}
</Fragment>
);
return this.props.isDesktop ? desktopItem : mobileItem;
</Fragment>
);
}
}
}

View File

@@ -224,88 +224,88 @@ class Item extends Component {
share_permission = share_permission.slice(7);
}
const desktopItem = (
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter}>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
<td>
{item.share_type == 'personal' ? <span title={item.contact_email}>{shareTo}</span> : shareTo}
</td>
<td>
{!isShowPermEditor && (
<div>
<span>{Utils.sharePerms(share_permission) || share_permission_name}</span>
{isOpIconShown && (
<a href="#"
role="button"
aria-label={gettext('Edit')}
title={gettext('Edit')}
className="sf3-font sf3-font-rename attr-action-icon"
onClick={this.onEditPermission}>
</a>
)}
</div>
)}
{isShowPermEditor && (
<SharePermissionEditor
if (this.props.isDesktop) {
return (
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onFocus={this.onMouseEnter}>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
<td>
{item.share_type == 'personal' ? <span title={item.contact_email}>{shareTo}</span> : shareTo}
</td>
<td>
{!isShowPermEditor && (
<div>
<span>{Utils.sharePerms(share_permission) || share_permission_name}</span>
{isOpIconShown && (
<a href="#"
role="button"
aria-label={gettext('Edit')}
title={gettext('Edit')}
className="sf3-font sf3-font-rename attr-action-icon"
onClick={this.onEditPermission}>
</a>
)}
</div>
)}
{isShowPermEditor && (
<SharePermissionEditor
repoID={item.repo_id}
isTextMode={true}
isEditing={true}
autoFocus={true}
isEditIconShow={this.state.isOpIconShown}
currentPermission={share_permission}
permissions={this.permissions}
onPermissionChanged={this.changePerm}
/>
)}
</td>
<td><a href="#" role="button" aria-label={gettext('Unshare')} className={`action-icon sf2-icon-x3 ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Unshare')} onClick={this.unshare}></a></td>
</tr>
);
} else {
return (
<Fragment>
<tr>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td>
<Link to={repoUrl}>{item.repo_name}</Link>
<span className="item-meta-info-highlighted">{Utils.sharePerms(share_permission)}</span>
<br />
<span className="item-meta-info">{`${gettext('Share To:')} ${shareTo}`}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>
<DropdownItem className="mobile-menu-item" onClick={this.unshare}>{gettext('Unshare')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen && (
<PermSelect
repoID={item.repo_id}
isTextMode={true}
isEditing={true}
autoFocus={true}
isEditIconShow={this.state.isOpIconShown}
currentPermission={share_permission}
currentPerm={share_permission}
permissions={this.permissions}
onPermissionChanged={this.changePerm}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
)}
</td>
<td><a href="#" role="button" aria-label={gettext('Unshare')} className={`action-icon sf2-icon-x3 ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Unshare')} onClick={this.unshare}></a></td>
</tr>
);
const mobileItem = (
<Fragment>
<tr>
<td><img src={iconUrl} title={iconTitle} alt={iconTitle} width="24" /></td>
<td>
<Link to={repoUrl}>{item.repo_name}</Link>
<span className="item-meta-info-highlighted">{Utils.sharePerms(share_permission)}</span>
<br />
<span className="item-meta-info">{`${gettext('Share To:')} ${shareTo}`}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>
<DropdownItem className="mobile-menu-item" onClick={this.unshare}>{gettext('Unshare')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen && (
<PermSelect
repoID={item.repo_id}
currentPerm={share_permission}
permissions={this.permissions}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
)}
</Fragment>
);
return this.props.isDesktop ? desktopItem : mobileItem;
</Fragment>
);
}
}
}

View File

@@ -267,88 +267,108 @@ class Item extends Component {
objUrl = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
}
const deletedTip = item.obj_id === '' ? <span style={{ color: 'red' }}>{gettext('(deleted)')}</span> : null;
const desktopItem = (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onFocus={this.handleMouseEnter}>
<td><img src={iconUrl} width="24" alt="" /></td>
<td>
{item.is_dir ?
<Link to={objUrl}>{item.obj_name}</Link> :
<a href={objUrl} target="_blank" rel="noreferrer">{item.obj_name}</a>
}
{deletedTip}
</td>
<td><Link to={`${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}/`}>{item.repo_name}</Link></td>
{isPro &&
<td>
<Selector
isDropdownToggleShown={isOpIconShown && !item.is_expired}
currentSelectedOption={currentSelectedPermOption}
options={this.permOptions}
selectOption={this.changePermission}
toggleItemFreezed={this.props.toggleItemFreezed}
/>
</td>
}
<td>{item.view_cnt}</td>
<td>{this.renderExpiration()}</td>
<td>
{!item.is_expired && <a href="#" className={`sf2-icon-link action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('View')} aria-label={gettext('View')} role="button" onClick={this.viewLink}></a>}
<a href="#" className={`sf3-font-delete1 sf3-font action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Remove')} aria-label={gettext('Remove')} role="button" onClick={this.removeLink}></a>
</td>
</tr>
);
const mobileItem = (
<Fragment>
<tr>
<td><img src={iconUrl} alt="" width="24" /></td>
<td>
{item.is_dir ?
<Link to={objUrl}>{item.obj_name}</Link> :
<a href={objUrl} target="_blank" rel="noreferrer">{item.obj_name}</a>
}
{isPro && <span className="item-meta-info-highlighted">{Utils.getShareLinkPermissionObject(currentPermission).text}</span>}
<br />
<span>{item.repo_name}</span><br />
<span className="item-meta-info">{gettext('Visits')}: {item.view_cnt}</span>
<span className="item-meta-info">{gettext('Expiration')}: {this.renderExpiration()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{(isPro && !item.is_expired) && <DropdownItem className="mobile-menu-item" onClick={this.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>}
{!item.is_expired && <DropdownItem className="mobile-menu-item" onClick={this.viewLink}>{gettext('View')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.removeLink}>{gettext('Remove')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen &&
<ShareLinkPermissionSelect
currentPerm={currentPermission}
permissions={permissionOptions}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
}
</Fragment>
);
return (
<Fragment>
{this.props.isDesktop ? desktopItem : mobileItem}
{this.props.isDesktop ?
<tr
className={this.state.highlight ? 'tr-highlight' : ''}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
onFocus={this.handleMouseEnter}
>
<td><img src={iconUrl} width="24" alt="" /></td>
<td>
{item.is_dir ?
<Link to={objUrl}>{item.obj_name}</Link> :
<a href={objUrl} target="_blank" rel="noreferrer">{item.obj_name}</a>
}
{item.obj_id === '' ? <span style={{ color: 'red' }}>{gettext('(deleted)')}</span> : null}
</td>
<td>
<Link to={`${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}/`}>{item.repo_name}</Link>
</td>
{isPro &&
<td>
<Selector
isDropdownToggleShown={isOpIconShown && !item.is_expired}
currentSelectedOption={currentSelectedPermOption}
options={this.permOptions}
selectOption={this.changePermission}
toggleItemFreezed={this.props.toggleItemFreezed}
/>
</td>
}
<td>{item.view_cnt}</td>
<td>{this.renderExpiration()}</td>
<td>
{!item.is_expired &&
<a
href="#"
className={`sf2-icon-link action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`}
title={gettext('View')}
aria-label={gettext('View')}
role="button"
onClick={this.viewLink}
>
</a>
}
<a
href="#"
className={`sf3-font-delete1 sf3-font action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`}
title={gettext('Remove')}
aria-label={gettext('Remove')}
role="button"
onClick={this.removeLink}
>
</a>
</td>
</tr>
:
<Fragment>
<tr>
<td><img src={iconUrl} alt="" width="24" /></td>
<td>
{item.is_dir ?
<Link to={objUrl}>{item.obj_name}</Link> :
<a href={objUrl} target="_blank" rel="noreferrer">{item.obj_name}</a>
}
{isPro && <span className="item-meta-info-highlighted">{Utils.getShareLinkPermissionObject(currentPermission).text}</span>}
<br />
<span>{item.repo_name}</span><br />
<span className="item-meta-info">{gettext('Visits')}: {item.view_cnt}</span>
<span className="item-meta-info">{gettext('Expiration')}: {this.renderExpiration()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{(isPro && !item.is_expired) && <DropdownItem className="mobile-menu-item" onClick={this.togglePermSelectDialog}>{gettext('Permission')}</DropdownItem>}
{!item.is_expired && <DropdownItem className="mobile-menu-item" onClick={this.viewLink}>{gettext('View')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.removeLink}>{gettext('Remove')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
{isPermSelectDialogOpen &&
<ShareLinkPermissionSelect
currentPerm={currentPermission}
permissions={permissionOptions}
changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog}
/>
}
</Fragment>
}
{isLinkDialogOpen &&
<ShareAdminLink
link={item.link}

View File

@@ -140,55 +140,54 @@ class Item extends Component {
const repoUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}`;
const objUrl = `${repoUrl}${Utils.encodePath(item.path)}`;
const deletedTip = item.obj_id === '' ? <span style={{ color: 'red' }}>{gettext('(deleted)')}</span> : null;
const desktopItem = (
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td><img src={iconUrl} alt="" width="24" /></td>
<td><Link to={objUrl}>{item.obj_name}</Link>{deletedTip}</td>
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
<td>{item.view_cnt}</td>
<td>{this.renderExpiration()}</td>
<td>
{!item.is_expired && <a href="#" className={`sf2-icon-link action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('View')} aria-label={gettext('View')} role="button" onClick={this.viewLink}></a>}
<a href="#" className={`sf3-font-delete1 sf3-font action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Remove')} aria-label={gettext('Remove')} role="button" onClick={this.removeLink}></a>
</td>
</tr>
);
const mobileItem = (
<tr>
<td><img src={iconUrl} alt="" width="24" /></td>
<td>
<Link to={objUrl}>{item.obj_name}</Link>
<br />
<span>{item.repo_name}</span><br />
<span className="item-meta-info">{gettext('Visits')}: {item.view_cnt}</span>
<span className="item-meta-info">{gettext('Expiration')}: {this.renderExpiration()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{!item.is_expired && <DropdownItem className="mobile-menu-item" onClick={this.viewLink}>{gettext('View')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.removeLink}>{gettext('Remove')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
);
return (
<Fragment>
{this.props.isDesktop ? desktopItem : mobileItem}
{this.props.isDesktop ?
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td><img src={iconUrl} alt="" width="24" /></td>
<td>
<Link to={objUrl}>{item.obj_name}</Link>
{item.obj_id === '' ? <span style={{ color: 'red' }}>{gettext('(deleted)')}</span> : null}
</td>
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
<td>{item.view_cnt}</td>
<td>{this.renderExpiration()}</td>
<td>
{!item.is_expired && <a href="#" className={`sf2-icon-link action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('View')} aria-label={gettext('View')} role="button" onClick={this.viewLink}></a>}
<a href="#" className={`sf3-font-delete1 sf3-font action-icon op-icon ${isOpIconShown ? '' : 'invisible'}`} title={gettext('Remove')} aria-label={gettext('Remove')} role="button" onClick={this.removeLink}></a>
</td>
</tr>
:
<tr>
<td><img src={iconUrl} alt="" width="24" /></td>
<td>
<Link to={objUrl}>{item.obj_name}</Link>
<br />
<span>{item.repo_name}</span><br />
<span className="item-meta-info">{gettext('Visits')}: {item.view_cnt}</span>
<span className="item-meta-info">{gettext('Expiration')}: {this.renderExpiration()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={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">
{!item.is_expired && <DropdownItem className="mobile-menu-item" onClick={this.viewLink}>{gettext('View')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.removeLink}>{gettext('Remove')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
}
{isLinkDialogOpen &&
<ShareAdminLink
link={item.link}

View File

@@ -282,172 +282,172 @@ class Item extends Component {
// at present, only repo shared with 'r', 'rw' can be monitored.(Fri Feb 10 16:24:49 CST 2023)
const enableMonitorRepo = isPro && (data.permission == 'r' || data.permission == 'rw');
const desktopItem = (
<Fragment>
{currentViewMode == 'list' ? (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td className="text-center">
<i
role="button"
title={this.state.isStarred ? gettext('Unstar') : gettext('Star')}
aria-label={this.state.isStarred ? gettext('Unstar') : gettext('Star')}
onClick={this.onToggleStarRepo}
className={`op-icon m-0 ${this.state.isStarred ? 'sf3-font-star' : 'sf3-font-star-empty'} sf3-font`}
>
</i>
</td>
<td><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td>
<td>
<Fragment>
<Link to={shareRepoUrl}>{data.repo_name}</Link>
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="ml-1 op-icon" />}
</Fragment>
</td>
<td>
{(isPro && data.is_admin) &&
<a href="#" className={shareIconClassName} title={gettext('Share')} role="button" aria-label={gettext('Share')} onClick={this.share}></a>
}
<a href="#" className={leaveShareIconClassName} title={gettext('Leave Share')} role="button" aria-label={gettext('Leave Share')} onClick={this.leaveShare}></a>
{enableMonitorRepo &&
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
role="button"
tabIndex="0"
className={`sf-dropdown-toggle sf3-font-more sf3-font ${iconVisibility}`}
title={gettext('More operations')}
aria-label={gettext('More operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<DropdownMenu>
<DropdownItem onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</td>
<td>{data.size}</td>
<td title={moment(data.last_modified).format('llll')}>{moment(data.last_modified).fromNow()}</td>
<td title={data.owner_contact_email}>{data.owner_name}</td>
</tr>
) : (
<div
className="library-grid-item px-3 d-flex justify-content-between align-items-center"
onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
onFocus={this.handleMouseOver}
>
<div className="d-flex align-items-center text-truncate">
<img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="36" className="mr-2" />
<Link to={shareRepoUrl} className="text-truncate library-name" title={data.repo_name}>{data.repo_name}</Link>
{isStarred &&
if (this.props.isDesktop) {
return (
<Fragment>
{currentViewMode == 'list' ? (
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td className="text-center">
<i
role="button"
title={gettext('Unstar')}
aria-label={gettext('Unstar')}
title={this.state.isStarred ? gettext('Unstar') : gettext('Star')}
aria-label={this.state.isStarred ? gettext('Unstar') : gettext('Star')}
onClick={this.onToggleStarRepo}
className='op-icon library-grid-item-icon sf3-font-star sf3-font'
className={`op-icon m-0 ${this.state.isStarred ? 'sf3-font-star' : 'sf3-font-star-empty'} sf3-font`}
>
</i>
}
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="op-icon library-grid-item-icon" />}
</div>
</td>
<td><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td>
<td>
<Fragment>
<Link to={shareRepoUrl}>{data.repo_name}</Link>
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="ml-1 op-icon" />}
</Fragment>
</td>
<td>
{(isPro && data.is_admin) &&
<a href="#" className={shareIconClassName} title={gettext('Share')} role="button" aria-label={gettext('Share')} onClick={this.share}></a>
}
<a href="#" className={leaveShareIconClassName} title={gettext('Leave Share')} role="button" aria-label={gettext('Leave Share')} onClick={this.leaveShare}></a>
{enableMonitorRepo &&
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
role="button"
tabIndex="0"
className={`sf-dropdown-toggle sf3-font-more sf3-font ${iconVisibility}`}
title={gettext('More operations')}
aria-label={gettext('More operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<DropdownMenu>
<DropdownItem onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</td>
<td>{data.size}</td>
<td title={moment(data.last_modified).format('llll')}>{moment(data.last_modified).fromNow()}</td>
<td title={data.owner_contact_email}>{data.owner_name}</td>
</tr>
) : (
<div
className="library-grid-item px-3 d-flex justify-content-between align-items-center"
onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
onFocus={this.handleMouseOver}
>
<div className="d-flex align-items-center text-truncate">
<img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="36" className="mr-2" />
<Link to={shareRepoUrl} className="text-truncate library-name" title={data.repo_name}>{data.repo_name}</Link>
{isStarred &&
<i
role="button"
title={gettext('Unstar')}
aria-label={gettext('Unstar')}
onClick={this.onToggleStarRepo}
className='op-icon library-grid-item-icon sf3-font-star sf3-font'
>
</i>
}
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="op-icon library-grid-item-icon" />}
</div>
<div className="flex-shrink-0">
{(isPro && data.is_admin) &&
<a href="#" className={shareIconClassName} title={gettext('Share')} role="button" aria-label={gettext('Share')} onClick={this.share}></a>
}
<a href="#" className={leaveShareIconClassName} title={gettext('Leave Share')} role="button" aria-label={gettext('Leave Share')} onClick={this.leaveShare}></a>
{enableMonitorRepo &&
<div className="flex-shrink-0">
{(isPro && data.is_admin) &&
<a href="#" className={shareIconClassName} title={gettext('Share')} role="button" aria-label={gettext('Share')} onClick={this.share}></a>
}
<a href="#" className={leaveShareIconClassName} title={gettext('Leave Share')} role="button" aria-label={gettext('Leave Share')} onClick={this.leaveShare}></a>
{enableMonitorRepo &&
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
role="button"
tabIndex="0"
className={`sf-dropdown-toggle sf3-font-more sf3-font ${iconVisibility}`}
title={gettext('More operations')}
aria-label={gettext('More operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<DropdownMenu>
<DropdownItem onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</div>
</div>
)}
{this.state.isShowSharedDialog && (
<ModalPotal>
<ShareDialog
itemType={'library'}
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
)}
</Fragment>
);
} else {
return (
<Fragment>
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
<td onClick={this.visitRepo}><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td>
<td onClick={this.visitRepo}>
<Link to={shareRepoUrl}>{data.repo_name}</Link>
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="ml-1 op-icon" />}
<br />
<span className="item-meta-info" title={data.owner_contact_email}>{data.owner_name}</span>
<span className="item-meta-info">{data.size}</span>
<span className="item-meta-info" title={moment(data.last_modified).format('llll')}>{moment(data.last_modified).fromNow()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
role="button"
tabIndex="0"
className={`sf-dropdown-toggle sf3-font-more sf3-font ${iconVisibility}`}
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical ml-0"
title={gettext('More operations')}
aria-label={gettext('More operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<DropdownMenu>
<DropdownItem onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</div>
</div>
)}
{this.state.isShowSharedDialog && (
<ModalPotal>
<ShareDialog
itemType={'library'}
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
)}
</Fragment>
);
const mobileItem = (
<Fragment>
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
<td onClick={this.visitRepo}><img src={data.icon_url} title={data.icon_title} alt={data.icon_title} width="24" /></td>
<td onClick={this.visitRepo}>
<Link to={shareRepoUrl}>{data.repo_name}</Link>
{data.monitored && <RepoMonitoredIcon repoID={data.repo_id} className="ml-1 op-icon" />}
<br />
<span className="item-meta-info" title={data.owner_contact_email}>{data.owner_name}</span>
<span className="item-meta-info">{data.size}</span>
<span className="item-meta-info" title={moment(data.last_modified).format('llll')}>{moment(data.last_modified).fromNow()}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical 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.onToggleStarRepo}>{this.state.isStarred ? gettext('Unstar') : gettext('Star')}</DropdownItem>
{(isPro && data.is_admin) && <DropdownItem className="mobile-menu-item" onClick={this.share}>{gettext('Share')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.leaveShare}>{gettext('Leave Share')}</DropdownItem>
{enableMonitorRepo && <DropdownItem className="mobile-menu-item" onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>}
<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.onToggleStarRepo}>{this.state.isStarred ? gettext('Unstar') : gettext('Star')}</DropdownItem>
{(isPro && data.is_admin) && <DropdownItem className="mobile-menu-item" onClick={this.share}>{gettext('Share')}</DropdownItem>}
<DropdownItem className="mobile-menu-item" onClick={this.leaveShare}>{gettext('Leave Share')}</DropdownItem>
{enableMonitorRepo && <DropdownItem className="mobile-menu-item" onClick={data.monitored ? this.unwatchFileChanges : this.watchFileChanges}>{data.monitored ? gettext('Unwatch File Changes') : gettext('Watch File Changes')}</DropdownItem>}
</div>
</div>
</div>
</Dropdown>
</td>
</tr>
{this.state.isShowSharedDialog && (
<ModalPotal>
<ShareDialog
itemType={'library'}
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
)}
</Fragment>
);
return this.props.isDesktop ? desktopItem : mobileItem;
</Dropdown>
</td>
</tr>
{this.state.isShowSharedDialog && (
<ModalPotal>
<ShareDialog
itemType={'library'}
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
)}
</Fragment>
);
}
}
}

View File

@@ -19,42 +19,39 @@ class Content extends Component {
return <Loading />;
} else if (errorMsg) {
return <p className="error text-center">{errorMsg}</p>;
} else {
const emptyTip = (
} else if (items.length === 0) {
return (
<EmptyTip>
<h2>{gettext('No favorites')}</h2>
<p>{gettext('You have not added any libraries, folders or files to your favorites yet. A favorite gives you quick access to your most frequently used objects. You can add a library, folder or file to your favorites by clicking the star to the left of its name.')}</p>
</EmptyTip>
);
const desktopThead = (
<thead>
<tr>
<th width="4%"></th>
<th width="40%">{gettext('Name')}</th>
<th width="32%">{gettext('Library')}</th>
<th width="18%">{gettext('Last Update')}</th>
<th width="6%"></th>
</tr>
</thead>
);
const mobileThead = (
<thead>
<tr>
<th width="12%"></th>
<th width="80%"></th>
<th width="8%"></th>
</tr>
</thead>
);
} else {
const isDesktop = Utils.isDesktop();
return items.length ? (
return (
<table className={`table-hover ${isDesktop ? '' : 'table-thead-hidden'}`}>
{isDesktop ? desktopThead : mobileThead}
<TableBody items={items} />
{isDesktop ?
<thead>
<tr>
<th width="4%"></th>
<th width="40%">{gettext('Name')}</th>
<th width="32%">{gettext('Library')}</th>
<th width="18%">{gettext('Last Update')}</th>
<th width="6%"></th>
</tr>
</thead>
:
<thead>
<tr>
<th width="12%"></th>
<th width="80%"></th>
<th width="8%"></th>
</tr>
</thead>
}
<TableBody items={items} isDesktop={isDesktop} />
</table>
) : emptyTip;
);
}
}
}
@@ -133,7 +130,7 @@ class TableBody extends Component {
item.mtime_relative = moment(item.mtime).fromNow();
return <Item key={index} data={item} />;
return <Item key={index} data={item} isDesktop={this.props.isDesktop} />;
}, this);
return (
@@ -145,6 +142,7 @@ class TableBody extends Component {
TableBody.propTypes = {
data: PropTypes.object,
items: PropTypes.array,
isDesktop: PropTypes.bool.isRequired,
};
class Item extends Component {
@@ -197,18 +195,54 @@ class Item extends Component {
}
};
render() {
if (this.state.unstarred) {
return null;
}
renderMobile = () => {
const data = this.props.data;
const linkUrl = data.dirent_view_url;
const mobileItem = (
<tr>
<td className="text-center" onClick={this.visitItem}>
{
data.thumbnail_url ?
<img className="thumbnail" src={data.thumbnail_url} alt="" /> :
<img src={data.item_icon_url} alt={gettext('icon')} width="24" />
}
</td>
<td onClick={this.visitItem}>
{data.is_dir ?
<Link to={linkUrl}>{data.obj_name}</Link> :
<a className="normal" href={data.dirent_view_url} target="_blank" rel="noreferrer">{data.obj_name}</a>
}
<br />
<span className="item-meta-info">{data.repo_name}</span>
<span className="item-meta-info" dangerouslySetInnerHTML={{ __html: data.mtime_relative }}></span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical 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.unstar}>{gettext('Unstar')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
);
return mobileItem;
};
renderDesktop = () => {
const data = this.props.data;
let opClasses = 'sf2-icon-x3 unstar action-icon';
opClasses += this.state.showOpIcon ? '' : ' invisible';
const linkUrl = data.dirent_view_url;
const desktopItem = (
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
<td className="text-center">
@@ -238,52 +272,21 @@ class Item extends Component {
</td>
</tr>
);
return desktopItem;
};
const mobileItem = (
<tr>
<td className="text-center" onClick={this.visitItem}>
{
data.thumbnail_url ?
<img className="thumbnail" src={data.thumbnail_url} alt="" /> :
<img src={data.item_icon_url} alt={gettext('icon')} width="24" />
}
</td>
<td onClick={this.visitItem}>
{ data.is_dir ?
<Link to={linkUrl}>{data.obj_name}</Link> :
<a className="normal" href={data.dirent_view_url} target="_blank" rel="noreferrer">{data.obj_name}</a>
}
<br />
<span className="item-meta-info">{data.repo_name}</span>
<span className="item-meta-info" dangerouslySetInnerHTML={{ __html: data.mtime_relative }}></span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf3-font sf3-font-more-vertical 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.unstar}>{gettext('Unstar')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
);
return Utils.isDesktop() ? desktopItem : mobileItem;
render() {
if (this.state.unstarred) {
return null;
}
return this.props.isDesktop ? this.renderDesktop() : this.renderMobile();
}
}
Item.propTypes = {
data: PropTypes.object,
items: PropTypes.array,
isDesktop: PropTypes.bool.isRequired,
};
class Starred extends Component {