Skip to content

Commit

Permalink
Merge pull request #7042 from haiwen/feature/optimize_kanban
Browse files Browse the repository at this point in the history
Feature/optimize kanban
  • Loading branch information
YangGuoXuan-0503 authored Nov 15, 2024
2 parents 3045a7b + 3fffdf9 commit 95d99e1
Show file tree
Hide file tree
Showing 15 changed files with 274 additions and 124 deletions.
8 changes: 7 additions & 1 deletion frontend/src/components/cur-dir-path/dir-tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const propTypes = {
sortOrder: PropTypes.string,
sortItems: PropTypes.func,
viewId: PropTypes.string,
onCloseDetail: PropTypes.func,
};

class DirTool extends React.Component {
Expand Down Expand Up @@ -119,7 +120,12 @@ class DirTool extends React.Component {
if (isFileExtended) {
return (
<div className="dir-tool">
<MetadataViewToolBar viewId={viewId} isCustomPermission={isCustomPermission} showDetail={this.showDirentDetail} />
<MetadataViewToolBar
viewId={viewId}
isCustomPermission={isCustomPermission}
showDetail={this.showDirentDetail}
closeDetail={this.props.onCloseDetail}
/>
</div>
);
}
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/dir-view-mode/dir-column-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { GRID_MODE, LIST_MODE, METADATA_MODE } from './constants';
const propTypes = {
isSidePanelFolded: PropTypes.bool,
isTreePanelShown: PropTypes.bool.isRequired,
isDirentDetailShow: PropTypes.bool,
currentMode: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
repoID: PropTypes.string.isRequired,
Expand Down Expand Up @@ -198,13 +199,15 @@ class DirColumnView extends React.Component {
{currentMode === METADATA_MODE && (
<SeafileMetadata
mediaUrl={mediaUrl}
isDirentDetailShow={this.props.isDirentDetailShow}
repoID={this.props.repoID}
repoInfo={this.props.currentRepoInfo}
viewID={this.props.viewId}
deleteFilesCallback={this.props.deleteFilesCallback}
renameFileCallback={this.props.renameFileCallback}
updateCurrentDirent={this.props.updateCurrentDirent}
closeDirentDetail={this.props.closeDirentDetail}
showDirentDetail={this.props.showDirentDetail}
/>
)}
{currentMode === LIST_MODE &&
Expand Down
1 change: 1 addition & 0 deletions frontend/src/metadata/components/view-details/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const ViewDetails = ({ viewId, onClose }) => {
if (type === VIEW_TYPE.GALLERY) return `${mediaUrl}favicons/gallery.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.KANBAN) return `${mediaUrl}favicons/kanban.png`;
return `${mediaUrl}img/file/256/file.png`;
}, [view]);

Expand Down
8 changes: 6 additions & 2 deletions frontend/src/metadata/components/view-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import KanbanViewToolBar from './kanban-view-toolbar';

import './index.css';

const ViewToolBar = ({ viewId, isCustomPermission, showDetail }) => {
const ViewToolBar = ({ viewId, isCustomPermission, showDetail, closeDetail }) => {
const [view, setView] = useState(null);
const [collaborators, setCollaborators] = useState([]);

Expand Down Expand Up @@ -100,11 +100,14 @@ const ViewToolBar = ({ viewId, isCustomPermission, showDetail }) => {
)}
{viewType === VIEW_TYPE.KANBAN && (
<KanbanViewToolBar
isCustomPermission={isCustomPermission}
readOnly={readOnly}
view={view}
collaborators={collaborators}
modifyFilters={modifyFilters}
modifySorts={modifySorts}
showDetail={showDetail}
closeDetail={closeDetail}
/>
)}
</div>
Expand All @@ -114,7 +117,8 @@ const ViewToolBar = ({ viewId, isCustomPermission, showDetail }) => {
ViewToolBar.propTypes = {
viewId: PropTypes.string,
isCustomPermission: PropTypes.bool,
switchViewMode: PropTypes.func,
showDetail: PropTypes.func,
closeDetail: PropTypes.func,
};

export default ViewToolBar;
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React, { useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { IconBtn } from '@seafile/sf-metadata-ui-component';
import { EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY } from '../../../constants';
import { FilterSetter, SortSetter } from '../../data-process-setter';
import { gettext } from '../../../../utils/constants';

const KanbanViewToolBar = ({
isCustomPermission,
readOnly,
view,
collaborators,
modifyFilters,
modifySorts
modifySorts,
showDetail,
closeDetail,
}) => {
const viewType = useMemo(() => view.type, [view]);
const viewColumns = useMemo(() => {
Expand All @@ -22,9 +26,15 @@ const KanbanViewToolBar = ({
}, [viewColumns]);

const onToggleKanbanSetting = () => {
closeDetail();
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 (
<>
<div className="sf-metadata-tool-left-operations">
Expand Down Expand Up @@ -61,6 +71,11 @@ const KanbanViewToolBar = ({
tabIndex={0}
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 className="sf-metadata-tool-right-operations"></div>
</>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/metadata/constants/event-bus-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ export const EVENT_BUS_TYPE = {

// kanban
TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings',
OPEN_KANBAN_SETTINGS: 'open_kanban_settings',
CLOSE_KANBAN_SETTINGS: 'close_kanban_settings',
};
2 changes: 2 additions & 0 deletions frontend/src/metadata/hooks/metadata-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,12 @@ export const MetadataViewProvider = ({
isLoading,
metadata,
store: storeRef.current,
isDirentDetailShow: params.isDirentDetailShow,
deleteFilesCallback: params.deleteFilesCallback,
renameFileCallback: params.renameFileCallback,
updateCurrentDirent: params.updateCurrentDirent,
closeDirentDetail: params.closeDirentDetail,
showDirentDetail: params.showDirentDetail,
}}
>
{children}
Expand Down
97 changes: 97 additions & 0 deletions frontend/src/metadata/utils/open-file.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
};

15 changes: 15 additions & 0 deletions frontend/src/metadata/views/kanban/boards/board/card/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
display: flex;
flex-direction: column;
overflow: hidden;
user-select: none;
}

.sf-metadata-kanban-card.selected {
border-color: #FF8000;
}

.sf-metadata-kanban-card:hover {
Expand All @@ -22,6 +27,16 @@
overflow: hidden;
}

.sf-metadata-kanban-card .sf-metadata-kanban-card-header .sf-metadata-file-name {
text-decoration: 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 {
margin-top: 10px;
}
Expand Down
41 changes: 33 additions & 8 deletions frontend/src/metadata/views/kanban/boards/board/card/index.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,54 @@
import React from 'react';
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { getCellValueByColumn, isValidCellValue } from '../../../../../utils/cell';
import Formatter from '../formatter';
import { getCellValueByColumn, isValidCellValue } from '../../../../../utils/cell';
import { CellType } from '../../../../../constants';
import { getEventClassName } from '../../../../../utils/common';

import './index.css';

const Card = ({
readonly,
isSelected,
displayEmptyValue,
displayColumnName,
record,
titleColumn,
displayColumns,
onOpenFile,
onSelectCard,
}) => {

const titleValue = getCellValueByColumn(record, titleColumn);

const handleClickCard = useCallback((event) => {
event.preventDefault();
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
onSelectCard(record);
}, [record, onSelectCard]);

const handleClickFilename = useCallback((event) => {
if (titleColumn?.type !== CellType.FILE_NAME) return;
const eventName = getEventClassName(event);
if (eventName !== 'sf-metadata-file-name') return;
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
onOpenFile(record);
}, [titleColumn, record, onOpenFile]);

return (
<article data-id={record._id} className={classnames('sf-metadata-kanban-card', { 'readonly': readonly })}>
<article
data-id={record._id}
className={classnames('sf-metadata-kanban-card', { 'selected': isSelected })}
onClick={handleClickCard}
>
{titleColumn && (
<div className="sf-metadata-kanban-card-header">
<div className="sf-metadata-kanban-card-header" onClick={handleClickFilename}>
<Formatter value={titleValue} column={titleColumn} record={record}/>
</div>
)}
<div className="sf-metadata-kanban-card-body">
{displayColumns.map((column, index) => {
{displayColumns.map((column) => {
const value = getCellValueByColumn(record, column);
if (!displayEmptyValue && !isValidCellValue(value)) {
if (displayColumnName) {
Expand All @@ -51,12 +74,14 @@ const Card = ({
};

Card.propTypes = {
readonly: PropTypes.bool,
isSelected: PropTypes.bool,
displayEmptyValue: PropTypes.bool,
displayColumnName: PropTypes.bool,
record: PropTypes.object,
titleColumn: PropTypes.object,
displayColumns: PropTypes.array,
onOpenFile: PropTypes.func.isRequired,
onSelectCard: PropTypes.func.isRequired,
};

export default Card;
Loading

0 comments on commit 95d99e1

Please sign in to comment.