mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-08 18:30:53 +00:00
Feature/gallery info side panel (#6876)
* gallery info side panel * clean up code * optimize code * optimize code * feat: optimize code * feat: optimize code --------- Co-authored-by: zhouwenxuan <aries@Mac.local> Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
@@ -10,6 +10,7 @@ import ViewModes from '../../components/view-modes';
|
|||||||
import ReposSortMenu from '../../components/repos-sort-menu';
|
import ReposSortMenu from '../../components/repos-sort-menu';
|
||||||
import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
||||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
|
import { DIRENT_DETAIL_MODE } from '../dir-view-mode/constants';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoID: PropTypes.string.isRequired,
|
repoID: PropTypes.string.isRequired,
|
||||||
@@ -97,10 +98,14 @@ class DirTool extends React.Component {
|
|||||||
this.props.sortItems(sortBy, sortOrder);
|
this.props.sortItems(sortBy, sortOrder);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
showDirentDetail = () => {
|
||||||
|
this.props.switchViewMode(DIRENT_DETAIL_MODE);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const menuItems = this.getMenu();
|
const menuItems = this.getMenu();
|
||||||
const { isDropdownMenuOpen } = this.state;
|
const { isDropdownMenuOpen } = this.state;
|
||||||
const { repoID, currentMode, currentPath, sortBy, sortOrder, viewId } = this.props;
|
const { repoID, currentMode, currentPath, sortBy, sortOrder, viewId, isCustomPermission } = this.props;
|
||||||
const propertiesText = TextTranslation.PROPERTIES.value;
|
const propertiesText = TextTranslation.PROPERTIES.value;
|
||||||
const isFileExtended = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/');
|
const isFileExtended = currentPath.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/');
|
||||||
|
|
||||||
@@ -114,7 +119,7 @@ class DirTool extends React.Component {
|
|||||||
if (isFileExtended) {
|
if (isFileExtended) {
|
||||||
return (
|
return (
|
||||||
<div className="dir-tool">
|
<div className="dir-tool">
|
||||||
<MetadataViewToolBar viewId={viewId} />
|
<MetadataViewToolBar viewId={viewId} isCustomPermission={isCustomPermission} showDetail={this.showDirentDetail} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -124,8 +129,8 @@ class DirTool extends React.Component {
|
|||||||
<div className="dir-tool d-flex">
|
<div className="dir-tool d-flex">
|
||||||
<ViewModes currentViewMode={currentMode} switchViewMode={this.props.switchViewMode} />
|
<ViewModes currentViewMode={currentMode} switchViewMode={this.props.switchViewMode} />
|
||||||
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
|
<ReposSortMenu sortOptions={sortOptions} onSelectSortOption={this.onSelectSortOption}/>
|
||||||
{(!this.props.isCustomPermission) &&
|
{(!isCustomPermission) &&
|
||||||
<div className="cur-view-path-btn" onClick={() => this.props.switchViewMode('detail')}>
|
<div className="cur-view-path-btn" onClick={this.showDirentDetail}>
|
||||||
<span className="sf3-font sf3-font-info" aria-label={propertiesText} title={propertiesText}></span>
|
<span className="sf3-font sf3-font-info" aria-label={propertiesText} title={propertiesText}></span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const LIST_MODE = 'list';
|
export const LIST_MODE = 'list';
|
||||||
export const GRID_MODE = 'grid';
|
export const GRID_MODE = 'grid';
|
||||||
|
export const DIRENT_DETAIL_MODE = 'detail';
|
||||||
export const METADATA_MODE = 'metadata';
|
export const METADATA_MODE = 'metadata';
|
||||||
export const FACE_RECOGNITION_MODE = 'person_image';
|
export const FACE_RECOGNITION_MODE = 'person_image';
|
||||||
|
@@ -80,6 +80,7 @@ const propTypes = {
|
|||||||
fullDirentList: PropTypes.array,
|
fullDirentList: PropTypes.array,
|
||||||
onItemsScroll: PropTypes.func.isRequired,
|
onItemsScroll: PropTypes.func.isRequired,
|
||||||
eventBus: PropTypes.object,
|
eventBus: PropTypes.object,
|
||||||
|
updateCurrentDirent: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirColumnView extends React.Component {
|
class DirColumnView extends React.Component {
|
||||||
@@ -202,6 +203,7 @@ class DirColumnView extends React.Component {
|
|||||||
viewID={this.props.viewId}
|
viewID={this.props.viewId}
|
||||||
deleteFilesCallback={this.props.deleteFilesCallback}
|
deleteFilesCallback={this.props.deleteFilesCallback}
|
||||||
renameFileCallback={this.props.renameFileCallback}
|
renameFileCallback={this.props.renameFileCallback}
|
||||||
|
updateCurrentDirent={this.props.updateCurrentDirent}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{currentMode === FACE_RECOGNITION_MODE &&
|
{currentMode === FACE_RECOGNITION_MODE &&
|
||||||
|
@@ -2,12 +2,16 @@ import React, { useEffect } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import LibDetail from './lib-details';
|
import LibDetail from './lib-details';
|
||||||
import DirentDetail from './dirent-details';
|
import DirentDetail from './dirent-details';
|
||||||
|
import ViewDetails from '../../metadata/components/view-details';
|
||||||
import ObjectUtils from '../../metadata/utils/object-utils';
|
import ObjectUtils from '../../metadata/utils/object-utils';
|
||||||
import { MetadataContext } from '../../metadata';
|
import { MetadataContext } from '../../metadata';
|
||||||
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
|
|
||||||
const DetailContainer = React.memo(({ repoID, path, dirent, currentRepoInfo, repoTags, fileTags, onClose, onFileTagChanged }) => {
|
const DetailContainer = React.memo(({ repoID, path, dirent, currentRepoInfo, repoTags, fileTags, onClose, onFileTagChanged }) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (path.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES)) return;
|
||||||
|
|
||||||
// init context
|
// init context
|
||||||
const context = new MetadataContext();
|
const context = new MetadataContext();
|
||||||
window.sfMetadataContext = context;
|
window.sfMetadataContext = context;
|
||||||
@@ -16,7 +20,13 @@ const DetailContainer = React.memo(({ repoID, path, dirent, currentRepoInfo, rep
|
|||||||
window.sfMetadataContext.destroy();
|
window.sfMetadataContext.destroy();
|
||||||
delete window['sfMetadataContext'];
|
delete window['sfMetadataContext'];
|
||||||
};
|
};
|
||||||
}, [repoID, currentRepoInfo]);
|
}, [repoID, currentRepoInfo, path]);
|
||||||
|
|
||||||
|
if (path.startsWith('/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES)) {
|
||||||
|
const viewId = path.split('/').pop();
|
||||||
|
if (!dirent) return (<ViewDetails viewId={viewId} onClose={onClose} />);
|
||||||
|
path = dirent.path;
|
||||||
|
}
|
||||||
|
|
||||||
if (path === '/' && !dirent) {
|
if (path === '/' && !dirent) {
|
||||||
return (
|
return (
|
||||||
|
@@ -16,6 +16,15 @@
|
|||||||
width: 0; /* prevent strut flex layout */
|
width: 0; /* prevent strut flex layout */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detail-header .detail-title .detail-header-icon-container {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.detail-header .detail-title .name {
|
.detail-header .detail-title .name {
|
||||||
margin: 0 0.5rem 0 6px;
|
margin: 0 0.5rem 0 6px;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
|
@@ -4,12 +4,14 @@ import Icon from '../../../icon';
|
|||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const Header = ({ title, icon, onClose, component = {} }) => {
|
const Header = ({ title, icon, iconSize = 32, onClose, component = {} }) => {
|
||||||
const { closeIcon } = component;
|
const { closeIcon } = component;
|
||||||
return (
|
return (
|
||||||
<div className="detail-header">
|
<div className="detail-header">
|
||||||
<div className="detail-title dirent-title">
|
<div className="detail-title dirent-title">
|
||||||
<img src={icon} width="32" height="32" alt="" />
|
<div className="detail-header-icon-container">
|
||||||
|
<img src={icon} width={iconSize} height={iconSize} alt="" />
|
||||||
|
</div>
|
||||||
<span className="name ellipsis" title={title}>{title}</span>
|
<span className="name ellipsis" title={title}>{title}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="detail-control" onClick={onClose}>
|
<div className="detail-control" onClick={onClose}>
|
||||||
@@ -22,6 +24,7 @@ const Header = ({ title, icon, onClose, component = {} }) => {
|
|||||||
Header.propTypes = {
|
Header.propTypes = {
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
icon: PropTypes.string.isRequired,
|
icon: PropTypes.string.isRequired,
|
||||||
|
iconSize: PropTypes.number,
|
||||||
component: PropTypes.object,
|
component: PropTypes.object,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
@@ -42,3 +42,8 @@
|
|||||||
.detail-body .sf-metadata-property-detail-tags.tags-empty {
|
.detail-body .sf-metadata-property-detail-tags.tags-empty {
|
||||||
padding: 6.5px 6px;;
|
padding: 6.5px 6px;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detail-body .detail-content.detail-content-empty {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
3
frontend/src/metadata/components/view-details/index.css
Normal file
3
frontend/src/metadata/components/view-details/index.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.sf-metadata-view-detail .detail-content-empty .empty-tip {
|
||||||
|
margin: 0;
|
||||||
|
}
|
39
frontend/src/metadata/components/view-details/index.js
Normal file
39
frontend/src/metadata/components/view-details/index.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext, mediaUrl } from '../../../utils/constants';
|
||||||
|
import { Detail, Header, Body } from '../../../components/dirent-detail/detail';
|
||||||
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
|
import { useMetadata } from '../../hooks';
|
||||||
|
import { VIEW_TYPE } from '../../constants';
|
||||||
|
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
const ViewDetails = ({ viewId, onClose }) => {
|
||||||
|
const { viewsMap } = useMetadata();
|
||||||
|
|
||||||
|
const view = useMemo(() => viewsMap[viewId], [viewId, viewsMap]);
|
||||||
|
const icon = useMemo(() => {
|
||||||
|
const type = view.type;
|
||||||
|
if (type === VIEW_TYPE.GALLERY) return `${mediaUrl}favicons/gallery.png`;
|
||||||
|
if (type === VIEW_TYPE.TABLE) return `${mediaUrl}favicons/table.png`;
|
||||||
|
return `${mediaUrl}img/file/256/file.png`;
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Detail className="sf-metadata-view-detail">
|
||||||
|
<Header title={view.name} icon={icon} iconSize={28} onClose={onClose} />
|
||||||
|
<Body>
|
||||||
|
<div className="detail-content detail-content-empty">
|
||||||
|
<EmptyTip text={gettext('There is no information to display.')} />
|
||||||
|
</div>
|
||||||
|
</Body>
|
||||||
|
</Detail>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewDetails.propTypes = {
|
||||||
|
viewId: PropTypes.string.isRequired,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ViewDetails;
|
@@ -0,0 +1,71 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { GalleryGroupBySetter, GallerySliderSetter, FilterSetter, SortSetter } from '../../data-process-setter';
|
||||||
|
import { PRIVATE_COLUMN_KEY } from '../../../constants';
|
||||||
|
import { gettext } from '../../../../utils/constants';
|
||||||
|
|
||||||
|
const GalleryViewToolbar = ({
|
||||||
|
readOnly, isCustomPermission, view, collaborators,
|
||||||
|
modifyFilters, modifySorts, showDetail,
|
||||||
|
}) => {
|
||||||
|
const viewType = useMemo(() => view.type, [view]);
|
||||||
|
const viewColumns = useMemo(() => {
|
||||||
|
if (!view) return [];
|
||||||
|
return view.columns;
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
|
const filterColumns = useMemo(() => {
|
||||||
|
return viewColumns.filter(c => c.key !== PRIVATE_COLUMN_KEY.FILE_TYPE);
|
||||||
|
}, [viewColumns]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sf-metadata-tool-left-operations">
|
||||||
|
<GalleryGroupBySetter view={view} />
|
||||||
|
<GallerySliderSetter view={view} />
|
||||||
|
<FilterSetter
|
||||||
|
isNeedSubmit={true}
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-filter"
|
||||||
|
filtersClassName="sf-metadata-filters"
|
||||||
|
target="sf-metadata-filter-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
filterConjunction={view.filter_conjunction}
|
||||||
|
basicFilters={view.basic_filters}
|
||||||
|
filters={view.filters}
|
||||||
|
columns={filterColumns}
|
||||||
|
modifyFilters={modifyFilters}
|
||||||
|
collaborators={collaborators}
|
||||||
|
viewType={viewType}
|
||||||
|
/>
|
||||||
|
<SortSetter
|
||||||
|
isNeedSubmit={true}
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-sort"
|
||||||
|
target="sf-metadata-sort-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
sorts={view.sorts}
|
||||||
|
type={viewType}
|
||||||
|
columns={viewColumns}
|
||||||
|
modifySorts={modifySorts}
|
||||||
|
/>
|
||||||
|
{!isCustomPermission && (
|
||||||
|
<div className="cur-view-path-btn ml-2" onClick={showDetail}>
|
||||||
|
<span className="sf3-font sf3-font-info" aria-label={gettext('Properties')} title={gettext('Properties')}></span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="sf-metadata-tool-right-operations"></div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
GalleryViewToolbar.propTypes = {
|
||||||
|
readOnly: PropTypes.bool,
|
||||||
|
isCustomPermission: PropTypes.bool,
|
||||||
|
view: PropTypes.object.isRequired,
|
||||||
|
collaborators: PropTypes.array,
|
||||||
|
modifyFilters: PropTypes.func,
|
||||||
|
modifySorts: PropTypes.func,
|
||||||
|
showDetail: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GalleryViewToolbar;
|
@@ -1,23 +1,15 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { GalleryGroupBySetter, GallerySliderSetter, FilterSetter, GroupbySetter, SortSetter, HideColumnSetter } from '../data-process-setter';
|
import { EVENT_BUS_TYPE, VIEW_TYPE } from '../../constants';
|
||||||
import { EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY, VIEW_TYPE } from '../../constants';
|
import TableViewToolbar from './table-view-toolbar';
|
||||||
|
import GalleryViewToolbar from './gallery-view-toolbar';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const ViewToolBar = ({ viewId }) => {
|
const ViewToolBar = ({ viewId, isCustomPermission, showDetail }) => {
|
||||||
const [view, setView] = useState(null);
|
const [view, setView] = useState(null);
|
||||||
const [collaborators, setCollaborators] = useState([]);
|
const [collaborators, setCollaborators] = useState([]);
|
||||||
|
|
||||||
const viewColumns = useMemo(() => {
|
|
||||||
if (!view) return [];
|
|
||||||
return view.columns;
|
|
||||||
}, [view]);
|
|
||||||
|
|
||||||
const filterColumns = useMemo(() => {
|
|
||||||
return viewColumns.filter(c => c.key !== PRIVATE_COLUMN_KEY.FILE_TYPE);
|
|
||||||
}, [viewColumns]);
|
|
||||||
|
|
||||||
const onHeaderClick = useCallback(() => {
|
const onHeaderClick = useCallback(() => {
|
||||||
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
|
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -67,74 +59,44 @@ const ViewToolBar = ({ viewId }) => {
|
|||||||
if (!view) return null;
|
if (!view) return null;
|
||||||
|
|
||||||
const viewType = view.type;
|
const viewType = view.type;
|
||||||
const readOnly = !window.sfMetadataContext.canModifyView(view);
|
const readOnly = window.sfMetadataContext ? !window.sfMetadataContext.canModifyView(view) : true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="sf-metadata-tool"
|
className="sf-metadata-tool"
|
||||||
onClick={onHeaderClick}
|
onClick={onHeaderClick}
|
||||||
>
|
>
|
||||||
<div className="sf-metadata-tool-left-operations">
|
{viewType === VIEW_TYPE.TABLE && (
|
||||||
{viewType === VIEW_TYPE.GALLERY && (
|
<TableViewToolbar
|
||||||
<>
|
|
||||||
<GalleryGroupBySetter view={view} />
|
|
||||||
<GallerySliderSetter view={view} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<FilterSetter
|
|
||||||
isNeedSubmit={true}
|
|
||||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-filter"
|
|
||||||
filtersClassName="sf-metadata-filters"
|
|
||||||
target="sf-metadata-filter-popover"
|
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
filterConjunction={view.filter_conjunction}
|
view={view}
|
||||||
basicFilters={view.basic_filters}
|
|
||||||
filters={view.filters}
|
|
||||||
columns={filterColumns}
|
|
||||||
modifyFilters={modifyFilters}
|
|
||||||
collaborators={collaborators}
|
collaborators={collaborators}
|
||||||
viewType={viewType}
|
modifyFilters={modifyFilters}
|
||||||
/>
|
|
||||||
<SortSetter
|
|
||||||
isNeedSubmit={true}
|
|
||||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-sort"
|
|
||||||
target="sf-metadata-sort-popover"
|
|
||||||
readOnly={readOnly}
|
|
||||||
sorts={view.sorts}
|
|
||||||
type={viewType}
|
|
||||||
columns={viewColumns}
|
|
||||||
modifySorts={modifySorts}
|
modifySorts={modifySorts}
|
||||||
|
modifyGroupbys={modifyGroupbys}
|
||||||
|
modifyHiddenColumns={modifyHiddenColumns}
|
||||||
|
modifyColumnOrder={modifyColumnOrder}
|
||||||
/>
|
/>
|
||||||
{viewType !== VIEW_TYPE.GALLERY && (
|
)}
|
||||||
<GroupbySetter
|
{viewType === VIEW_TYPE.GALLERY && (
|
||||||
isNeedSubmit={true}
|
<GalleryViewToolbar
|
||||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-groupby"
|
readOnly={readOnly}
|
||||||
target="sf-metadata-groupby-popover"
|
isCustomPermission={isCustomPermission}
|
||||||
readOnly={readOnly}
|
view={view}
|
||||||
columns={viewColumns}
|
collaborators={collaborators}
|
||||||
groupbys={view.groupbys}
|
modifyFilters={modifyFilters}
|
||||||
modifyGroupbys={modifyGroupbys}
|
modifySorts={modifySorts}
|
||||||
/>
|
showDetail={showDetail}
|
||||||
)}
|
/>
|
||||||
{viewType !== VIEW_TYPE.GALLERY && (
|
)}
|
||||||
<HideColumnSetter
|
|
||||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-hide-column"
|
|
||||||
target="sf-metadata-hide-column-popover"
|
|
||||||
readOnly={readOnly}
|
|
||||||
columns={viewColumns.slice(1)}
|
|
||||||
hiddenColumns={view.hidden_columns || []}
|
|
||||||
modifyHiddenColumns={modifyHiddenColumns}
|
|
||||||
modifyColumnOrder={modifyColumnOrder}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="sf-metadata-tool-right-operations"></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
ViewToolBar.propTypes = {
|
ViewToolBar.propTypes = {
|
||||||
viewId: PropTypes.string,
|
viewId: PropTypes.string,
|
||||||
|
isCustomPermission: PropTypes.bool,
|
||||||
|
switchViewMode: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ViewToolBar;
|
export default ViewToolBar;
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { FilterSetter, GroupbySetter, SortSetter, HideColumnSetter } from '../../data-process-setter';
|
||||||
|
import { PRIVATE_COLUMN_KEY } from '../../../constants';
|
||||||
|
|
||||||
|
const TableViewToolbar = ({
|
||||||
|
readOnly, view, collaborators,
|
||||||
|
modifyFilters, modifySorts, modifyGroupbys, modifyHiddenColumns, modifyColumnOrder
|
||||||
|
}) => {
|
||||||
|
const viewType = useMemo(() => view.type, [view]);
|
||||||
|
const viewColumns = useMemo(() => {
|
||||||
|
if (!view) return [];
|
||||||
|
return view.columns;
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
|
const filterColumns = useMemo(() => {
|
||||||
|
return viewColumns.filter(c => c.key !== PRIVATE_COLUMN_KEY.FILE_TYPE);
|
||||||
|
}, [viewColumns]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sf-metadata-tool-left-operations">
|
||||||
|
<FilterSetter
|
||||||
|
isNeedSubmit={true}
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-filter"
|
||||||
|
filtersClassName="sf-metadata-filters"
|
||||||
|
target="sf-metadata-filter-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
filterConjunction={view.filter_conjunction}
|
||||||
|
basicFilters={view.basic_filters}
|
||||||
|
filters={view.filters}
|
||||||
|
columns={filterColumns}
|
||||||
|
modifyFilters={modifyFilters}
|
||||||
|
collaborators={collaborators}
|
||||||
|
viewType={viewType}
|
||||||
|
/>
|
||||||
|
<SortSetter
|
||||||
|
isNeedSubmit={true}
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-sort"
|
||||||
|
target="sf-metadata-sort-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
sorts={view.sorts}
|
||||||
|
type={viewType}
|
||||||
|
columns={viewColumns}
|
||||||
|
modifySorts={modifySorts}
|
||||||
|
/>
|
||||||
|
<GroupbySetter
|
||||||
|
isNeedSubmit={true}
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-groupby"
|
||||||
|
target="sf-metadata-groupby-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
columns={viewColumns}
|
||||||
|
groupbys={view.groupbys}
|
||||||
|
modifyGroupbys={modifyGroupbys}
|
||||||
|
/>
|
||||||
|
<HideColumnSetter
|
||||||
|
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-hide-column"
|
||||||
|
target="sf-metadata-hide-column-popover"
|
||||||
|
readOnly={readOnly}
|
||||||
|
columns={viewColumns.slice(1)}
|
||||||
|
hiddenColumns={view.hidden_columns || []}
|
||||||
|
modifyHiddenColumns={modifyHiddenColumns}
|
||||||
|
modifyColumnOrder={modifyColumnOrder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="sf-metadata-tool-right-operations"></div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TableViewToolbar.propTypes = {
|
||||||
|
readOnly: PropTypes.bool,
|
||||||
|
view: PropTypes.object.isRequired,
|
||||||
|
collaborators: PropTypes.array,
|
||||||
|
modifyFilters: PropTypes.func,
|
||||||
|
modifySorts: PropTypes.func,
|
||||||
|
modifyGroupbys: PropTypes.func,
|
||||||
|
modifyHiddenColumns: PropTypes.func,
|
||||||
|
modifyColumnOrder: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableViewToolbar;
|
@@ -124,6 +124,7 @@ export const MetadataViewProvider = ({
|
|||||||
store: storeRef.current,
|
store: storeRef.current,
|
||||||
deleteFilesCallback: params.deleteFilesCallback,
|
deleteFilesCallback: params.deleteFilesCallback,
|
||||||
renameFileCallback: params.renameFileCallback,
|
renameFileCallback: params.renameFileCallback,
|
||||||
|
updateCurrentDirent: params.updateCurrentDirent,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@@ -141,6 +141,7 @@ export const MetadataProvider = ({ repoID, hideMetadataView, selectMetadataView,
|
|||||||
parentNode: {},
|
parentNode: {},
|
||||||
key: repoID,
|
key: repoID,
|
||||||
view_id: view._id,
|
view_id: view._id,
|
||||||
|
view_type: view.type,
|
||||||
};
|
};
|
||||||
selectMetadataView(node);
|
selectMetadataView(node);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
@@ -13,7 +13,7 @@ const GalleryMain = ({
|
|||||||
gap,
|
gap,
|
||||||
mode,
|
mode,
|
||||||
selectedImages,
|
selectedImages,
|
||||||
setSelectedImages,
|
onImageSelect,
|
||||||
onImageClick,
|
onImageClick,
|
||||||
onImageDoubleClick,
|
onImageDoubleClick,
|
||||||
onImageRightClick
|
onImageRightClick
|
||||||
@@ -26,6 +26,7 @@ const GalleryMain = ({
|
|||||||
const [selectionStart, setSelectionStart] = useState(null);
|
const [selectionStart, setSelectionStart] = useState(null);
|
||||||
|
|
||||||
const imageHeight = useMemo(() => size + gap, [size, gap]);
|
const imageHeight = useMemo(() => size + gap, [size, gap]);
|
||||||
|
const selectedImageIds = useMemo(() => selectedImages.map(img => img.id), [selectedImages]);
|
||||||
|
|
||||||
const handleMouseDown = useCallback((e) => {
|
const handleMouseDown = useCallback((e) => {
|
||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
@@ -33,9 +34,7 @@ const GalleryMain = ({
|
|||||||
|
|
||||||
setIsSelecting(true);
|
setIsSelecting(true);
|
||||||
setSelectionStart({ x: e.clientX, y: e.clientY });
|
setSelectionStart({ x: e.clientX, y: e.clientY });
|
||||||
setSelectedImages([]);
|
}, []);
|
||||||
|
|
||||||
}, [setSelectedImages]);
|
|
||||||
|
|
||||||
const handleMouseMove = useCallback((e) => {
|
const handleMouseMove = useCallback((e) => {
|
||||||
if (!isSelecting) return;
|
if (!isSelecting) return;
|
||||||
@@ -59,9 +58,9 @@ const GalleryMain = ({
|
|||||||
const rect = imgElement.getBoundingClientRect();
|
const rect = imgElement.getBoundingClientRect();
|
||||||
if (
|
if (
|
||||||
rect.left < Math.max(selectionStart.x, selectionEnd.x) &&
|
rect.left < Math.max(selectionStart.x, selectionEnd.x) &&
|
||||||
rect.right > Math.min(selectionStart.x, selectionEnd.x) &&
|
rect.right > Math.min(selectionStart.x, selectionEnd.x) &&
|
||||||
rect.top < Math.max(selectionStart.y, selectionEnd.y) &&
|
rect.top < Math.max(selectionStart.y, selectionEnd.y) &&
|
||||||
rect.bottom > Math.min(selectionStart.y, selectionEnd.y)
|
rect.bottom > Math.min(selectionStart.y, selectionEnd.y)
|
||||||
) {
|
) {
|
||||||
selected.push(img);
|
selected.push(img);
|
||||||
}
|
}
|
||||||
@@ -70,9 +69,9 @@ const GalleryMain = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
setSelectedImages(selected);
|
onImageSelect(selected);
|
||||||
});
|
});
|
||||||
}, [groups, isSelecting, selectionStart, setSelectedImages]);
|
}, [groups, isSelecting, selectionStart, onImageSelect]);
|
||||||
|
|
||||||
const handleMouseUp = useCallback((e) => {
|
const handleMouseUp = useCallback((e) => {
|
||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
@@ -113,7 +112,6 @@ const GalleryMain = ({
|
|||||||
key={name}
|
key={name}
|
||||||
className="metadata-gallery-date-group"
|
className="metadata-gallery-date-group"
|
||||||
style={{ height, paddingTop }}
|
style={{ height, paddingTop }}
|
||||||
|
|
||||||
>
|
>
|
||||||
{mode !== GALLERY_DATE_MODE.ALL && childrenStartIndex === 0 && (
|
{mode !== GALLERY_DATE_MODE.ALL && childrenStartIndex === 0 && (
|
||||||
<div className="metadata-gallery-date-tag">{name || gettext('Empty')}</div>
|
<div className="metadata-gallery-date-tag">{name || gettext('Empty')}</div>
|
||||||
@@ -129,7 +127,7 @@ const GalleryMain = ({
|
|||||||
>
|
>
|
||||||
{children.slice(childrenStartIndex, childrenEndIndex + 1).map((row) => {
|
{children.slice(childrenStartIndex, childrenEndIndex + 1).map((row) => {
|
||||||
return row.children.map((img) => {
|
return row.children.map((img) => {
|
||||||
const isSelected = selectedImages.includes(img);
|
const isSelected = selectedImageIds.includes(img.id);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={img.src}
|
key={img.src}
|
||||||
@@ -151,7 +149,7 @@ const GalleryMain = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}, [overScan, columns, size, imageHeight, mode, selectedImages, onImageClick, onImageDoubleClick, onImageRightClick]);
|
}, [overScan, columns, size, imageHeight, mode, selectedImageIds, onImageClick, onImageDoubleClick, onImageRightClick]);
|
||||||
|
|
||||||
if (!Array.isArray(groups) || groups.length === 0) {
|
if (!Array.isArray(groups) || groups.length === 0) {
|
||||||
return <EmptyTip text={gettext('No record')}/>;
|
return <EmptyTip text={gettext('No record')}/>;
|
||||||
@@ -195,6 +193,7 @@ GalleryMain.propTypes = {
|
|||||||
gap: PropTypes.number.isRequired,
|
gap: PropTypes.number.isRequired,
|
||||||
mode: PropTypes.string,
|
mode: PropTypes.string,
|
||||||
selectedImages: PropTypes.array.isRequired,
|
selectedImages: PropTypes.array.isRequired,
|
||||||
|
onImageSelect: PropTypes.func.isRequired,
|
||||||
onImageClick: PropTypes.func.isRequired,
|
onImageClick: PropTypes.func.isRequired,
|
||||||
onImageDoubleClick: PropTypes.func.isRequired,
|
onImageDoubleClick: PropTypes.func.isRequired,
|
||||||
onImageRightClick: PropTypes.func.isRequired,
|
onImageRightClick: PropTypes.func.isRequired,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
.sf-metadata-gallery-container {
|
.sf-metadata-gallery-container {
|
||||||
height: calc(100vh - 100px);
|
height: 100%;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -13,6 +13,8 @@ import { Utils } from '../../../utils/utils';
|
|||||||
import { getDateDisplayString, getFileNameFromRecord, getParentDirFromRecord } from '../../utils/cell';
|
import { getDateDisplayString, getFileNameFromRecord, getParentDirFromRecord } from '../../utils/cell';
|
||||||
import { siteRoot, fileServerRoot, useGoFileserver, gettext, thumbnailSizeForGrid, thumbnailSizeForOriginal } from '../../../utils/constants';
|
import { siteRoot, fileServerRoot, useGoFileserver, gettext, thumbnailSizeForGrid, thumbnailSizeForOriginal } from '../../../utils/constants';
|
||||||
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, PRIVATE_COLUMN_KEY, GALLERY_DATE_MODE, DATE_TAG_HEIGHT, GALLERY_IMAGE_GAP } from '../../constants';
|
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, PRIVATE_COLUMN_KEY, GALLERY_DATE_MODE, DATE_TAG_HEIGHT, GALLERY_IMAGE_GAP } from '../../constants';
|
||||||
|
import { getRowById } from '../../utils/table';
|
||||||
|
import { getEventClassName } from '../../utils/common';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -31,9 +33,14 @@ const Gallery = () => {
|
|||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const renderMoreTimer = useRef(null);
|
const renderMoreTimer = useRef(null);
|
||||||
|
|
||||||
const { metadata, store } = useMetadataView();
|
const { metadata, store, updateCurrentDirent } = useMetadataView();
|
||||||
const repoID = window.sfMetadataContext.getSetting('repoID');
|
const repoID = window.sfMetadataContext.getSetting('repoID');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateCurrentDirent();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Number of images per row
|
// Number of images per row
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
return 8 - zoomGear;
|
return 8 - zoomGear;
|
||||||
@@ -206,21 +213,38 @@ const Gallery = () => {
|
|||||||
return groups.flatMap(group => group.children.flatMap(row => row.children));
|
return groups.flatMap(group => group.children.flatMap(row => row.children));
|
||||||
}, [groups]);
|
}, [groups]);
|
||||||
|
|
||||||
|
const updateSelectedImage = useCallback((image = null) => {
|
||||||
|
const imageInfo = image ? getRowById(metadata, image.id) : null;
|
||||||
|
if (!imageInfo) {
|
||||||
|
updateCurrentDirent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateCurrentDirent({
|
||||||
|
type: 'file',
|
||||||
|
name: image.name,
|
||||||
|
path: image.path,
|
||||||
|
file_tags: []
|
||||||
|
});
|
||||||
|
}, [metadata, updateCurrentDirent]);
|
||||||
|
|
||||||
const handleClick = useCallback((event, image) => {
|
const handleClick = useCallback((event, image) => {
|
||||||
if (event.metaKey || event.ctrlKey) {
|
if (event.metaKey || event.ctrlKey) {
|
||||||
setSelectedImages(prev =>
|
setSelectedImages(prev =>
|
||||||
prev.includes(image) ? prev.filter(img => img !== image) : [...prev, image]
|
prev.includes(image) ? prev.filter(img => img !== image) : [...prev, image]
|
||||||
);
|
);
|
||||||
|
updateSelectedImage(image);
|
||||||
} else if (event.shiftKey && selectedImages.length > 0) {
|
} else if (event.shiftKey && selectedImages.length > 0) {
|
||||||
const lastSelected = selectedImages[selectedImages.length - 1];
|
const lastSelected = selectedImages[selectedImages.length - 1];
|
||||||
const start = imageItems.indexOf(lastSelected);
|
const start = imageItems.indexOf(lastSelected);
|
||||||
const end = imageItems.indexOf(image);
|
const end = imageItems.indexOf(image);
|
||||||
const range = imageItems.slice(Math.min(start, end), Math.max(start, end) + 1);
|
const range = imageItems.slice(Math.min(start, end), Math.max(start, end) + 1);
|
||||||
setSelectedImages(prev => Array.from(new Set([...prev, ...range])));
|
setSelectedImages(prev => Array.from(new Set([...prev, ...range])));
|
||||||
|
updateSelectedImage(null);
|
||||||
} else {
|
} else {
|
||||||
setSelectedImages([image]);
|
setSelectedImages([image]);
|
||||||
|
updateSelectedImage(image);
|
||||||
}
|
}
|
||||||
}, [imageItems, selectedImages]);
|
}, [imageItems, selectedImages, updateSelectedImage]);
|
||||||
|
|
||||||
const handleDoubleClick = useCallback((event, image) => {
|
const handleDoubleClick = useCallback((event, image) => {
|
||||||
const index = imageItems.findIndex(item => item.id === image.id);
|
const index = imageItems.findIndex(item => item.id === image.id);
|
||||||
@@ -246,6 +270,10 @@ const Gallery = () => {
|
|||||||
setImageIndex((prevState) => (prevState + 1) % imageItemsLength);
|
setImageIndex((prevState) => (prevState + 1) % imageItemsLength);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImageSelection = useCallback((selectedImages) => {
|
||||||
|
setSelectedImages(selectedImages);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const closeImagePopup = () => {
|
const closeImagePopup = () => {
|
||||||
setIsImagePopupOpen(false);
|
setIsImagePopupOpen(false);
|
||||||
};
|
};
|
||||||
@@ -308,8 +336,18 @@ const Gallery = () => {
|
|||||||
setIsZipDialogOpen(false);
|
setIsZipDialogOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClickOutside = useCallback((event) => {
|
||||||
|
const className = getEventClassName(event);
|
||||||
|
const isClickInsideImage = className.includes('metadata-gallery-image-item') || className.includes('metadata-gallery-grid-image');
|
||||||
|
|
||||||
|
if (!isClickInsideImage && containerRef.current.contains(event.target)) {
|
||||||
|
handleImageSelection([]);
|
||||||
|
updateSelectedImage();
|
||||||
|
}
|
||||||
|
}, [handleImageSelection, updateSelectedImage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sf-metadata-container">
|
<div className="sf-metadata-container" onMouseDown={handleClickOutside}>
|
||||||
<div className={`sf-metadata-gallery-container sf-metadata-gallery-container-${mode}`} ref={containerRef} onScroll={handleScroll} >
|
<div className={`sf-metadata-gallery-container sf-metadata-gallery-container-${mode}`} ref={containerRef} onScroll={handleScroll} >
|
||||||
{!isFirstLoading && (
|
{!isFirstLoading && (
|
||||||
<>
|
<>
|
||||||
@@ -321,7 +359,7 @@ const Gallery = () => {
|
|||||||
gap={GALLERY_IMAGE_GAP}
|
gap={GALLERY_IMAGE_GAP}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
selectedImages={selectedImages}
|
selectedImages={selectedImages}
|
||||||
setSelectedImages={setSelectedImages}
|
onImageSelect={handleImageSelection}
|
||||||
onImageClick={handleClick}
|
onImageClick={handleClick}
|
||||||
onImageDoubleClick={handleDoubleClick}
|
onImageDoubleClick={handleDoubleClick}
|
||||||
onImageRightClick={handleRightClick}
|
onImageRightClick={handleRightClick}
|
||||||
|
@@ -22,12 +22,13 @@ import DeleteFolderDialog from '../../components/dialog/delete-folder-dialog';
|
|||||||
import { EVENT_BUS_TYPE } from '../../components/common/event-bus-type';
|
import { EVENT_BUS_TYPE } from '../../components/common/event-bus-type';
|
||||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
import { MetadataProvider, CollaboratorsProvider } from '../../metadata/hooks';
|
import { MetadataProvider, CollaboratorsProvider } from '../../metadata/hooks';
|
||||||
import { LIST_MODE, METADATA_MODE, FACE_RECOGNITION_MODE } from '../../components/dir-view-mode/constants';
|
import { LIST_MODE, METADATA_MODE, FACE_RECOGNITION_MODE, DIRENT_DETAIL_MODE } from '../../components/dir-view-mode/constants';
|
||||||
import CurDirPath from '../../components/cur-dir-path';
|
import CurDirPath from '../../components/cur-dir-path';
|
||||||
import DirTool from '../../components/cur-dir-path/dir-tool';
|
import DirTool from '../../components/cur-dir-path/dir-tool';
|
||||||
import DetailContainer from '../../components/dirent-detail/detail-container';
|
import DetailContainer from '../../components/dirent-detail/detail-container';
|
||||||
import DirColumnView from '../../components/dir-view-mode/dir-column-view';
|
import DirColumnView from '../../components/dir-view-mode/dir-column-view';
|
||||||
import SelectedDirentsToolbar from '../../components/toolbar/selected-dirents-toolbar';
|
import SelectedDirentsToolbar from '../../components/toolbar/selected-dirents-toolbar';
|
||||||
|
import { VIEW_TYPE } from '../../metadata/constants';
|
||||||
|
|
||||||
import '../../css/lib-content-view.css';
|
import '../../css/lib-content-view.css';
|
||||||
|
|
||||||
@@ -83,7 +84,6 @@ class LibContentView extends React.Component {
|
|||||||
dirID: '', // for update dir list
|
dirID: '', // for update dir list
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
isDirentDetailShow: false,
|
isDirentDetailShow: false,
|
||||||
direntDetailPanelTab: '',
|
|
||||||
itemsShowLength: 100,
|
itemsShowLength: 100,
|
||||||
isSessionExpired: false,
|
isSessionExpired: false,
|
||||||
isCopyMoveProgressDialogShow: false,
|
isCopyMoveProgressDialogShow: false,
|
||||||
@@ -107,7 +107,11 @@ class LibContentView extends React.Component {
|
|||||||
this.unsubscribeEventBus = null;
|
this.unsubscribeEventBus = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentDirent = (deletedDirent) => {
|
updateCurrentDirent = (dirent = null) => {
|
||||||
|
this.setState({ currentDirent: dirent });
|
||||||
|
};
|
||||||
|
|
||||||
|
updateCurrentNotExistDirent = (deletedDirent) => {
|
||||||
let { currentDirent } = this.state;
|
let { currentDirent } = this.state;
|
||||||
if (currentDirent && deletedDirent.name === currentDirent.name) {
|
if (currentDirent && deletedDirent.name === currentDirent.name) {
|
||||||
this.setState({ currentDirent: null });
|
this.setState({ currentDirent: null });
|
||||||
@@ -124,31 +128,16 @@ class LibContentView extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
showDirentDetail = (direntDetailPanelTab) => {
|
showDirentDetail = () => {
|
||||||
if (direntDetailPanelTab) {
|
this.setState({ isDirentDetailShow: true });
|
||||||
this.setState({ direntDetailPanelTab: direntDetailPanelTab }, () => {
|
|
||||||
this.setState({ isDirentDetailShow: true });
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
direntDetailPanelTab: '',
|
|
||||||
isDirentDetailShow: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleDirentDetail = () => {
|
toggleDirentDetail = () => {
|
||||||
this.setState({
|
this.setState({ isDirentDetailShow: !this.state.isDirentDetailShow });
|
||||||
direntDetailPanelTab: '',
|
|
||||||
isDirentDetailShow: !this.state.isDirentDetailShow
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
closeDirentDetail = () => {
|
closeDirentDetail = () => {
|
||||||
this.setState({
|
this.setState({ isDirentDetailShow: false });
|
||||||
isDirentDetailShow: false,
|
|
||||||
direntDetailPanelTab: '',
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -538,14 +527,14 @@ class LibContentView extends React.Component {
|
|||||||
window.history.pushState({ url: url, path: filePath }, filePath, url);
|
window.history.pushState({ url: url, path: filePath }, filePath, url);
|
||||||
};
|
};
|
||||||
|
|
||||||
showFileMetadata = (filePath, viewId) => {
|
showFileMetadata = (filePath, viewId, viewType) => {
|
||||||
const repoID = this.props.repoID;
|
const repoID = this.props.repoID;
|
||||||
const repoInfo = this.state.currentRepoInfo;
|
const repoInfo = this.state.currentRepoInfo;
|
||||||
this.setState({
|
this.setState({
|
||||||
currentMode: METADATA_MODE,
|
currentMode: METADATA_MODE,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
isDirentDetailShow: false
|
isDirentDetailShow: viewType === VIEW_TYPE.GALLERY ? this.state.isDirentDetailShow : false,
|
||||||
}, () => {
|
}, () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.unsubscribeEventBus = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.OPEN_MARKDOWN_DIALOG, this.openMarkDownDialog);
|
this.unsubscribeEventBus = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.OPEN_MARKDOWN_DIALOG, this.openMarkDownDialog);
|
||||||
@@ -1020,7 +1009,7 @@ class LibContentView extends React.Component {
|
|||||||
if (mode === this.state.currentMode) {
|
if (mode === this.state.currentMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mode === 'detail') {
|
if (mode === DIRENT_DETAIL_MODE) {
|
||||||
this.toggleDirentDetail();
|
this.toggleDirentDetail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1134,7 +1123,7 @@ class LibContentView extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMainPanelItemDelete = (dirent) => {
|
onMainPanelItemDelete = (dirent) => {
|
||||||
this.updateCurrentDirent(dirent);
|
this.updateCurrentNotExistDirent(dirent);
|
||||||
let path = Utils.joinPath(this.state.path, dirent.name);
|
let path = Utils.joinPath(this.state.path, dirent.name);
|
||||||
this.deleteItem(path, dirent.isDir());
|
this.deleteItem(path, dirent.isDir());
|
||||||
};
|
};
|
||||||
@@ -1261,7 +1250,7 @@ class LibContentView extends React.Component {
|
|||||||
|
|
||||||
// list operations
|
// list operations
|
||||||
onMoveItem = (destRepo, dirent, moveToDirentPath, nodeParentPath) => {
|
onMoveItem = (destRepo, dirent, moveToDirentPath, nodeParentPath) => {
|
||||||
this.updateCurrentDirent(dirent);
|
this.updateCurrentNotExistDirent(dirent);
|
||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
// just for view list state
|
// just for view list state
|
||||||
let dirName = dirent.name;
|
let dirName = dirent.name;
|
||||||
@@ -1897,7 +1886,7 @@ class LibContentView extends React.Component {
|
|||||||
}
|
}
|
||||||
} else if (Utils.isFileMetadata(node?.object?.type)) {
|
} else if (Utils.isFileMetadata(node?.object?.type)) {
|
||||||
if (node.path !== this.state.path) {
|
if (node.path !== this.state.path) {
|
||||||
this.showFileMetadata(node.path, node.view_id || '0000');
|
this.showFileMetadata(node.path, node.view_id || '0000', node.view_type || VIEW_TYPE.TABLE);
|
||||||
}
|
}
|
||||||
} else if (Utils.isFaceRecognition(node?.object?.type)) {
|
} else if (Utils.isFaceRecognition(node?.object?.type)) {
|
||||||
if (node.path !== this.state.path) {
|
if (node.path !== this.state.path) {
|
||||||
@@ -2428,6 +2417,7 @@ class LibContentView extends React.Component {
|
|||||||
getMarkDownFilePath={this.getMarkDownFilePath}
|
getMarkDownFilePath={this.getMarkDownFilePath}
|
||||||
getMarkDownFileName={this.getMarkDownFileName}
|
getMarkDownFileName={this.getMarkDownFileName}
|
||||||
openMarkdownFile={this.openMarkdownFile}
|
openMarkdownFile={this.openMarkdownFile}
|
||||||
|
updateCurrentDirent={this.updateCurrentDirent}
|
||||||
/>
|
/>
|
||||||
:
|
:
|
||||||
<div className="message err-tip">{gettext('Folder does not exist.')}</div>
|
<div className="message err-tip">{gettext('Folder does not exist.')}</div>
|
||||||
|
Reference in New Issue
Block a user