mirror of
https://github.com/makeplane/plane.git
synced 2026-07-14 14:31:37 +02:00
Merge pull request #1921 from makeplane/sync/ce-ee
Sync: Community Changes
This commit is contained in:
@@ -24,6 +24,8 @@ export type CalendarStoreType =
|
||||
| EIssuesStoreType.MODULE
|
||||
| EIssuesStoreType.CYCLE
|
||||
| EIssuesStoreType.PROJECT_VIEW
|
||||
| EIssuesStoreType.TEAM
|
||||
| EIssuesStoreType.TEAM_VIEW
|
||||
| EIssuesStoreType.EPIC;
|
||||
|
||||
interface IBaseCalendarRoot {
|
||||
@@ -32,13 +34,14 @@ interface IBaseCalendarRoot {
|
||||
isCompletedCycle?: boolean;
|
||||
viewId?: string | undefined;
|
||||
isEpic?: boolean;
|
||||
canEditPropertiesBasedOnProject?: (projectId: string) => boolean;
|
||||
}
|
||||
|
||||
export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
const { QuickActions, addIssuesToView, isCompletedCycle = false, viewId, isEpic = false } = props;
|
||||
const { QuickActions, addIssuesToView, isCompletedCycle = false, viewId, isEpic = false, canEditPropertiesBasedOnProject } = props;
|
||||
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug } = useParams();
|
||||
|
||||
// hooks
|
||||
const storeType = useIssueStoreType() as CalendarStoreType;
|
||||
@@ -63,6 +66,8 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
|
||||
const { enableInlineEditing } = issues?.viewFlags || {};
|
||||
|
||||
const displayFilters = issuesFilter.issueFilters?.displayFilters;
|
||||
|
||||
const groupedIssueIds = (issues.groupedIssueIds ?? {}) as TGroupedIssues;
|
||||
@@ -71,9 +76,7 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
const { startDate, endDate } = issueCalendarView.getStartAndEndDate(layout) ?? {};
|
||||
|
||||
useEffect(() => {
|
||||
startDate &&
|
||||
endDate &&
|
||||
layout &&
|
||||
if (startDate && endDate && layout) {
|
||||
fetchIssues(
|
||||
"init-loader",
|
||||
{
|
||||
@@ -85,21 +88,23 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
},
|
||||
viewId
|
||||
);
|
||||
}
|
||||
}, [fetchIssues, storeType, startDate, endDate, layout, viewId]);
|
||||
|
||||
const handleDragAndDrop = async (
|
||||
issueId: string | undefined,
|
||||
issueProjectId: string | undefined,
|
||||
sourceDate: string | undefined,
|
||||
destinationDate: string | undefined
|
||||
) => {
|
||||
if (!issueId || !destinationDate || !sourceDate) return;
|
||||
if (!issueId || !destinationDate || !sourceDate || !issueProjectId) return;
|
||||
|
||||
await handleDragDrop(
|
||||
issueId,
|
||||
sourceDate,
|
||||
destinationDate,
|
||||
workspaceSlug?.toString(),
|
||||
projectId?.toString(),
|
||||
issueProjectId,
|
||||
updateIssue
|
||||
).catch((err) => {
|
||||
setToast({
|
||||
@@ -127,6 +132,16 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
[issues?.getGroupIssueCount]
|
||||
);
|
||||
|
||||
const canEditProperties = useCallback(
|
||||
(projectId: string | undefined) => {
|
||||
const isEditingAllowedBasedOnProject =
|
||||
canEditPropertiesBasedOnProject && projectId ? canEditPropertiesBasedOnProject(projectId) : isEditingAllowed;
|
||||
|
||||
return enableInlineEditing && isEditingAllowedBasedOnProject;
|
||||
},
|
||||
[canEditPropertiesBasedOnProject, enableInlineEditing, isEditingAllowed]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full w-full overflow-hidden bg-custom-background-100 pt-4">
|
||||
@@ -147,7 +162,7 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
handleRemoveFromView={async () => removeIssueFromView && removeIssueFromView(issue.project_id, issue.id)}
|
||||
handleArchive={async () => archiveIssue && archiveIssue(issue.project_id, issue.id)}
|
||||
handleRestore={async () => restoreIssue && restoreIssue(issue.project_id, issue.id)}
|
||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||
readOnly={!canEditProperties(issue.project_id ?? undefined) || isCompletedCycle}
|
||||
placements={placement}
|
||||
/>
|
||||
)}
|
||||
@@ -156,9 +171,10 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||
getGroupIssueCount={getGroupIssueCount}
|
||||
addIssuesToView={addIssuesToView}
|
||||
quickAddCallback={quickAddIssue}
|
||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||
readOnly={isCompletedCycle}
|
||||
updateFilters={updateFilters}
|
||||
handleDragAndDrop={handleDragAndDrop}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -26,10 +26,10 @@ import { EIssueFilterType, EIssueLayoutTypes, EIssuesStoreType } from "@/constan
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||
// hooks
|
||||
import { useIssues, useUserPermissions } from "@/hooks/store";
|
||||
import { useIssues } from "@/hooks/store";
|
||||
import useSize from "@/hooks/use-window-size";
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// store
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
import { ICycleIssuesFilter } from "@/store/issue/cycle";
|
||||
import { ICalendarStore } from "@/store/issue/issue_calendar_view.store";
|
||||
import { IModuleIssuesFilter } from "@/store/issue/module";
|
||||
@@ -38,7 +38,6 @@ import { IProjectViewIssuesFilter } from "@/store/issue/project-views";
|
||||
import { IssueLayoutHOC } from "../issue-layout-HOC";
|
||||
import { TRenderQuickActions } from "../list/list-view-types";
|
||||
import type { ICalendarWeek } from "./types";
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
|
||||
type Props = {
|
||||
issuesFilterStore:
|
||||
@@ -59,6 +58,7 @@ type Props = {
|
||||
quickActions: TRenderQuickActions;
|
||||
handleDragAndDrop: (
|
||||
issueId: string | undefined,
|
||||
issueProjectId: string | undefined,
|
||||
sourceDate: string | undefined,
|
||||
destinationDate: string | undefined
|
||||
) => Promise<void>;
|
||||
@@ -69,6 +69,7 @@ type Props = {
|
||||
filterType: EIssueFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties | TIssueKanbanFilters
|
||||
) => Promise<void>;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
isEpic?: boolean;
|
||||
};
|
||||
|
||||
@@ -88,6 +89,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
getPaginationData,
|
||||
getGroupIssueCount,
|
||||
updateFilters,
|
||||
canEditProperties,
|
||||
readOnly = false,
|
||||
isEpic = false,
|
||||
} = props;
|
||||
@@ -99,15 +101,10 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
const {
|
||||
issues: { viewFlags },
|
||||
} = useIssues(EIssuesStoreType.PROJECT);
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
const [windowWidth] = useSize();
|
||||
|
||||
const { enableIssueCreation } = viewFlags || {};
|
||||
const isEditingAllowed = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
const { enableIssueCreation, enableQuickAdd } = viewFlags || {};
|
||||
|
||||
const calendarPayload = issueCalendarView.calendarPayload;
|
||||
|
||||
@@ -171,12 +168,13 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
loadMoreIssues={loadMoreIssues}
|
||||
getPaginationData={getPaginationData}
|
||||
getGroupIssueCount={getGroupIssueCount}
|
||||
enableQuickIssueCreate
|
||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||
enableQuickIssueCreate={enableQuickAdd}
|
||||
disableIssueCreation={!enableIssueCreation}
|
||||
quickActions={quickActions}
|
||||
quickAddCallback={quickAddCallback}
|
||||
addIssuesToView={addIssuesToView}
|
||||
readOnly={readOnly}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
))}
|
||||
@@ -194,12 +192,13 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
loadMoreIssues={loadMoreIssues}
|
||||
getPaginationData={getPaginationData}
|
||||
getGroupIssueCount={getGroupIssueCount}
|
||||
enableQuickIssueCreate
|
||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||
enableQuickIssueCreate={enableQuickAdd}
|
||||
disableIssueCreation={!enableIssueCreation}
|
||||
quickActions={quickActions}
|
||||
quickAddCallback={quickAddCallback}
|
||||
addIssuesToView={addIssuesToView}
|
||||
readOnly={readOnly}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
)}
|
||||
@@ -219,11 +218,12 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
getPaginationData={getPaginationData}
|
||||
getGroupIssueCount={getGroupIssueCount}
|
||||
quickActions={quickActions}
|
||||
enableQuickIssueCreate
|
||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||
enableQuickIssueCreate={enableQuickAdd}
|
||||
disableIssueCreation={!enableIssueCreation}
|
||||
quickAddCallback={quickAddCallback}
|
||||
addIssuesToView={addIssuesToView}
|
||||
readOnly={readOnly}
|
||||
canEditProperties={canEditProperties}
|
||||
isDragDisabled
|
||||
isMobileView
|
||||
isEpic={isEpic}
|
||||
@@ -246,11 +246,12 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
||||
loadMoreIssues={loadMoreIssues}
|
||||
getPaginationData={getPaginationData}
|
||||
getGroupIssueCount={getGroupIssueCount}
|
||||
enableQuickIssueCreate
|
||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||
enableQuickIssueCreate={enableQuickAdd}
|
||||
disableIssueCreation={!enableIssueCreation}
|
||||
quickAddCallback={quickAddCallback}
|
||||
addIssuesToView={addIssuesToView}
|
||||
readOnly={readOnly}
|
||||
canEditProperties={canEditProperties}
|
||||
isDragDisabled
|
||||
isMobileView
|
||||
isEpic={isEpic}
|
||||
|
||||
@@ -18,12 +18,12 @@ import { MONTHS_LIST } from "@/constants/calendar";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||
// types
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
import { ICycleIssuesFilter } from "@/store/issue/cycle";
|
||||
import { IModuleIssuesFilter } from "@/store/issue/module";
|
||||
import { IProjectIssuesFilter } from "@/store/issue/project";
|
||||
import { IProjectViewIssuesFilter } from "@/store/issue/project-views";
|
||||
import { TRenderQuickActions } from "../list/list-view-types";
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
|
||||
type Props = {
|
||||
issuesFilterStore:
|
||||
@@ -44,6 +44,7 @@ type Props = {
|
||||
quickActions: TRenderQuickActions;
|
||||
handleDragAndDrop: (
|
||||
issueId: string | undefined,
|
||||
issueProjectId: string | undefined,
|
||||
sourceDate: string | undefined,
|
||||
destinationDate: string | undefined
|
||||
) => Promise<void>;
|
||||
@@ -51,6 +52,7 @@ type Props = {
|
||||
readOnly?: boolean;
|
||||
selectedDate: Date;
|
||||
setSelectedDate: (date: Date) => void;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
isEpic?: boolean;
|
||||
};
|
||||
|
||||
@@ -72,6 +74,7 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
||||
selectedDate,
|
||||
handleDragAndDrop,
|
||||
setSelectedDate,
|
||||
canEditProperties,
|
||||
isEpic = false,
|
||||
} = props;
|
||||
|
||||
@@ -119,7 +122,12 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
||||
}
|
||||
}
|
||||
|
||||
handleDragAndDrop(sourceData?.id, sourceData?.date, destinationData?.date);
|
||||
handleDragAndDrop(
|
||||
sourceData?.id,
|
||||
issueDetails?.project_id ?? undefined,
|
||||
sourceData?.date,
|
||||
destinationData?.date
|
||||
);
|
||||
highlightIssueOnDrop(source?.element?.id, false);
|
||||
},
|
||||
})
|
||||
@@ -184,6 +192,7 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
||||
enableQuickIssueCreate={enableQuickIssueCreate}
|
||||
quickAddCallback={quickAddCallback}
|
||||
readOnly={readOnly}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -16,10 +16,11 @@ type Props = {
|
||||
quickActions: TRenderQuickActions;
|
||||
isDragDisabled: boolean;
|
||||
isEpic?: boolean;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
};
|
||||
|
||||
export const CalendarIssueBlockRoot: React.FC<Props> = observer((props) => {
|
||||
const { issueId, quickActions, isDragDisabled, isEpic = false } = props;
|
||||
const { issueId, quickActions, isDragDisabled, isEpic = false, canEditProperties } = props;
|
||||
|
||||
const issueRef = useRef<HTMLAnchorElement | null>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
@@ -30,6 +31,8 @@ export const CalendarIssueBlockRoot: React.FC<Props> = observer((props) => {
|
||||
|
||||
const issue = getIssueById(issueId);
|
||||
|
||||
const canDrag = !isDragDisabled && canEditProperties(issue?.project_id ?? undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const element = issueRef.current;
|
||||
|
||||
@@ -38,7 +41,7 @@ export const CalendarIssueBlockRoot: React.FC<Props> = observer((props) => {
|
||||
return combine(
|
||||
draggable({
|
||||
element,
|
||||
canDrag: () => !isDragDisabled,
|
||||
canDrag: () => canDrag,
|
||||
getInitialData: () => ({ id: issue?.id, date: issue?.target_date }),
|
||||
onDragStart: () => {
|
||||
setIsDragging(true);
|
||||
@@ -48,7 +51,7 @@ export const CalendarIssueBlockRoot: React.FC<Props> = observer((props) => {
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [issueRef?.current, issue]);
|
||||
}, [issueRef?.current, issue, canDrag]);
|
||||
|
||||
useOutsideClickDetector(issueRef, () => {
|
||||
issueRef?.current?.classList?.remove(HIGHLIGHT_CLASS);
|
||||
|
||||
@@ -22,6 +22,7 @@ type Props = {
|
||||
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||
readOnly?: boolean;
|
||||
isMobileView?: boolean;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
isEpic?: boolean;
|
||||
};
|
||||
|
||||
@@ -38,6 +39,7 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
|
||||
addIssuesToView,
|
||||
readOnly,
|
||||
isMobileView = false,
|
||||
canEditProperties,
|
||||
isEpic = false,
|
||||
} = props;
|
||||
const formattedDatePayload = renderFormattedPayloadDate(date);
|
||||
@@ -65,6 +67,7 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
|
||||
issueId={issueId}
|
||||
quickActions={quickActions}
|
||||
isDragDisabled={isDragDisabled || isMobileView}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// hooks
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store";
|
||||
// plane web constants
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// components
|
||||
import { BaseCalendarRoot } from "../base-calendar-root";
|
||||
|
||||
export const CalendarLayout: React.FC = observer(() => <BaseCalendarRoot QuickActions={ProjectIssueQuickActions} />);
|
||||
export const CalendarLayout: React.FC = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
// derived values
|
||||
const canEditPropertiesBasedOnProject = (projectId: string) =>
|
||||
allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug?.toString(),
|
||||
projectId
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseCalendarRoot
|
||||
QuickActions={ProjectIssueQuickActions}
|
||||
canEditPropertiesBasedOnProject={canEditPropertiesBasedOnProject}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,13 +5,13 @@ import { CalendarDayTile } from "@/components/issues";
|
||||
// helpers
|
||||
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||
// types
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
import { ICycleIssuesFilter } from "@/store/issue/cycle";
|
||||
import { IModuleIssuesFilter } from "@/store/issue/module";
|
||||
import { IProjectIssuesFilter } from "@/store/issue/project";
|
||||
import { IProjectViewIssuesFilter } from "@/store/issue/project-views";
|
||||
import { TRenderQuickActions } from "../list/list-view-types";
|
||||
import { ICalendarDate, ICalendarWeek } from "./types";
|
||||
import { IProjectEpicsFilter } from "@/plane-web/store/issue/epic";
|
||||
|
||||
type Props = {
|
||||
issuesFilterStore:
|
||||
@@ -32,6 +32,7 @@ type Props = {
|
||||
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
|
||||
handleDragAndDrop: (
|
||||
issueId: string | undefined,
|
||||
issueProjectId: string | undefined,
|
||||
sourceDate: string | undefined,
|
||||
destinationDate: string | undefined
|
||||
) => Promise<void>;
|
||||
@@ -39,6 +40,7 @@ type Props = {
|
||||
readOnly?: boolean;
|
||||
selectedDate: Date;
|
||||
setSelectedDate: (date: Date) => void;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
isEpic?: boolean;
|
||||
};
|
||||
|
||||
@@ -60,6 +62,7 @@ export const CalendarWeekDays: React.FC<Props> = observer((props) => {
|
||||
readOnly = false,
|
||||
selectedDate,
|
||||
setSelectedDate,
|
||||
canEditProperties,
|
||||
isEpic = false,
|
||||
} = props;
|
||||
|
||||
@@ -96,6 +99,7 @@ export const CalendarWeekDays: React.FC<Props> = observer((props) => {
|
||||
addIssuesToView={addIssuesToView}
|
||||
readOnly={readOnly}
|
||||
handleDragAndDrop={handleDragAndDrop}
|
||||
canEditProperties={canEditProperties}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -134,6 +134,13 @@ export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
||||
values={value}
|
||||
/>
|
||||
)}
|
||||
{filterKey === "team_project" && (
|
||||
<AppliedProjectFilters
|
||||
editable={isEditingAllowed}
|
||||
handleRemove={(val) => handleRemoveFilter("team_project", val)}
|
||||
values={value}
|
||||
/>
|
||||
)}
|
||||
{isEditingAllowed && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -25,7 +25,7 @@ import { ILayoutDisplayFiltersOptions } from "@/constants/issue";
|
||||
// hooks
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web components
|
||||
import { FilterIssueTypes } from "@/plane-web/components/issues";
|
||||
import { FilterIssueTypes, FilterTeamProjects } from "@/plane-web/components/issues";
|
||||
|
||||
type Props = {
|
||||
filters: IIssueFilterOptions;
|
||||
@@ -208,6 +208,18 @@ export const FilterSelection: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* team project */}
|
||||
{isFilterEnabled("team_project") && (
|
||||
<div className="py-2">
|
||||
<FilterTeamProjects
|
||||
appliedFilters={filters.team_project ?? null}
|
||||
handleUpdate={(val) => handleFiltersUpdate("team_project", val)}
|
||||
searchQuery={filtersSearchQuery}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* issue type */}
|
||||
{isDisplayFilterEnabled("type") && displayFilters && handleDisplayFiltersUpdate && (
|
||||
<div className="py-2">
|
||||
|
||||
@@ -6,6 +6,7 @@ import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element
|
||||
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import { EIssueServiceType } from "@plane/constants";
|
||||
import { DeleteIssueModal } from "@/components/issues";
|
||||
//constants
|
||||
import { ISSUE_DELETED } from "@/constants/event-tracker";
|
||||
@@ -25,7 +26,6 @@ import { IQuickActionProps, TRenderQuickActions } from "../list/list-view-types"
|
||||
import { getSourceFromDropPayload } from "../utils";
|
||||
import { KanBan } from "./default";
|
||||
import { KanBanSwimLanes } from "./swimlanes";
|
||||
import { EIssueServiceType } from "@plane/constants";
|
||||
|
||||
export type KanbanStoreType =
|
||||
| EIssuesStoreType.PROJECT
|
||||
@@ -34,6 +34,8 @@ export type KanbanStoreType =
|
||||
| EIssuesStoreType.PROJECT_VIEW
|
||||
| EIssuesStoreType.DRAFT
|
||||
| EIssuesStoreType.PROFILE
|
||||
| EIssuesStoreType.TEAM
|
||||
| EIssuesStoreType.TEAM_VIEW
|
||||
| EIssuesStoreType.EPIC;
|
||||
|
||||
export interface IBaseKanBanLayout {
|
||||
@@ -187,11 +189,11 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
||||
handleRemoveFromView={async () => removeIssueFromView && removeIssueFromView(issue.project_id, issue.id)}
|
||||
handleArchive={async () => archiveIssue && archiveIssue(issue.project_id, issue.id)}
|
||||
handleRestore={async () => restoreIssue && restoreIssue(issue.project_id, issue.id)}
|
||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||
readOnly={!canEditProperties(issue.project_id ?? undefined) || isCompletedCycle}
|
||||
/>
|
||||
),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[isEditingAllowed, isCompletedCycle, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
[isCompletedCycle, canEditProperties, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
);
|
||||
|
||||
const handleDeleteIssue = async () => {
|
||||
|
||||
@@ -36,6 +36,7 @@ interface IssueBlockProps {
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
draggableId: string;
|
||||
canDropOverIssue: boolean;
|
||||
canDragIssuesInCurrentGrouping: boolean;
|
||||
updateIssue: ((projectId: string | null, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
|
||||
quickActions: TRenderQuickActions;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
@@ -115,6 +116,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
|
||||
issuesMap,
|
||||
displayProperties,
|
||||
canDropOverIssue,
|
||||
canDragIssuesInCurrentGrouping,
|
||||
updateIssue,
|
||||
quickActions,
|
||||
canEditProperties,
|
||||
@@ -144,7 +146,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
|
||||
|
||||
const canEditIssueProperties = canEditProperties(issue?.project_id ?? undefined);
|
||||
|
||||
const isDragAllowed = !issue?.tempId && canEditIssueProperties;
|
||||
const isDragAllowed = canDragIssuesInCurrentGrouping && !issue?.tempId && canEditIssueProperties;
|
||||
|
||||
useOutsideClickDetector(cardRef, () => {
|
||||
cardRef?.current?.classList?.remove(HIGHLIGHT_CLASS);
|
||||
@@ -200,12 +202,15 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
|
||||
className={cn("group/kanban-block relative mb-2", { "z-[1]": isCurrentBlockDragging })}
|
||||
onDragStart={() => {
|
||||
if (isDragAllowed) setIsCurrentBlockDragging(true);
|
||||
else
|
||||
else {
|
||||
setToast({
|
||||
type: TOAST_TYPE.WARNING,
|
||||
title: "Cannot move issue",
|
||||
message: "Drag and drop is disabled for the current grouping",
|
||||
message: !canEditIssueProperties
|
||||
? "You are not allowed to move this issue"
|
||||
: "Drag and drop is disabled for the current grouping",
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ControlLink
|
||||
|
||||
@@ -16,6 +16,7 @@ interface IssueBlocksListProps {
|
||||
quickActions: TRenderQuickActions;
|
||||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
canDropOverIssue: boolean;
|
||||
canDragIssuesInCurrentGrouping: boolean;
|
||||
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||
isEpic?: boolean;
|
||||
}
|
||||
@@ -28,6 +29,7 @@ export const KanbanIssueBlocksList: React.FC<IssueBlocksListProps> = observer((p
|
||||
issueIds,
|
||||
displayProperties,
|
||||
canDropOverIssue,
|
||||
canDragIssuesInCurrentGrouping,
|
||||
updateIssue,
|
||||
quickActions,
|
||||
canEditProperties,
|
||||
@@ -59,6 +61,7 @@ export const KanbanIssueBlocksList: React.FC<IssueBlocksListProps> = observer((p
|
||||
quickActions={quickActions}
|
||||
draggableId={draggableId}
|
||||
canDropOverIssue={canDropOverIssue}
|
||||
canDragIssuesInCurrentGrouping={canDragIssuesInCurrentGrouping}
|
||||
canEditProperties={canEditProperties}
|
||||
scrollableContainerRef={scrollableContainerRef}
|
||||
isEpic={isEpic}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { KanbanQuickAddIssueButton, QuickAddIssueRoot } from "@/components/issue
|
||||
import { highlightIssueOnDrop } from "@/components/issues/issue-layouts/utils";
|
||||
import { KanbanIssueBlockLoader } from "@/components/ui";
|
||||
// helpers
|
||||
import { EIssueLayoutTypes } from "@/constants/issue";
|
||||
import { DRAG_ALLOWED_GROUPS, EIssueLayoutTypes } from "@/constants/issue";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useProjectState } from "@/hooks/store";
|
||||
@@ -260,6 +260,10 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
|
||||
const shouldLoadMore = nextPageResults === undefined ? issueIds?.length < groupIssueCount : !!nextPageResults;
|
||||
const canOverlayBeVisible = isWorkflowDropDisabled || orderBy !== "sort_order" || isDropDisabled;
|
||||
const shouldOverlayBeVisible = isDraggingOverColumn && canOverlayBeVisible;
|
||||
const canDragIssuesInCurrentGrouping =
|
||||
!!group_by &&
|
||||
DRAG_ALLOWED_GROUPS.includes(group_by) &&
|
||||
(!!sub_group_by ? DRAG_ALLOWED_GROUPS.includes(sub_group_by) : true);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -291,6 +295,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
|
||||
canEditProperties={canEditProperties}
|
||||
scrollableContainerRef={scrollableContainerRef}
|
||||
canDropOverIssue={!canOverlayBeVisible}
|
||||
canDragIssuesInCurrentGrouping={canDragIssuesInCurrentGrouping}
|
||||
isEpic={isEpic}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,9 +1,32 @@
|
||||
import { observer } from "mobx-react";
|
||||
// mobx store
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
import { useParams } from "next/navigation";
|
||||
// components
|
||||
// types
|
||||
// constants
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store";
|
||||
// plane web constants
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// local components
|
||||
import { BaseKanBanRoot } from "../base-kanban-root";
|
||||
|
||||
export const KanBanLayout: React.FC = observer(() => <BaseKanBanRoot QuickActions={ProjectIssueQuickActions} />);
|
||||
export const KanBanLayout: React.FC = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
// derived values
|
||||
const canEditPropertiesBasedOnProject = (projectId: string) =>
|
||||
allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug?.toString(),
|
||||
projectId
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseKanBanRoot
|
||||
QuickActions={ProjectIssueQuickActions}
|
||||
canEditPropertiesBasedOnProject={canEditPropertiesBasedOnProject}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -27,6 +27,8 @@ type ListStoreType =
|
||||
| EIssuesStoreType.PROFILE
|
||||
| EIssuesStoreType.ARCHIVED
|
||||
| EIssuesStoreType.WORKSPACE_DRAFT
|
||||
| EIssuesStoreType.TEAM
|
||||
| EIssuesStoreType.TEAM_VIEW
|
||||
| EIssuesStoreType.EPIC;
|
||||
|
||||
interface IBaseListRoot {
|
||||
@@ -110,11 +112,11 @@ export const BaseListRoot = observer((props: IBaseListRoot) => {
|
||||
handleRemoveFromView={async () => removeIssueFromView && removeIssueFromView(issue.project_id, issue.id)}
|
||||
handleArchive={async () => archiveIssue && archiveIssue(issue.project_id, issue.id)}
|
||||
handleRestore={async () => restoreIssue && restoreIssue(issue.project_id, issue.id)}
|
||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||
readOnly={!canEditProperties(issue.project_id ?? undefined) || isCompletedCycle}
|
||||
/>
|
||||
),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[isEditingAllowed, isCompletedCycle, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
[isCompletedCycle, canEditProperties, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
);
|
||||
|
||||
const loadMoreIssues = useCallback(
|
||||
|
||||
@@ -93,8 +93,11 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
||||
isArchived: !!issue.archived_at,
|
||||
});
|
||||
|
||||
// derived values
|
||||
const issue = issuesMap[issueId];
|
||||
const subIssuesCount = issue?.sub_issues_count ?? 0;
|
||||
const canEditIssueProperties = canEditProperties(issue?.project_id ?? undefined);
|
||||
const isDraggingAllowed = canDrag && canEditIssueProperties;
|
||||
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
||||
@@ -106,7 +109,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
||||
return combine(
|
||||
draggable({
|
||||
element,
|
||||
canDrag: () => canDrag,
|
||||
canDrag: () => isDraggingAllowed,
|
||||
getInitialData: () => ({ id: issueId, type: "ISSUE", groupId }),
|
||||
onDragStart: () => {
|
||||
setIsCurrentBlockDragging(true);
|
||||
@@ -116,11 +119,10 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [canDrag, issueId, groupId, setIsCurrentBlockDragging]);
|
||||
}, [isDraggingAllowed, issueId, groupId, setIsCurrentBlockDragging]);
|
||||
|
||||
if (!issue) return null;
|
||||
|
||||
const canEditIssueProperties = canEditProperties(issue.project_id ?? undefined);
|
||||
const projectIdentifier = getProjectIdentifierById(issue.project_id);
|
||||
const isIssueSelected = selectionHelpers.getIsEntitySelected(issue.id);
|
||||
const isIssueActive = selectionHelpers.getIsEntityActive(issue.id);
|
||||
@@ -169,11 +171,13 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
||||
}
|
||||
)}
|
||||
onDragStart={() => {
|
||||
if (!canDrag) {
|
||||
if (!isDraggingAllowed) {
|
||||
setToast({
|
||||
type: TOAST_TYPE.WARNING,
|
||||
title: "Cannot move issue",
|
||||
message: "Drag and drop is disabled for the current grouping",
|
||||
message: !canEditIssueProperties
|
||||
? "You are not allowed to move this issue"
|
||||
: "Drag and drop is disabled for the current grouping",
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
||||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { cn } from "@plane/editor";
|
||||
// plane packages
|
||||
import {
|
||||
@@ -100,7 +99,6 @@ export const ListGroup = observer((props: Props) => {
|
||||
const isExpanded = !collapsedGroups?.group_by.includes(group.id);
|
||||
const groupRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const { projectId } = useParams();
|
||||
const projectState = useProjectState();
|
||||
|
||||
const {
|
||||
@@ -239,8 +237,7 @@ export const ListGroup = observer((props: Props) => {
|
||||
isWorkflowDropDisabled,
|
||||
]);
|
||||
|
||||
const isDragAllowed =
|
||||
!!group_by && DRAG_ALLOWED_GROUPS.includes(group_by) && canEditProperties(projectId?.toString());
|
||||
const isDragAllowed = !!group_by && DRAG_ALLOWED_GROUPS.includes(group_by);
|
||||
const canOverlayBeVisible = isWorkflowDropDisabled || orderBy !== "sort_order" || !!group.isDropDisabled;
|
||||
|
||||
const isGroupByCreatedBy = group_by === "created_by";
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// hooks
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// components
|
||||
// types
|
||||
// constants
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store";
|
||||
// plane web constants
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// components
|
||||
import { BaseListRoot } from "../base-list-root";
|
||||
|
||||
export const ListLayout: FC = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
if (!workspaceSlug || !projectId) return null;
|
||||
if (!workspaceSlug) return null;
|
||||
|
||||
const canEditPropertiesBasedOnProject = (projectId: string) =>
|
||||
allowPermissions(
|
||||
|
||||
@@ -56,7 +56,12 @@ export const ProjectIssueQuickActions: React.FC<IQuickActionProps> = observer((p
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
// auth
|
||||
const isEditingAllowed =
|
||||
allowPermissions([EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.PROJECT) && !readOnly;
|
||||
allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug?.toString(),
|
||||
issue.project_id ?? undefined
|
||||
) && !readOnly;
|
||||
const isArchivingAllowed = handleArchive && isEditingAllowed;
|
||||
const isInArchivableGroup = !!stateDetails && ARCHIVABLE_STATE_GROUPS.includes(stateDetails?.group);
|
||||
const isDeletingAllowed = isEditingAllowed;
|
||||
|
||||
@@ -25,6 +25,8 @@ export type SpreadsheetStoreType =
|
||||
| EIssuesStoreType.MODULE
|
||||
| EIssuesStoreType.CYCLE
|
||||
| EIssuesStoreType.PROJECT_VIEW
|
||||
| EIssuesStoreType.TEAM
|
||||
| EIssuesStoreType.TEAM_VIEW
|
||||
| EIssuesStoreType.EPIC;
|
||||
|
||||
interface IBaseSpreadsheetRoot {
|
||||
@@ -102,11 +104,11 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
|
||||
handleArchive={async () => archiveIssue && archiveIssue(issue.project_id, issue.id)}
|
||||
handleRestore={async () => restoreIssue && restoreIssue(issue.project_id, issue.id)}
|
||||
portalElement={portalElement}
|
||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||
readOnly={!canEditProperties(issue.project_id ?? undefined) || isCompletedCycle}
|
||||
placements={placement}
|
||||
/>
|
||||
),
|
||||
[isEditingAllowed, isCompletedCycle, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
[isCompletedCycle, canEditProperties, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
|
||||
);
|
||||
|
||||
if (!Array.isArray(issueIds)) return null;
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// mobx store
|
||||
import { ProjectIssueQuickActions } from "../../quick-action-dropdowns";
|
||||
import { useParams } from "next/navigation";
|
||||
// components
|
||||
import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store";
|
||||
// plane web constants
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
// local components
|
||||
import { BaseSpreadsheetRoot } from "../base-spreadsheet-root";
|
||||
|
||||
export const ProjectSpreadsheetLayout: React.FC = observer(() => (
|
||||
<BaseSpreadsheetRoot QuickActions={ProjectIssueQuickActions} />
|
||||
));
|
||||
export const ProjectSpreadsheetLayout: React.FC = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
// derived values
|
||||
const canEditPropertiesBasedOnProject = (projectId: string) =>
|
||||
allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug?.toString(),
|
||||
projectId
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseSpreadsheetRoot
|
||||
QuickActions={ProjectIssueQuickActions}
|
||||
canEditPropertiesBasedOnProject={canEditPropertiesBasedOnProject}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use-client";
|
||||
import { FC, useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// types
|
||||
import { TNameDescriptionLoader } from "@plane/types";
|
||||
// components
|
||||
import { IssueParentDetail, TIssueOperations } from "@/components/issues";
|
||||
// helpers
|
||||
@@ -25,8 +27,8 @@ interface IPeekOverviewIssueDetails {
|
||||
issueOperations: TIssueOperations;
|
||||
disabled: boolean;
|
||||
isArchived: boolean;
|
||||
isSubmitting: "submitting" | "submitted" | "saved";
|
||||
setIsSubmitting: (value: "submitting" | "submitted" | "saved") => void;
|
||||
isSubmitting: TNameDescriptionLoader;
|
||||
setIsSubmitting: (value: TNameDescriptionLoader) => void;
|
||||
}
|
||||
|
||||
export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = observer((props) => {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { FC, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { EIssueServiceType } from "@plane/constants";
|
||||
// types
|
||||
import { TNameDescriptionLoader } from "@plane/types";
|
||||
// components
|
||||
import {
|
||||
DeleteIssueModal,
|
||||
IssuePeekOverviewHeader,
|
||||
@@ -50,7 +53,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
||||
} = props;
|
||||
// states
|
||||
const [peekMode, setPeekMode] = useState<TPeekModes>("side-peek");
|
||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||
const [isSubmitting, setIsSubmitting] = useState<TNameDescriptionLoader>("saved");
|
||||
// ref
|
||||
const issuePeekOverviewRef = useRef<HTMLDivElement>(null);
|
||||
// store hooks
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { FC, useState, useEffect, useCallback } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { TNameDescriptionLoader } from "@plane/types";
|
||||
// components
|
||||
import { TextArea } from "@plane/ui";
|
||||
// types
|
||||
@@ -14,8 +15,8 @@ export type IssueTitleInputProps = {
|
||||
disabled?: boolean;
|
||||
value: string | undefined | null;
|
||||
workspaceSlug: string;
|
||||
isSubmitting: "submitting" | "submitted" | "saved";
|
||||
setIsSubmitting: (value: "submitting" | "submitted" | "saved") => void;
|
||||
isSubmitting: TNameDescriptionLoader;
|
||||
setIsSubmitting: (value: TNameDescriptionLoader) => void;
|
||||
issueOperations: TIssueOperations;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
|
||||
@@ -61,7 +61,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
||||
<div className="grow">
|
||||
<div className="pb-1 text-base font-medium text-custom-text-100">Property changes</div>
|
||||
<div className="text-sm font-normal text-custom-text-300">
|
||||
Notify me when issue's properties like assignees, priority, estimates or anything else changes.
|
||||
Notify me when issue's properties like assignees, priority, estimates or anything else changes.
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
|
||||
@@ -19,7 +19,7 @@ type DNDStoreType =
|
||||
| EIssuesStoreType.ARCHIVED
|
||||
| EIssuesStoreType.WORKSPACE_DRAFT
|
||||
| EIssuesStoreType.TEAM
|
||||
| EIssuesStoreType.TEAM_VIEW;
|
||||
| EIssuesStoreType.TEAM_VIEW
|
||||
| EIssuesStoreType.EPIC;
|
||||
|
||||
export const useGroupIssuesDragNDrop = (
|
||||
|
||||
Reference in New Issue
Block a user