diff --git a/web/components/core/multiple-select/entity-select-action.tsx b/web/components/core/multiple-select/entity-select-action.tsx index 7b9ca9409..7672928cd 100644 --- a/web/components/core/multiple-select/entity-select-action.tsx +++ b/web/components/core/multiple-select/entity-select-action.tsx @@ -18,6 +18,8 @@ export const MultipleSelectEntityAction: React.FC = (props) => { // derived values const isSelected = selectionHelpers.getIsEntitySelected(id); + if (selectionHelpers.isSelectionDisabled) return null; + return ( = (props) => { // derived values const groupSelectionStatus = selectionHelpers.isGroupSelected(groupID); + if (selectionHelpers.isSelectionDisabled) return null; + return ( React.ReactNode; containerRef: React.MutableRefObject; + disabled?: boolean; entities: Record; // { groupID: entityIds[] } }; export const MultipleSelectGroup: React.FC = observer((props) => { - const { children, containerRef, entities } = props; + const { children, containerRef, disabled = false, entities } = props; const helpers = useMultipleSelect({ containerRef, + disabled, entities, }); diff --git a/web/components/gantt-chart/chart/main-content.tsx b/web/components/gantt-chart/chart/main-content.tsx index e5bd7afbf..fc62f1bbc 100644 --- a/web/components/gantt-chart/chart/main-content.tsx +++ b/web/components/gantt-chart/chart/main-content.tsx @@ -118,6 +118,7 @@ export const GanttChartMainContent: React.FC = observer((props) => { entities={{ [GANTT_SELECT_GROUP]: chartBlocks?.map((block) => block.id) ?? [], }} + disabled > {(helpers) => ( <> diff --git a/web/components/issues/bulk-operations/root.tsx b/web/components/issues/bulk-operations/root.tsx index f92e02279..741a341be 100644 --- a/web/components/issues/bulk-operations/root.tsx +++ b/web/components/issues/bulk-operations/root.tsx @@ -11,11 +11,11 @@ type Props = { }; export const IssueBulkOperationsRoot: React.FC = observer((props) => { - const { className } = props; + const { className, selectionHelpers } = props; // store hooks const { isSelectionActive } = useMultipleSelectStore(); - if (!isSelectionActive) return null; + if (!isSelectionActive || selectionHelpers.isSelectionDisabled) return null; return ; }); diff --git a/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx b/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx index 17df47163..2f257c6cd 100644 --- a/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx +++ b/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx @@ -72,7 +72,7 @@ export const BaseGanttRoot: React.FC = observer((props: IBaseGan enableBlockMove={isAllowed} enableReorder={appliedDisplayFilters?.order_by === "sort_order" && isAllowed} enableAddBlock={isAllowed} - enableSelection={isAllowed} + enableSelection={false} quickAdd={ enableIssueCreation && isAllowed ? ( diff --git a/web/components/issues/issue-layouts/list/block.tsx b/web/components/issues/issue-layouts/list/block.tsx index 42f7afff6..dabcf3a24 100644 --- a/web/components/issues/issue-layouts/list/block.tsx +++ b/web/components/issues/issue-layouts/list/block.tsx @@ -102,6 +102,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => { const isIssueSelected = selectionHelpers.getIsEntitySelected(issue.id); const isIssueActive = selectionHelpers.getIsEntityActive(issue.id); const isSubIssue = nestingLevel !== 0; + const canSelectIssues = canEditIssueProperties && !selectionHelpers.isSelectionDisabled; const marginLeft = `${spacingLeft}px`; @@ -149,7 +150,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
{/* select checkbox */} - {projectId && canEditIssueProperties && ( + {projectId && canSelectIssues && ( diff --git a/web/components/issues/issue-layouts/list/default.tsx b/web/components/issues/issue-layouts/list/default.tsx index daddc572f..321f0640f 100644 --- a/web/components/issues/issue-layouts/list/default.tsx +++ b/web/components/issues/issue-layouts/list/default.tsx @@ -134,7 +134,7 @@ const GroupByList: React.FC = observer((props) => { return (
{groups && ( - + {(helpers) => ( <>
{ const existingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true }; const isGroupSelectionEmpty = selectionHelpers.isGroupSelected(groupID) === "empty"; // auth - const canSelectIssues = canEditProperties(projectId?.toString()); + const canSelectIssues = canEditProperties(projectId?.toString()) && !selectionHelpers.isSelectionDisabled; const handleAddIssuesToView = async (data: ISearchIssueResponse[]) => { if (!workspaceSlug || !projectId) return; @@ -83,7 +83,7 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => { return ( <> -
+
{canSelectIssues && (
{ const subIssuesCount = issueDetail?.sub_issues_count ?? 0; const isIssueSelected = selectionHelpers.getIsEntitySelected(issueDetail.id); + const canSelectIssues = !disableUserActions && !selectionHelpers.isSelectionDisabled; + //TODO: add better logic. This is to have a min width for ID/Key based on the length of project identifier const keyMinWidth = (getProjectIdentifierById(issueDetail.project_id)?.length ?? 0 + 5) * 7; @@ -250,7 +252,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => { >
{/* select checkbox */} - {projectId && !disableUserActions && ( + {projectId && canSelectIssues && ( diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-header.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-header.tsx index 74f65db31..6052454d1 100644 --- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-header.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-header.tsx @@ -38,7 +38,7 @@ export const SpreadsheetHeader = observer((props: Props) => { // derived values const isGroupSelectionEmpty = selectionHelpers.isGroupSelected(SPREADSHEET_SELECT_GROUP) === "empty"; // auth - const canSelectIssues = canEditProperties(projectId?.toString()); + const canSelectIssues = canEditProperties(projectId?.toString()) && !selectionHelpers.isSelectionDisabled; return ( diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx index 8287ea746..169d4f94c 100644 --- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx @@ -81,6 +81,7 @@ export const SpreadsheetView: React.FC = observer((props) => { entities={{ [SPREADSHEET_SELECT_GROUP]: issueIds, }} + disabled > {(helpers) => ( <> diff --git a/web/hooks/use-multiple-select.ts b/web/hooks/use-multiple-select.ts index 47f673624..fdb3c0b1c 100644 --- a/web/hooks/use-multiple-select.ts +++ b/web/hooks/use-multiple-select.ts @@ -10,6 +10,7 @@ export type TEntityDetails = { type Props = { containerRef: React.MutableRefObject; + disabled: boolean; entities: Record; // { groupID: entityIds[] } }; @@ -25,10 +26,11 @@ export type TSelectionHelper = { getIsEntityActive: (entityID: string) => boolean; handleGroupClick: (groupID: string) => void; isGroupSelected: (groupID: string) => "empty" | "partial" | "complete"; + isSelectionDisabled: boolean; }; export const useMultipleSelect = (props: Props) => { - const { containerRef, entities } = props; + const { containerRef, disabled, entities } = props; // router const router = useRouter(); // store hooks @@ -97,6 +99,8 @@ export const useMultipleSelect = (props: Props) => { const handleActiveEntityChange = useCallback( (entityDetails: TEntityDetails | null, shouldScroll: boolean = true) => { + if (disabled) return; + if (!entityDetails) { updateActiveEntityDetails(null); updatePreviousActiveEntity(null); @@ -134,6 +138,7 @@ export const useMultipleSelect = (props: Props) => { }, [ containerRef, + disabled, getPreviousAndNextEntities, updateActiveEntityDetails, updateNextActiveEntity, @@ -147,6 +152,8 @@ export const useMultipleSelect = (props: Props) => { shouldScroll: boolean = true, forceAction: "force-add" | "force-remove" | null = null ) => { + if (disabled) return; + if (Array.isArray(entityDetails)) { bulkUpdateSelectedEntityDetails(entityDetails, forceAction === "force-add" ? "add" : "remove"); if (forceAction === "force-add" && entityDetails.length > 0) { @@ -176,7 +183,13 @@ export const useMultipleSelect = (props: Props) => { handleActiveEntityChange(entityDetails, shouldScroll); } }, - [bulkUpdateSelectedEntityDetails, getIsEntitySelected, handleActiveEntityChange, updateSelectedEntityDetails] + [ + bulkUpdateSelectedEntityDetails, + disabled, + getIsEntitySelected, + handleActiveEntityChange, + updateSelectedEntityDetails, + ] ); /** @@ -187,6 +200,7 @@ export const useMultipleSelect = (props: Props) => { */ const handleEntityClick = useCallback( (e: React.MouseEvent, entityID: string, groupID: string) => { + if (disabled) return; const lastSelectedEntityDetails = getLastSelectedEntityDetails(); if (e.shiftKey && lastSelectedEntityDetails) { const currentEntityIndex = entitiesList.findIndex((entity) => entity?.entityID === entityID); @@ -223,7 +237,7 @@ export const useMultipleSelect = (props: Props) => { handleEntitySelection({ entityID, groupID }, false); }, - [entitiesList, handleEntitySelection, getLastSelectedEntityDetails] + [disabled, entitiesList, handleEntitySelection, getLastSelectedEntityDetails] ); /** @@ -248,15 +262,19 @@ export const useMultipleSelect = (props: Props) => { */ const handleGroupClick = useCallback( (groupID: string) => { + if (disabled) return; + const groupEntities = entitiesList.filter((entity) => entity.groupID === groupID); const groupSelectionStatus = isGroupSelected(groupID); handleEntitySelection(groupEntities, false, groupSelectionStatus === "empty" ? "force-add" : "force-remove"); }, - [entitiesList, handleEntitySelection, isGroupSelected] + [disabled, entitiesList, handleEntitySelection, isGroupSelected] ); // clear selection on escape key press useEffect(() => { + if (disabled) return; + const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") clearSelection(); }; @@ -265,10 +283,12 @@ export const useMultipleSelect = (props: Props) => { return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [clearSelection]); + }, [clearSelection, disabled]); // select entities on shift + arrow up/down key press useEffect(() => { + if (disabled) return; + const handleKeyDown = (e: KeyboardEvent) => { if (!e.shiftKey) return; @@ -291,6 +311,7 @@ export const useMultipleSelect = (props: Props) => { window.removeEventListener("keydown", handleKeyDown); }; }, [ + disabled, getActiveEntityDetails, handleEntitySelection, getLastSelectedEntityDetails, @@ -299,6 +320,8 @@ export const useMultipleSelect = (props: Props) => { ]); useEffect(() => { + if (disabled) return; + const handleKeyDown = (e: KeyboardEvent) => { if (e.shiftKey) return; const activeEntityDetails = getActiveEntityDetails(); @@ -331,7 +354,7 @@ export const useMultipleSelect = (props: Props) => { return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [getActiveEntityDetails, entitiesList, groups, getPreviousAndNextEntities, handleActiveEntityChange]); + }, [disabled, getActiveEntityDetails, entitiesList, groups, getPreviousAndNextEntities, handleActiveEntityChange]); // clear selection on route change useEffect(() => { @@ -346,6 +369,7 @@ export const useMultipleSelect = (props: Props) => { // when entities list change, remove entityIds from the selected entities array, which are not present in the new list useEffect(() => { + if (disabled) return; selectedEntityIds.map((entityID) => { const isEntityPresent = entitiesList.find((en) => en.entityID === entityID); if (!isEntityPresent) { @@ -355,7 +379,7 @@ export const useMultipleSelect = (props: Props) => { } } }); - }, [entitiesList, getEntityDetailsFromEntityID, handleEntitySelection, selectedEntityIds]); + }, [disabled, entitiesList, getEntityDetailsFromEntityID, handleEntitySelection, selectedEntityIds]); /** * @description helper functions for selection @@ -368,8 +392,17 @@ export const useMultipleSelect = (props: Props) => { getIsEntityActive, handleGroupClick, isGroupSelected, + isSelectionDisabled: disabled, }), - [clearSelection, getIsEntityActive, getIsEntitySelected, handleEntityClick, handleGroupClick, isGroupSelected] + [ + clearSelection, + disabled, + getIsEntityActive, + getIsEntitySelected, + handleEntityClick, + handleGroupClick, + isGroupSelected, + ] ); return helpers;