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

feat: optimize code

This commit is contained in:
杨国璇
2024-11-15 16:08:46 +08:00
parent a629d1c07c
commit 5a7e25740f
16 changed files with 240 additions and 264 deletions

View File

@@ -120,7 +120,12 @@ class DirTool extends React.Component {
if (isFileExtended) { if (isFileExtended) {
return ( return (
<div className="dir-tool"> <div className="dir-tool">
<MetadataViewToolBar viewId={viewId} isCustomPermission={isCustomPermission} showDetail={this.showDirentDetail} closeDetail={this.props.onCloseDetail} /> <MetadataViewToolBar
viewId={viewId}
isCustomPermission={isCustomPermission}
showDetail={this.showDirentDetail}
closeDetail={this.props.onCloseDetail}
/>
</div> </div>
); );
} }

View File

@@ -14,6 +14,7 @@ import { GRID_MODE, LIST_MODE, METADATA_MODE } from './constants';
const propTypes = { const propTypes = {
isSidePanelFolded: PropTypes.bool, isSidePanelFolded: PropTypes.bool,
isTreePanelShown: PropTypes.bool.isRequired, isTreePanelShown: PropTypes.bool.isRequired,
isDirentDetailShow: PropTypes.bool,
currentMode: PropTypes.string.isRequired, currentMode: PropTypes.string.isRequired,
path: PropTypes.string.isRequired, path: PropTypes.string.isRequired,
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
@@ -198,6 +199,7 @@ class DirColumnView extends React.Component {
{currentMode === METADATA_MODE && ( {currentMode === METADATA_MODE && (
<SeafileMetadata <SeafileMetadata
mediaUrl={mediaUrl} mediaUrl={mediaUrl}
isDirentDetailShow={this.props.isDirentDetailShow}
repoID={this.props.repoID} repoID={this.props.repoID}
repoInfo={this.props.currentRepoInfo} repoInfo={this.props.currentRepoInfo}
viewID={this.props.viewId} viewID={this.props.viewId}

View File

@@ -17,6 +17,7 @@ const ViewDetails = ({ viewId, onClose }) => {
if (type === VIEW_TYPE.GALLERY) return `${mediaUrl}favicons/gallery.png`; if (type === VIEW_TYPE.GALLERY) return `${mediaUrl}favicons/gallery.png`;
if (type === VIEW_TYPE.TABLE) return `${mediaUrl}favicons/table.png`; if (type === VIEW_TYPE.TABLE) return `${mediaUrl}favicons/table.png`;
if (type === VIEW_TYPE.FACE_RECOGNITION) return `${mediaUrl}favicons/face-recognition-view.png`; if (type === VIEW_TYPE.FACE_RECOGNITION) return `${mediaUrl}favicons/face-recognition-view.png`;
if (type === VIEW_TYPE.KANBAN) return `${mediaUrl}favicons/kanban.png`;
return `${mediaUrl}img/file/256/file.png`; return `${mediaUrl}img/file/256/file.png`;
}, [view]); }, [view]);

View File

@@ -100,11 +100,13 @@ const ViewToolBar = ({ viewId, isCustomPermission, showDetail, closeDetail }) =>
)} )}
{viewType === VIEW_TYPE.KANBAN && ( {viewType === VIEW_TYPE.KANBAN && (
<KanbanViewToolBar <KanbanViewToolBar
isCustomPermission={isCustomPermission}
readOnly={readOnly} readOnly={readOnly}
view={view} view={view}
collaborators={collaborators} collaborators={collaborators}
modifyFilters={modifyFilters} modifyFilters={modifyFilters}
modifySorts={modifySorts} modifySorts={modifySorts}
showDetail={showDetail}
closeDetail={closeDetail} closeDetail={closeDetail}
/> />
)} )}

View File

@@ -1,15 +1,18 @@
import React, { useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { IconBtn } from '@seafile/sf-metadata-ui-component'; import { IconBtn } from '@seafile/sf-metadata-ui-component';
import { EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY } from '../../../constants'; import { EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY } from '../../../constants';
import { FilterSetter, SortSetter } from '../../data-process-setter'; import { FilterSetter, SortSetter } from '../../data-process-setter';
import { gettext } from '../../../../utils/constants';
const KanbanViewToolBar = ({ const KanbanViewToolBar = ({
isCustomPermission,
readOnly, readOnly,
view, view,
collaborators, collaborators,
modifyFilters, modifyFilters,
modifySorts, modifySorts,
showDetail,
closeDetail, closeDetail,
}) => { }) => {
const viewType = useMemo(() => view.type, [view]); const viewType = useMemo(() => view.type, [view]);
@@ -27,6 +30,11 @@ const KanbanViewToolBar = ({
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_KANBAN_SETTINGS); window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_KANBAN_SETTINGS);
}; };
const toggleDetails = useCallback(() => {
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.CLOSE_KANBAN_SETTINGS);
showDetail();
}, [showDetail]);
return ( return (
<> <>
<div className="sf-metadata-tool-left-operations"> <div className="sf-metadata-tool-left-operations">
@@ -63,6 +71,11 @@ const KanbanViewToolBar = ({
tabIndex={0} tabIndex={0}
onClick={onToggleKanbanSetting} onClick={onToggleKanbanSetting}
/> />
{!isCustomPermission && (
<div className="cur-view-path-btn ml-2" onClick={toggleDetails}>
<span className="sf3-font sf3-font-info" aria-label={gettext('Properties')} title={gettext('Properties')}></span>
</div>
)}
</div> </div>
<div className="sf-metadata-tool-right-operations"></div> <div className="sf-metadata-tool-right-operations"></div>
</> </>

View File

@@ -60,4 +60,6 @@ export const EVENT_BUS_TYPE = {
// kanban // kanban
TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings', TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings',
OPEN_KANBAN_SETTINGS: 'open_kanban_settings',
CLOSE_KANBAN_SETTINGS: 'close_kanban_settings',
}; };

View File

@@ -135,9 +135,3 @@ export const GALLERY_DATE_MODE = {
}; };
export const UNCATEGORIZED = '_uncategorized'; export const UNCATEGORIZED = '_uncategorized';
export const FILE_TYPE = {
MARKDOWN: 'markdown',
SDOC: 'sdoc',
IMAGE: 'image',
};

View File

@@ -130,6 +130,7 @@ export const MetadataViewProvider = ({
isLoading, isLoading,
metadata, metadata,
store: storeRef.current, store: storeRef.current,
isDirentDetailShow: params.isDirentDetailShow,
deleteFilesCallback: params.deleteFilesCallback, deleteFilesCallback: params.deleteFilesCallback,
renameFileCallback: params.renameFileCallback, renameFileCallback: params.renameFileCallback,
updateCurrentDirent: params.updateCurrentDirent, updateCurrentDirent: params.updateCurrentDirent,

View File

@@ -0,0 +1,97 @@
import { getFileNameFromRecord, getParentDirFromRecord } from './cell';
import { checkIsDir } from './row';
import { Utils } from '../../utils/utils';
import { siteRoot } from '../../utils/constants';
import { EVENT_BUS_TYPE } from '../../components/common/event-bus-type';
const FILE_TYPE = {
FOLDER: 'folder',
MARKDOWN: 'markdown',
SDOC: 'sdoc',
IMAGE: 'image',
};
const _getFileType = (fileName, isDir) => {
if (isDir) return FILE_TYPE.FOLDER;
if (!fileName) return '';
const index = fileName.lastIndexOf('.');
if (index === -1) return '';
const suffix = fileName.slice(index).toLowerCase();
if (suffix.indexOf(' ') > -1) return '';
if (Utils.imageCheck(fileName)) return FILE_TYPE.IMAGE;
if (Utils.isMarkdownFile(fileName)) return FILE_TYPE.MARKDOWN;
if (Utils.isSdocFile(fileName)) return FILE_TYPE.SDOC;
return '';
};
const _getParentDir = (record) => {
const parentDir = getParentDirFromRecord(record);
if (parentDir === '/') {
return '';
}
return parentDir;
};
const _generateUrl = (fileName, parentDir) => {
const repoID = window.sfMetadataContext.getSetting('repoID');
const path = Utils.encodePath(Utils.joinPath(parentDir, fileName));
return `${siteRoot}lib/${repoID}/file${path}`;
};
const _openUrl = (url) => {
window.open(url);
};
const _openMarkdown = (fileName, parentDir, eventBus) => {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.OPEN_MARKDOWN_DIALOG, parentDir, fileName);
};
const _openByNewWindow = (fileName, parentDir, fileType) => {
if (!fileType) {
const url = _generateUrl(fileName, parentDir);
_openUrl(url);
return;
}
let pathname = window.location.pathname;
if (pathname.endsWith('/')) {
pathname = pathname.slice(0, -1);
}
_openUrl(window.location.origin + pathname + Utils.encodePath(Utils.joinPath(parentDir, fileName)));
};
const _openSdoc = (fileName, parentDir) => {
const url = _generateUrl(fileName, parentDir);
_openUrl(url);
};
const _openOthers = (fileName, parentDir, fileType) => {
_openByNewWindow(fileName, parentDir, fileType);
};
export const openFile = (record, eventBus, _openImage = () => {}) => {
if (!record) return;
const fileName = getFileNameFromRecord(record);
const isDir = checkIsDir(record);
const parentDir = _getParentDir(record);
const fileType = _getFileType(fileName, isDir);
switch (fileType) {
case FILE_TYPE.MARKDOWN: {
_openMarkdown(fileName, parentDir, eventBus);
break;
}
case FILE_TYPE.SDOC: {
_openSdoc(fileName, parentDir);
break;
}
case FILE_TYPE.IMAGE: {
_openImage(record);
break;
}
default: {
_openOthers(fileName, parentDir, fileType);
break;
}
}
};

View File

@@ -12,21 +12,32 @@
user-select: none; user-select: none;
} }
.sf-metadata-kanban-card.selected {
border-color: #FF8000;
}
.sf-metadata-kanban-card:hover { .sf-metadata-kanban-card:hover {
cursor: pointer; cursor: pointer;
box-shadow: 0 0 6px #0000002e; box-shadow: 0 0 6px #0000002e;
} }
.sf-metadata-kanban-card.readonly {
cursor: default;
}
.sf-metadata-kanban-card .sf-metadata-kanban-card-header { .sf-metadata-kanban-card .sf-metadata-kanban-card-header {
font-weight: 500; font-weight: 500;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }
.sf-metadata-kanban-card .sf-metadata-kanban-card-header .sf-metadata-file-name {
text-decoration: none;
flex: none;
}
.sf-metadata-kanban-card .sf-metadata-kanban-card-header .sf-metadata-file-name:hover {
cursor: pointer;
text-decoration: underline;
text-decoration-color: #212529;
}
.sf-metadata-kanban-card .sf-metadata-kanban-card-body .sf-metadata-kanban-card-record:first-child { .sf-metadata-kanban-card .sf-metadata-kanban-card-body .sf-metadata-kanban-card-record:first-child {
margin-top: 10px; margin-top: 10px;
} }
@@ -84,17 +95,6 @@
transform: translateY(-1px); transform: translateY(-1px);
} }
.sf-metadata-kanban-card .sf-metadata-ui.file-name-formatter .sf-metadata-file-name {
text-decoration: none;
flex: none;
}
.sf-metadata-kanban-card .sf-metadata-ui.file-name-formatter .sf-metadata-file-name:hover {
cursor: pointer;
text-decoration: underline;
text-decoration-color: #212529;
}
.sf-metadata-kanban-card .sf-metadata-kanban-card-record .collaborators-formatter { .sf-metadata-kanban-card .sf-metadata-kanban-card-record .collaborators-formatter {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@@ -1,98 +1,49 @@
import React, { useCallback, useEffect, useRef } from 'react'; import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import Formatter from '../formatter'; import Formatter from '../formatter';
import { FILE_TYPE } from '../../../../../constants'; import { getCellValueByColumn, isValidCellValue } from '../../../../../utils/cell';
import { useMetadataView } from '../../../../../hooks/metadata-view';
import { Utils } from '../../../../../../utils/utils';
import { geRecordIdFromRecord, getCellValueByColumn, getFileNameFromRecord, getParentDirFromRecord, isValidCellValue } from '../../../../../utils/cell';
import './index.css'; import './index.css';
const Card = ({ const Card = ({
readonly, isSelected,
displayEmptyValue, displayEmptyValue,
displayColumnName, displayColumnName,
record, record,
titleColumn, titleColumn,
displayColumns, displayColumns,
onCloseSettings,
onOpenFile, onOpenFile,
onSelectCard,
}) => { }) => {
const cardRef = useRef(null);
const { updateCurrentDirent, showDirentDetail } = useMetadataView();
const titleValue = getCellValueByColumn(record, titleColumn); const titleValue = getCellValueByColumn(record, titleColumn);
const handleClickCard = useCallback((e) => { const handleClickCard = useCallback((event) => {
e.preventDefault(); event.preventDefault();
e.stopPropagation(); event.stopPropagation();
const name = getFileNameFromRecord(record); event.nativeEvent.stopImmediatePropagation();
const path = getParentDirFromRecord(record); onSelectCard(record);
updateCurrentDirent({ }, [record, onSelectCard]);
type: 'file',
name,
path,
file_tags: []
});
onCloseSettings();
showDirentDetail();
}, [record, updateCurrentDirent, showDirentDetail, onCloseSettings]);
const getFileType = useCallback((fileName) => { const handleClickFilename = useCallback((event) => {
if (!fileName) return ''; event.stopPropagation();
const index = fileName.lastIndexOf('.'); event.nativeEvent.stopImmediatePropagation();
if (index === -1) return ''; onOpenFile(record);
const suffix = fileName.slice(index).toLowerCase(); }, [record, onOpenFile]);
if (suffix.indexOf(' ') > -1) return '';
if (Utils.imageCheck(fileName)) return FILE_TYPE.IMAGE;
if (Utils.isMarkdownFile(fileName)) return FILE_TYPE.MARKDOWN;
if (Utils.isSdocFile(fileName)) return FILE_TYPE.SDOC;
return '';
}, []);
const handleClickFilename = useCallback((e) => {
e.preventDefault();
e.stopPropagation();
const fileName = getFileNameFromRecord(record);
const fileType = getFileType(fileName);
const parentDir = getParentDirFromRecord(record);
const recordId = geRecordIdFromRecord(record);
onOpenFile(fileType, fileName, parentDir, recordId);
}, [record, getFileType, onOpenFile]);
useEffect(() => {
const cardElement = cardRef.current;
if (!cardElement) return;
const filenameElement = cardElement.querySelector('.file-name-formatter .sf-metadata-file-name');
if (filenameElement) {
filenameElement.addEventListener('click', handleClickFilename);
}
return () => {
if (filenameElement) {
filenameElement.removeEventListener('click', handleClickFilename);
}
};
}, [handleClickFilename]);
return ( return (
<article <article
ref={cardRef}
data-id={record._id} data-id={record._id}
className={classnames('sf-metadata-kanban-card', { 'readonly': readonly })} className={classnames('sf-metadata-kanban-card', { 'selected': isSelected })}
onClick={handleClickCard} onClick={handleClickCard}
> >
{titleColumn && ( {titleColumn && (
<div className="sf-metadata-kanban-card-header"> <div className="sf-metadata-kanban-card-header" onClick={handleClickFilename}>
<Formatter value={titleValue} column={titleColumn} record={record}/> <Formatter value={titleValue} column={titleColumn} record={record}/>
</div> </div>
)} )}
<div className="sf-metadata-kanban-card-body"> <div className="sf-metadata-kanban-card-body">
{displayColumns.map((column, index) => { {displayColumns.map((column) => {
const value = getCellValueByColumn(record, column); const value = getCellValueByColumn(record, column);
if (!displayEmptyValue && !isValidCellValue(value)) { if (!displayEmptyValue && !isValidCellValue(value)) {
if (displayColumnName) { if (displayColumnName) {
@@ -118,14 +69,14 @@ const Card = ({
}; };
Card.propTypes = { Card.propTypes = {
readonly: PropTypes.bool, isSelected: PropTypes.bool,
displayEmptyValue: PropTypes.bool, displayEmptyValue: PropTypes.bool,
displayColumnName: PropTypes.bool, displayColumnName: PropTypes.bool,
record: PropTypes.object, record: PropTypes.object,
titleColumn: PropTypes.object, titleColumn: PropTypes.object,
displayColumns: PropTypes.array, displayColumns: PropTypes.array,
onCloseSettings: PropTypes.func.isRequired,
onOpenFile: PropTypes.func.isRequired, onOpenFile: PropTypes.func.isRequired,
onSelectCard: PropTypes.func.isRequired,
}; };
export default Card; export default Card;

View File

@@ -6,6 +6,7 @@ import { useMetadataView } from '../../../../hooks/metadata-view';
import { getRowById } from '../../../../utils/table'; import { getRowById } from '../../../../utils/table';
import Container from '../../dnd/container'; import Container from '../../dnd/container';
import Draggable from '../../dnd/draggable'; import Draggable from '../../dnd/draggable';
import { geRecordIdFromRecord } from '../../../../utils/cell';
import './index.css'; import './index.css';
@@ -19,12 +20,13 @@ const Board = ({
groupByColumn, groupByColumn,
titleColumn, titleColumn,
displayColumns, displayColumns,
selectedCard,
onMove, onMove,
deleteOption, deleteOption,
onFreezed, onFreezed,
onUnFreezed, onUnFreezed,
onCloseSettings,
onOpenFile, onOpenFile,
onSelectCard,
}) => { }) => {
const [isDraggingOver, setDraggingOver] = useState(false); const [isDraggingOver, setDraggingOver] = useState(false);
const boardName = useMemo(() => `sf_metadata_kanban_board_${board.key}`, [board]); const boardName = useMemo(() => `sf_metadata_kanban_board_${board.key}`, [board]);
@@ -75,17 +77,18 @@ const Board = ({
{board.children.map((cardKey) => { {board.children.map((cardKey) => {
const record = getRowById(metadata, cardKey); const record = getRowById(metadata, cardKey);
if (!record) return null; if (!record) return null;
const isSelected = selectedCard === geRecordIdFromRecord(record);
const CardElement = ( const CardElement = (
<Card <Card
key={cardKey} key={cardKey}
readonly={readonly} isSelected={isSelected}
displayEmptyValue={displayEmptyValue} displayEmptyValue={displayEmptyValue}
displayColumnName={displayColumnName} displayColumnName={displayColumnName}
record={record} record={record}
titleColumn={titleColumn} titleColumn={titleColumn}
displayColumns={displayColumns} displayColumns={displayColumns}
onCloseSettings={onCloseSettings}
onOpenFile={onOpenFile} onOpenFile={onOpenFile}
onSelectCard={onSelectCard}
/> />
); );
if (readonly) return CardElement; if (readonly) return CardElement;
@@ -110,12 +113,13 @@ Board.propTypes = {
groupByColumn: PropTypes.object, groupByColumn: PropTypes.object,
titleColumn: PropTypes.object, titleColumn: PropTypes.object,
displayColumns: PropTypes.array, displayColumns: PropTypes.array,
selectedCard: PropTypes.string,
onMove: PropTypes.func, onMove: PropTypes.func,
deleteOption: PropTypes.func, deleteOption: PropTypes.func,
onFreezed: PropTypes.func, onFreezed: PropTypes.func,
onUnFreezed: PropTypes.func, onUnFreezed: PropTypes.func,
onCloseSettings: PropTypes.func.isRequired,
onOpenFile: PropTypes.func.isRequired, onOpenFile: PropTypes.func.isRequired,
onSelectCard: PropTypes.func.isRequired,
}; };
export default Board; export default Board;

View File

@@ -1,29 +1,33 @@
import React, { useMemo, useCallback, useState } from 'react'; import React, { useMemo, useCallback, useState, useRef, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { useMetadataView } from '../../../hooks/metadata-view'; import { useMetadataView } from '../../../hooks/metadata-view';
import { useCollaborators } from '../../../hooks'; import { useCollaborators } from '../../../hooks';
import { CellType, KANBAN_SETTINGS_KEYS, UNCATEGORIZED, FILE_TYPE } from '../../../constants'; import { CellType, KANBAN_SETTINGS_KEYS, UNCATEGORIZED } from '../../../constants';
import { COLUMN_DATA_OPERATION_TYPE } from '../../../store/operations'; import { COLUMN_DATA_OPERATION_TYPE } from '../../../store/operations';
import { gettext, siteRoot } from '../../../../utils/constants'; import { gettext } from '../../../../utils/constants';
import { checkIsPredefinedOption, getCellValueByColumn, isValidCellValue, geRecordIdFromRecord } from '../../../utils/cell'; import { checkIsPredefinedOption, getCellValueByColumn, isValidCellValue, geRecordIdFromRecord,
getFileNameFromRecord, getParentDirFromRecord
} from '../../../utils/cell';
import { getColumnOptions, getColumnOriginName } from '../../../utils/column'; import { getColumnOptions, getColumnOriginName } from '../../../utils/column';
import AddBoard from '../add-board'; import AddBoard from '../add-board';
import EmptyTip from '../../../../components/empty-tip'; import EmptyTip from '../../../../components/empty-tip';
import Board from './board'; import Board from './board';
import { Utils } from '../../../../utils/utils';
import { EVENT_BUS_TYPE } from '../../../../components/common/event-bus-type';
import ImagePreviewer from '../../../components/cell-formatter/image-previewer'; import ImagePreviewer from '../../../components/cell-formatter/image-previewer';
import { getRowById } from '../../../utils/table'; import { openFile } from '../../../utils/open-file';
import { checkIsDir } from '../../../utils/row';
import './index.css'; import './index.css';
const Boards = ({ modifyRecord, modifyColumnData, onCloseSettings }) => { const Boards = ({ modifyRecord, modifyColumnData, onCloseSettings }) => {
const [haveFreezed, setHaveFreezed] = useState(false); const [haveFreezed, setHaveFreezed] = useState(false);
const [isImagePreviewerVisible, setImagePreviewerVisible] = useState(false); const [isImagePreviewerVisible, setImagePreviewerVisible] = useState(false);
const [record, setRecord] = useState(null); const [selectedCard, setSelectedCard] = useState('');
const { metadata, store } = useMetadataView(); const currentImageRef = useRef(null);
const containerRef = useRef(null);
const { isDirentDetailShow, metadata, store, updateCurrentDirent, showDirentDetail } = useMetadataView();
const { collaborators } = useCollaborators(); const { collaborators } = useCollaborators();
const groupByColumn = useMemo(() => { const groupByColumn = useMemo(() => {
@@ -170,68 +174,57 @@ const Boards = ({ modifyRecord, modifyColumnData, onCloseSettings }) => {
setHaveFreezed(false); setHaveFreezed(false);
}, []); }, []);
const isEmpty = boards.length === 0; const onOpenFile = useCallback((record) => {
openFile(record, window.sfMetadataContext.eventBus, () => {
const generateUrl = (fileName, parentDir) => { currentImageRef.current = record;
const repoID = window.sfMetadataContext.getSetting('repoID'); setImagePreviewerVisible(true);
const path = Utils.encodePath(Utils.joinPath(parentDir, fileName)); });
return `${siteRoot}lib/${repoID}/file${path}`;
};
const openMarkdown = useCallback((name, parentDir) => {
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.OPEN_MARKDOWN_DIALOG, parentDir, name);
}, []); }, []);
const openByNewWindow = useCallback((fileType, fileName, parentDir) => {
if (!fileType) {
const url = generateUrl(fileName, parentDir);
window.open(url);
} else {
let pathname = window.location.pathname;
if (pathname.endsWith('/')) {
pathname = pathname.slice(0, -1);
}
window.open(window.location.origin + pathname + Utils.encodePath(Utils.joinPath(parentDir, fileName)));
}
}, []);
const openSdoc = useCallback((fileName, parentDir) => {
const url = generateUrl(fileName, parentDir);
window.open(url);
}, []);
const openFile = useCallback((type, fileName, parentDir, recordId = null) => {
switch (type) {
case FILE_TYPE.MARKDOWN: {
openMarkdown(fileName, parentDir);
break;
}
case FILE_TYPE.SDOC: {
openSdoc(fileName, parentDir);
break;
}
case FILE_TYPE.IMAGE: {
const record = getRowById(metadata, recordId);
setRecord(record);
setImagePreviewerVisible(true);
break;
}
default: {
openByNewWindow(type, fileName, parentDir);
break;
}
}
}, [openMarkdown, openSdoc, openByNewWindow, metadata]);
const closeImagePreviewer = useCallback(() => { const closeImagePreviewer = useCallback(() => {
currentImageRef.current = null;
setImagePreviewerVisible(false); setImagePreviewerVisible(false);
}, []); }, []);
const onSelectCard = useCallback((record) => {
const recordId = geRecordIdFromRecord(record);
const name = getFileNameFromRecord(record);
const path = getParentDirFromRecord(record);
const isDir = checkIsDir(record);
updateCurrentDirent({
type: isDir ? 'dir' : 'file',
mtime: '',
name,
path,
file_tags: []
});
setSelectedCard(recordId);
onCloseSettings();
showDirentDetail();
}, [onCloseSettings, showDirentDetail, updateCurrentDirent]);
const handleClickOutside = useCallback((event) => {
if (!containerRef.current.contains(event.target)) return;
setSelectedCard(null);
updateCurrentDirent();
}, [updateCurrentDirent]);
useEffect(() => {
if (!isDirentDetailShow) {
setSelectedCard(null);
}
}, [isDirentDetailShow]);
const isEmpty = boards.length === 0;
return ( return (
<div className={classnames('sf-metadata-view-kanban-boards', { <div
'sf-metadata-view-kanban-boards-text-wrap': textWrap, ref={containerRef}
'readonly': readonly, className={classnames('sf-metadata-view-kanban-boards', {
})} 'sf-metadata-view-kanban-boards-text-wrap': textWrap,
'readonly': readonly,
})}
onClick={handleClickOutside}
> >
<div className="smooth-dnd-container horizontal"> <div className="smooth-dnd-container horizontal">
{isEmpty && (<EmptyTip className="tips-empty-boards" text={gettext('No categories')} />)} {isEmpty && (<EmptyTip className="tips-empty-boards" text={gettext('No categories')} />)}
@@ -250,12 +243,13 @@ const Boards = ({ modifyRecord, modifyColumnData, onCloseSettings }) => {
groupByColumn={groupByColumn} groupByColumn={groupByColumn}
titleColumn={titleColumn} titleColumn={titleColumn}
displayColumns={displayColumns} displayColumns={displayColumns}
selectedCard={selectedCard}
onMove={onMove} onMove={onMove}
deleteOption={deleteOption} deleteOption={deleteOption}
onFreezed={onFreezed} onFreezed={onFreezed}
onUnFreezed={onUnFreezed} onUnFreezed={onUnFreezed}
onCloseSettings={onCloseSettings} onOpenFile={onOpenFile}
onOpenFile={openFile} onSelectCard={onSelectCard}
/> />
); );
})} })}
@@ -263,7 +257,7 @@ const Boards = ({ modifyRecord, modifyColumnData, onCloseSettings }) => {
)} )}
{!readonly && (<AddBoard groupByColumn={groupByColumn}/>)} {!readonly && (<AddBoard groupByColumn={groupByColumn}/>)}
</div> </div>
{isImagePreviewerVisible && (<ImagePreviewer record={record} table={metadata} closeImagePopup={closeImagePreviewer} />)} {isImagePreviewerVisible && (<ImagePreviewer record={currentImageRef.current} table={metadata} closeImagePopup={closeImagePreviewer} />)}
</div> </div>
); );
}; };

View File

@@ -45,8 +45,10 @@ const Kanban = () => {
useEffect(() => { useEffect(() => {
const eventBus = window.sfMetadataContext.eventBus; const eventBus = window.sfMetadataContext.eventBus;
const unsubscribeKanbanSetting = eventBus.subscribe(EVENT_BUS_TYPE.TOGGLE_KANBAN_SETTINGS, () => setShowSettings(!isShowSettings)); const unsubscribeKanbanSetting = eventBus.subscribe(EVENT_BUS_TYPE.TOGGLE_KANBAN_SETTINGS, () => setShowSettings(!isShowSettings));
const unsubscribeCloseKanbanSetting = eventBus.subscribe(EVENT_BUS_TYPE.CLOSE_KANBAN_SETTINGS, () => setShowSettings(false));
return () => { return () => {
unsubscribeKanbanSetting(); unsubscribeKanbanSetting();
unsubscribeCloseKanbanSetting();
}; };
}, [isShowSettings]); }, [isShowSettings]);

View File

@@ -1,121 +1,28 @@
import React, { useMemo } from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { UncontrolledTooltip } from 'reactstrap'; import { UncontrolledTooltip } from 'reactstrap';
import { IconBtn } from '@seafile/sf-metadata-ui-component'; import { IconBtn } from '@seafile/sf-metadata-ui-component';
import { Utils } from '../../../../../../../../utils/utils'; import { gettext } from '../../../../../../../../utils/constants';
import { gettext, siteRoot } from '../../../../../../../../utils/constants';
import { EVENT_BUS_TYPE } from '../../../../../../../..//components/common/event-bus-type';
import { EVENT_BUS_TYPE as METADATA_EVENT_BUS_TYPE, EDITOR_TYPE } from '../../../../../../../constants'; import { EVENT_BUS_TYPE as METADATA_EVENT_BUS_TYPE, EDITOR_TYPE } from '../../../../../../../constants';
import { getFileNameFromRecord, getParentDirFromRecord } from '../../../../../../../utils/cell'; import { openFile } from '../../../../../../../utils/open-file';
import { checkIsDir } from '../../../../../../../utils/row';
import './index.css'; import './index.css';
const FILE_TYPE = {
FOLDER: 'folder',
MARKDOWN: 'markdown',
SDOC: 'sdoc',
IMAGE: 'image',
};
const CellOperationBtn = ({ isDir, column, record, cellValue, ...props }) => { const CellOperationBtn = ({ isDir, column, record, cellValue, ...props }) => {
const fileName = useMemo(() => { const handelClick = (event) => {
const { key } = column;
return record[key];
}, [column, record]);
const fileType = useMemo(() => {
if (checkIsDir(record)) return FILE_TYPE.FOLDER;
if (!fileName) return '';
const index = fileName.lastIndexOf('.');
if (index === -1) return '';
const suffix = fileName.slice(index).toLowerCase();
if (suffix.indexOf(' ') > -1) return '';
if (Utils.imageCheck(fileName)) return FILE_TYPE.IMAGE;
if (Utils.isMarkdownFile(fileName)) return FILE_TYPE.MARKDOWN;
if (Utils.isSdocFile(fileName)) return FILE_TYPE.SDOC;
return '';
}, [record, fileName]);
const getParentDir = () => {
const parentDir = getParentDirFromRecord(record);
if (parentDir === '/') {
return '';
}
return parentDir;
};
const generateUrl = () => {
const repoID = window.sfMetadataContext.getSetting('repoID');
const parentDir = getParentDir();
const path = Utils.encodePath(Utils.joinPath(parentDir, fileName));
return `${siteRoot}lib/${repoID}/file${path}`;
};
const openUrl = (url) => {
window.open(url);
};
const openMarkdown = () => {
const fileName = getFileNameFromRecord(record);
const parentDir = getParentDirFromRecord(record);
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.OPEN_MARKDOWN_DIALOG, parentDir, fileName);
};
const openByNewWindow = (fileType) => {
if (!fileType) {
const url = generateUrl();
openUrl(url);
} else {
const parentDir = getParentDir();
let pathname = window.location.pathname;
if (pathname.endsWith('/')) {
pathname = pathname.slice(0, -1);
}
openUrl(window.location.origin + pathname + Utils.encodePath(Utils.joinPath(parentDir, fileName)));
}
};
const openSdoc = () => {
const url = generateUrl();
openUrl(url);
};
const openOthers = () => {
openByNewWindow(fileType);
};
const openFile = (event) => {
event.stopPropagation(); event.stopPropagation();
event.nativeEvent.stopImmediatePropagation(); event.nativeEvent.stopImmediatePropagation();
openFile(record, window.sfMetadataContext.eventBus, () => {
switch (fileType) { window.sfMetadataContext.eventBus.dispatch(METADATA_EVENT_BUS_TYPE.OPEN_EDITOR, EDITOR_TYPE.PREVIEWER);
case FILE_TYPE.MARKDOWN: { });
openMarkdown();
break;
}
case FILE_TYPE.SDOC: {
openSdoc();
break;
}
case FILE_TYPE.IMAGE: {
// render image previewer via FileNameEditor
window.sfMetadataContext.eventBus.dispatch(METADATA_EVENT_BUS_TYPE.OPEN_EDITOR, EDITOR_TYPE.PREVIEWER);
break;
}
default: {
openOthers();
break;
}
}
}; };
if (!cellValue) return null; if (!cellValue) return null;
return ( return (
<> <>
<IconBtn id={'sf-metadata-cell-open-file-btn'} className="sf-metadata-cell-operation-btn" size={20} iconName="open-file" onClick={openFile} /> <IconBtn id={'sf-metadata-cell-open-file-btn'} className="sf-metadata-cell-operation-btn" size={20} iconName="open-file" onClick={handelClick} />
<UncontrolledTooltip <UncontrolledTooltip
hideArrow hideArrow
target={'sf-metadata-cell-open-file-btn'} target={'sf-metadata-cell-open-file-btn'}

View File

@@ -2358,6 +2358,7 @@ class LibContentView extends React.Component {
<DirColumnView <DirColumnView
isSidePanelFolded={this.props.isSidePanelFolded} isSidePanelFolded={this.props.isSidePanelFolded}
isTreePanelShown={this.state.isTreePanelShown} isTreePanelShown={this.state.isTreePanelShown}
isDirentDetailShow={this.state.isDirentDetailShow}
currentMode={this.state.currentMode} currentMode={this.state.currentMode}
path={this.state.path} path={this.state.path}
repoID={this.props.repoID} repoID={this.props.repoID}