From cb3af6e66a6dbbb2fdde2673961937e7d8dc6f55 Mon Sep 17 00:00:00 2001 From: Aries Date: Sat, 8 Feb 2025 17:56:36 +0800 Subject: [PATCH] kanban supports collapse (#7437) * kanban supports collapse * optimize * optimize ui --------- Co-authored-by: zhouwenxuan --- .../file-details/collapse/index.css | 2 +- .../kanban/boards/board/header/index.css | 22 ++++ .../views/kanban/boards/board/header/index.js | 35 ++++-- .../boards/board/header/op-menu/index.js | 5 +- .../views/kanban/boards/board/index.js | 103 ++++++++++-------- 5 files changed, 108 insertions(+), 59 deletions(-) diff --git a/frontend/src/components/dirent-detail/dirent-details/file-details/collapse/index.css b/frontend/src/components/dirent-detail/dirent-details/file-details/collapse/index.css index e62d8242f1..e15cbac375 100644 --- a/frontend/src/components/dirent-detail/dirent-details/file-details/collapse/index.css +++ b/frontend/src/components/dirent-detail/dirent-details/file-details/collapse/index.css @@ -35,7 +35,7 @@ } .file-details-collapse .file-details-collapse-header .file-details-collapse-header-operation:hover { - background-color: #DBDBDB; + background-color: #EFEFEF; cursor: pointer; border-radius: 3px; } diff --git a/frontend/src/metadata/views/kanban/boards/board/header/index.css b/frontend/src/metadata/views/kanban/boards/board/header/index.css index 3c77e2de6b..b97b914633 100644 --- a/frontend/src/metadata/views/kanban/boards/board/header/index.css +++ b/frontend/src/metadata/views/kanban/boards/board/header/index.css @@ -27,3 +27,25 @@ color: #666666; margin-left: 12px; } + +.sf-metadata-view-kanban-board-header .board-header-operation-btn { + display: flex; + align-items: flex-end; +} + +.board-header-operation-btn .kanban-header-op-btn { + width: 20px; + height: 20px; + display: flex; + justify-content: center; + align-items: center; + margin-left: 0.5rem; + color: #666666; + cursor: pointer; + border-radius: 3px; +} + +.board-header-operation-btn .kanban-header-op-btn.kanban-header-collapse-btn:hover, +.board-header-operation-btn .kanban-header-op-btn.kanban-more-operations-toggle:hover { + background-color: #EFEFEF; +} diff --git a/frontend/src/metadata/views/kanban/boards/board/header/index.js b/frontend/src/metadata/views/kanban/boards/board/header/index.js index 7498ddf4e3..bc3a48f242 100644 --- a/frontend/src/metadata/views/kanban/boards/board/header/index.js +++ b/frontend/src/metadata/views/kanban/boards/board/header/index.js @@ -1,5 +1,6 @@ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import CellFormatter from '../../../../../components/cell-formatter'; import { gettext } from '../../../../../../utils/constants'; import OpMenu from './op-menu'; @@ -7,9 +8,11 @@ import { CellType } from '../../../../../constants'; import './index.css'; -const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, onDelete, onFreezed, onUnFreezed }) => { +const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, onDelete, onFreezed, onUnFreezed, isCollapsed, onCollapse }) => { const [active, setActive] = useState(false); + const headerRef = useRef(); + const onMouseEnter = useCallback(() => { if (haveFreezed) return; setActive(true); @@ -20,10 +23,14 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on setActive(false); }, [haveFreezed]); - const handelUnFreezed = useCallback((keepActive) => { + const keepActive = useCallback((event) => { + return event.target.className?.includes('kanban-header-op-btn') || event.target === headerRef.current; + }, []); + + const handelUnFreezed = useCallback((event) => { onUnFreezed(); - !keepActive && setActive(false); - }, [onUnFreezed]); + !keepActive(event) && setActive(false); + }, [onUnFreezed, keepActive]); const titleValue = useMemo(() => { if (!value || !groupByColumn) return null; @@ -31,9 +38,14 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on return value; }, [value, groupByColumn]); + const handleCollapse = useCallback((event) => { + onCollapse(); + !keepActive(event) && setActive(false); + }, [onCollapse, keepActive]); + return (
-
+
{value ? ( ) : ( @@ -41,8 +53,15 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on )} {cardsQuantity}
- {value && !readonly && active && ( - + {active && ( +
+ {value && !readonly && } + + +
)}
); diff --git a/frontend/src/metadata/views/kanban/boards/board/header/op-menu/index.js b/frontend/src/metadata/views/kanban/boards/board/header/op-menu/index.js index e4b8ffde41..e53eba737d 100644 --- a/frontend/src/metadata/views/kanban/boards/board/header/op-menu/index.js +++ b/frontend/src/metadata/views/kanban/boards/board/header/op-menu/index.js @@ -9,8 +9,7 @@ const OpMenu = ({ onDelete, onFreezed, onUnFreezed }) => { const toggle = useCallback((event) => { event.stopPropagation(); if (isShow) { - const isClickToggleBtn = event.target.className?.includes('kanban-more-operations-toggle'); - onUnFreezed(isClickToggleBtn); + onUnFreezed(event); } else { onFreezed(); } @@ -35,7 +34,7 @@ const OpMenu = ({ onDelete, onFreezed, onUnFreezed }) => { tag="i" role="button" tabIndex="0" - className="sf-dropdown-toggle sf3-font-more sf3-font kanban-more-operations-toggle" + className="sf-dropdown-toggle sf3-font-more sf3-font kanban-header-op-btn kanban-more-operations-toggle" title={gettext('More operations')} aria-label={gettext('More operations')} data-toggle="dropdown" diff --git a/frontend/src/metadata/views/kanban/boards/board/index.js b/frontend/src/metadata/views/kanban/boards/board/index.js index ff91f6e437..2e27775da5 100644 --- a/frontend/src/metadata/views/kanban/boards/board/index.js +++ b/frontend/src/metadata/views/kanban/boards/board/index.js @@ -31,6 +31,7 @@ const Board = ({ onContextMenu, }) => { const [isDraggingOver, setDraggingOver] = useState(false); + const [isCollapsed, setCollapsed] = useState(false); const boardName = useMemo(() => `sf_metadata_kanban_board_${board.key}`, [board]); const cardsQuantity = useMemo(() => board.children.length, [board.children]); @@ -54,6 +55,10 @@ const Board = ({ setTimeout(() => updateDragging(false), 0); }, [isDraggingOver, onMove, updateDragging]); + const onCollapse = useCallback(() => { + setCollapsed(!isCollapsed); + }, [isCollapsed]); + return (
deleteOption(board.key)} onFreezed={onFreezed} onUnFreezed={onUnFreezed} + isCollapsed={isCollapsed} + onCollapse={onCollapse} /> - onDragEnd(boardIndex, e)} - onDragEnter={() => setDraggingOver(true)} - onDragLeave={() => setDraggingOver(false)} - shouldAcceptDrop={(sourceContainer) => sourceContainer.groupName !== boardName} - getChildPayload={(cardIndex) => ({ boardIndex, cardIndex })} - dropPlaceholder={{ - animationDuration: 300, - showOnTop: true, - className: 'card-drop-preview', - }} - getGhostParent={() => { + {!isCollapsed && ( + onDragEnd(boardIndex, e)} + onDragEnter={() => setDraggingOver(true)} + onDragLeave={() => setDraggingOver(false)} + shouldAcceptDrop={(sourceContainer) => sourceContainer.groupName !== boardName} + getChildPayload={(cardIndex) => ({ boardIndex, cardIndex })} + dropPlaceholder={{ + animationDuration: 300, + showOnTop: true, + className: 'card-drop-preview', + }} + getGhostParent={() => { // return anchestor of container who doesn't have a transform property - return document.querySelector('.sf-metadata-main'); - }} - > - {board.children.map((cardKey) => { - const record = getRowById(metadata, cardKey); - if (!record) return null; - const recordId = getRecordIdFromRecord(record); - const isSelected = selectedCard === recordId; - const CardElement = ( - onContextMenu(e, recordId)} - /> - ); - if (readonly) return CardElement; - return ( - - {CardElement} - - ); - })} - + return document.querySelector('.sf-metadata-main'); + }} + > + {board.children.map((cardKey) => { + const record = getRowById(metadata, cardKey); + if (!record) return null; + const recordId = getRecordIdFromRecord(record); + const isSelected = selectedCard === recordId; + const CardElement = ( + onContextMenu(e, recordId)} + /> + ); + if (readonly) return CardElement; + return ( + + {CardElement} + + ); + })} + + )}
); };