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}
+
+ );
+ })}
+
+ )}
);
};