Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: admin share ui #7265

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions frontend/src/components/common/fixed-width-table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useState, useEffect, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';

const FixedWidthTable = ({ className, headers, theadOptions = {}, children }) => {
const [containerWidth, setContainerWidth] = useState(0);
const fixedWidth = useMemo(() => headers.reduce((pre, cur) => cur.isFixed ? cur.width + pre : pre, 0), [headers]);

const containerRef = useRef(null);

useEffect(() => {
const container = containerRef.current;
const handleResize = () => {
if (!container) return;
setContainerWidth(container.offsetWidth);
};
const resizeObserver = new ResizeObserver(handleResize);
container && resizeObserver.observe(container);

return () => {
container && resizeObserver.unobserve(container);
};
}, []);

return (
<table ref={containerRef} className={className}>
<thead { ...theadOptions }>
<tr>
{headers.map((header, index) => {
const { width, isFixed, children: thChildren, className } = header;
const validWidth = isFixed ? width : (containerWidth - fixedWidth) * width;
return (<th key={index} style={{ width: validWidth }} className={className}>{thChildren}</th>);
})}
</tr>
</thead>
<tbody>
{children}
</tbody>
</table>
);
};

FixedWidthTable.propTypes = {
className: PropTypes.string,
headers: PropTypes.array,
theadOptions: PropTypes.object,
children: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.number]),
};

export default FixedWidthTable;
52 changes: 16 additions & 36 deletions frontend/src/components/dialog/my-deleted-repos-dialog/repos.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import RepoItem from './repo-item';
import { gettext, trashReposExpireDays } from '../../../utils/constants';
import FixedWidthTable from '../../common/fixed-width-table';

const Repos = ({ repos, filterRestoredRepo }) => {
const [containerWidth, setContainerWidth] = useState(0);

const containerRef = useRef(null);

useEffect(() => {
const container = containerRef.current;
const handleResize = () => {
if (!container) return;
setContainerWidth(container.offsetWidth);
};
const resizeObserver = new ResizeObserver(handleResize);
container && resizeObserver.observe(container);

return () => {
container && resizeObserver.unobserve(container);
};
}, []);
const headers = useMemo(() => [
{ width: 40, isFixed: true, className: 'pl-2 pr-2' },
{ width: 0.5, isFixed: false, children: gettext('Name') },
{ width: 0.3, isFixed: false, children: gettext('Deleted Time') },
{ width: 0.2, isFixed: false },
], []);

return (
<div ref={containerRef}>
<div>
<p className="tip my-deleted-repos-tip">{gettext('Tip: libraries deleted {placeholder} days ago will be cleaned automatically.').replace('{placeholder}', trashReposExpireDays)}</p>
<table>
<thead>
<tr>
<th style={{ width: 40 }} className="pl-2 pr-2">{/* img*/}</th>
<th style={{ width: (containerWidth - 40) * 0.5 }}>{gettext('Name')}</th>
<th style={{ width: (containerWidth - 40) * 0.3 }}>{gettext('Deleted Time')}</th>
<th style={{ width: (containerWidth - 40) * 0.2 }}></th>
</tr>
</thead>
<tbody>
{repos.map((repo) => {
return (
<RepoItem key={repo.repo_id} repo={repo} filterRestoredRepo={filterRestoredRepo} />
);
})}
</tbody>
</table>
<FixedWidthTable headers={headers} >
{repos.map((repo) => {
return (
<RepoItem key={repo.repo_id} repo={repo} filterRestoredRepo={filterRestoredRepo} />
);
})}
</FixedWidthTable>
</div>
);
};
Expand Down
56 changes: 18 additions & 38 deletions frontend/src/components/dialog/trash-dialog/table/index.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../../../utils/constants';
import FolderRecords from './folder-records';
import FileRecords from './file-records';
import FixedWidthTable from '../../../common/fixed-width-table';

const Table = ({ repoID, renderFolder, data }) => {
const [containerWidth, setContainerWidth] = useState(0);

const containerRef = useRef(null);

useEffect(() => {
const container = containerRef.current;
const handleResize = () => {
if (!container) return;
setContainerWidth(container.offsetWidth);
};
const resizeObserver = new ResizeObserver(handleResize);
container && resizeObserver.observe(container);

return () => {
container && resizeObserver.unobserve(container);
};
}, []);
const headers = useMemo(() => [
{ isFixed: true, width: 40, className: 'pl-2 pr-2' },
{ isFixed: false, width: 0.25, children: gettext('Name') },
{ isFixed: false, width: 0.4, children: gettext('Original path') },
{ isFixed: false, width: 0.12, children: gettext('Delete Time') },
{ isFixed: false, width: 0.13, children: gettext('Size') },
{ isFixed: false, width: 0.1, children: gettext('Size') },
], []);

const { items, showFolder, commitID, baseDir, folderPath, folderItems } = data;

return (
<div className="table-container p-0" ref={containerRef}>
<table className="table-hover">
<thead>
<tr>
<th style={{ width: 40 }} className="pl-2 pr-2">{/* icon */}</th>
<th style={{ width: (containerWidth - 40) * 0.25 }}>{gettext('Name')}</th>
<th style={{ width: (containerWidth - 40) * 0.4 }}>{gettext('Original path')}</th>
<th style={{ width: (containerWidth - 40) * 0.12 }}>{gettext('Delete Time')}</th>
<th style={{ width: (containerWidth - 40) * 0.13 }}>{gettext('Size')}</th>
<th style={{ width: (containerWidth - 40) * 0.1 }}>{/* op */}</th>
</tr>
</thead>
<tbody>
{showFolder ? (
<FolderRecords records={folderItems} repoID={repoID} commitID={commitID} baseDir={baseDir} folderPath={folderPath} renderFolder={renderFolder} />
) : (
<FileRecords records={items} repoID={repoID} renderFolder={renderFolder} />
)}
</tbody>
</table>
<div className="table-container p-0">
<FixedWidthTable className="table-hover" headers={headers}>
{showFolder ? (
<FolderRecords records={folderItems} repoID={repoID} commitID={commitID} baseDir={baseDir} folderPath={folderPath} renderFolder={renderFolder} />
) : (
<FileRecords records={items} repoID={repoID} renderFolder={renderFolder} />
)}
</FixedWidthTable>
</div>
);
};
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/dirent-detail/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import { METADATA_MODE, TAGS_MODE } from '../dir-view-mode/constants';

const Detail = React.memo(({ repoID, path, currentMode, dirent, currentRepoInfo, repoTags, fileTags, onClose, onFileTagChanged }) => {
const isView = useMemo(() => currentMode === METADATA_MODE || path.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES), [currentMode, path]);
const isTag = useMemo(() => currentMode === TAGS_MODE || path.startsWith('/' + PRIVATE_FILE_TYPE.TAGS_PROPERTIES), [currentMode, path]);

useEffect(() => {
if (isView) return;
if (isTag) return;

// init context
const context = new MetadataContext();
Expand All @@ -24,9 +26,9 @@ const Detail = React.memo(({ repoID, path, currentMode, dirent, currentRepoInfo,
delete window['sfMetadataContext'];
}
};
}, [repoID, currentRepoInfo, isView]);
}, [repoID, currentRepoInfo, isView, isTag]);

if (currentMode === TAGS_MODE) return null;
if (isTag) return null;

if (isView) {
const viewId = path.split('/').pop();
Expand Down
101 changes: 50 additions & 51 deletions frontend/src/components/dirent-list-view/dirent-list-view.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { siteRoot, gettext, username, enableSeadoc, thumbnailSizeForOriginal, thumbnailDefaultSize, fileServerRoot } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import TextTranslation from '../../utils/text-translation';
Expand All @@ -20,6 +21,7 @@ import { EVENT_BUS_TYPE } from '../common/event-bus-type';
import EmptyTip from '../empty-tip';
import imageAPI from '../../utils/image-api';
import { seafileAPI } from '../../utils/seafile-api';
import FixedWidthTable from '../common/fixed-width-table';

const propTypes = {
path: PropTypes.string.isRequired,
Expand Down Expand Up @@ -80,7 +82,6 @@ class DirentListView extends React.Component {
activeDirent: null,
isListDropTipShow: false,
isShowDirentsDraggablePreview: false,
containerWidth: 0,
};

this.enteredCounter = 0; // Determine whether to enter the child element to avoid dragging bubbling bugs。
Expand All @@ -101,20 +102,12 @@ class DirentListView extends React.Component {
const { modify } = customPermission.permission;
this.canDrop = modify;
}

this.containerRef = null;
}

componentDidMount() {
this.unsubscribeEvent = this.props.eventBus.subscribe(EVENT_BUS_TYPE.RESTORE_IMAGE, this.recalculateImageItems);
this.resizeObserver = new ResizeObserver(this.handleResize);
this.containerRef && this.resizeObserver.observe(this.containerRef);
}

handleResize = () => {
this.setState({ containerWidth: this.containerRef.offsetWidth - 32 });
};

recalculateImageItems = () => {
if (!this.state.isImagePopupOpen) return;
let imageItems = this.props.direntList
Expand All @@ -129,7 +122,6 @@ class DirentListView extends React.Component {

componentWillUnmount() {
this.unsubscribeEvent();
this.containerRef && this.resizeObserver.unobserve(this.containerRef);
}

freezeItem = () => {
Expand Down Expand Up @@ -687,18 +679,56 @@ class DirentListView extends React.Component {
});
};

render() {
getHeaders = (isDesktop) => {
const { direntList, sortBy, sortOrder } = this.props;
const { containerWidth } = this.state;
if (!isDesktop) {
return [
{ isFixed: false, width: 0.12 },
{ isFixed: false, width: 0.8 },
{ isFixed: false, width: 0.08 },
];
}

// sort
const sortByName = sortBy == 'name';
const sortByTime = sortBy == 'time';
const sortBySize = sortBy == 'size';
const sortIcon = sortOrder == 'asc' ? <span className="sf3-font sf3-font-down rotate-180 d-inline-block"></span> : <span className="sf3-font sf3-font-down"></span>;
return [
{ isFixed: true, width: 31, className: 'pl10 pr-2', children: (
<input
type="checkbox"
className="vam"
onChange={this.props.onAllItemSelected}
checked={this.props.isAllItemSelected}
title={this.props.isAllItemSelected ? gettext('Unselect all items') : gettext('Select all items')}
aria-label={this.props.isAllItemSelected ? gettext('Unselect all items') : gettext('Select all items')}
disabled={direntList.length === 0}
/>
) }, {
isFixed: true, width: 32, className: 'pl-2 pr-2', // star
}, {
isFixed: true, width: 40, className: 'pl-2 pr-2', // icon
}, {
isFixed: false, width: 0.5, children: (<a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a>),
}, {
isFixed: false, width: 0.06, // tag
}, {
isFixed: false, width: 0.18, // operation
}, {
isFixed: false, width: 0.11, children: (<a className="d-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBySize && sortIcon}</a>)
}, {
isFixed: false, width: 0.15, children: (<a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a>)
}
];
};

render() {
const { direntList } = this.props;

const isDesktop = Utils.isDesktop();
const repoEncrypted = this.props.currentRepoInfo.encrypted;
const headers = this.getHeaders(isDesktop);

return (
<div
Expand All @@ -710,43 +740,13 @@ class DirentListView extends React.Component {
onDragOver={this.onTableDragOver}
onDragLeave={this.onTableDragLeave}
onDrop={this.tableDrop}
ref={ref => this.containerRef = ref}
>
{direntList.length > 0 &&
<table className={`table-hover ${isDesktop ? '' : 'table-thead-hidden'}`}>
{isDesktop ? (
<thead onMouseDown={this.onThreadMouseDown} onContextMenu={this.onThreadContextMenu}>
<tr>
<th style={{ width: 31 }} className="pl10 pr-2">
<input
type="checkbox"
className="vam"
onChange={this.props.onAllItemSelected}
checked={this.props.isAllItemSelected}
title={this.props.isAllItemSelected ? gettext('Unselect all items') : gettext('Select all items')}
aria-label={this.props.isAllItemSelected ? gettext('Unselect all items') : gettext('Select all items')}
disabled={direntList.length === 0}
/>
</th>
<th style={{ width: 32 }} className="pl-2 pr-2">{/* star */}</th>
<th style={{ width: 40 }} className="pl-2 pr-2">{/* icon */}</th>
<th style={{ width: (containerWidth - 103) * 0.5 }}><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
<th style={{ width: (containerWidth - 103) * 0.06 }}>{/* tag */}</th>
<th style={{ width: (containerWidth - 103) * 0.18 }}>{/* operation */}</th>
<th style={{ width: (containerWidth - 103) * 0.11 }}><a className="d-block table-sort-op" href="#" onClick={this.sortBySize}>{gettext('Size')} {sortBySize && sortIcon}</a></th>
<th style={{ width: (containerWidth - 103) * 0.15 }}><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>
</tr>
</thead>
) : (
<thead>
<tr>
<th width="12%"></th>
<th width="80%"></th>
<th width="8%"></th>
</tr>
</thead>
)}
<tbody>
{direntList.length > 0 && (
<FixedWidthTable
className={classnames('table-hover', { 'table-thead-hidden': !isDesktop })}
headers={headers}
theadOptions={isDesktop ? { onMouseDown: this.onThreadMouseDown, onContextMenu: this.onThreadContextMenu } : {}}
>
{direntList.map((dirent, index) => {
return (
<DirentListItem
Expand Down Expand Up @@ -790,9 +790,8 @@ class DirentListView extends React.Component {
/>
);
})}
</tbody>
</table>
}
</FixedWidthTable>
)}
{direntList.length === 0 &&
<EmptyTip text={gettext('No file')}/>
}
Expand Down
Loading
Loading