UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: миграция desktop header action-menu на ActionDropdown

This commit is contained in:
DCCONSTRUCTIONS 2026-04-22 12:42:54 +03:00
parent 082948a69c
commit e880daf588
3 changed files with 84 additions and 58 deletions

View File

@ -15,7 +15,8 @@ import { PlusIcon } from "@plane/propel/icons";
import { setPromiseToast } from "@plane/propel/toast";
import type { ISearchIssueResponse, TIssue } from "@plane/types";
import { EIssueLayoutTypes } from "@plane/types";
import { CustomMenu } from "@plane/ui";
import type { TContextMenuItem } from "@plane/ui";
import { ActionDropdown } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
@ -78,6 +79,19 @@ export const CalendarQuickAddIssueActions = observer(function CalendarQuickAddIs
const handleExistingIssue = () => {
setIsExistingIssueModalOpen(true);
};
const actionItems: TContextMenuItem[] = [
{
key: "create-work-item",
action: handleNewIssue,
title: isEpic ? t("epic.add.label") : t("issue.add.label"),
},
{
key: "add-existing-work-item",
action: handleExistingIssue,
title: t("issue.add.existing"),
shouldRender: !isEpic,
},
];
if (!projectId) return null;
@ -117,28 +131,24 @@ export const CalendarQuickAddIssueActions = observer(function CalendarQuickAddIs
}
)}
>
<CustomMenu
<ActionDropdown
items={actionItems}
placement="bottom-start"
menuButtonOnClick={() => setIsMenuOpen(true)}
onMenuClose={() => setIsMenuOpen(false)}
className="w-full"
customButtonClassName="w-full"
customButton={
<div className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-tertiary hover:text-tertiary">
onOpenChange={setIsMenuOpen}
button={
<button
type="button"
className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-tertiary hover:text-tertiary"
>
<PlusIcon className="h-3.5 w-3.5 flex-shrink-0 stroke-2" />
<span className="flex-shrink-0 text-13 font-medium">
{isEpic ? t("epic.add.label") : t("issue.add.label")}
</span>
</div>
</button>
}
>
<CustomMenu.MenuItem onClick={handleNewIssue}>
{isEpic ? t("epic.add.label") : t("issue.add.label")}
</CustomMenu.MenuItem>
{!isEpic && (
<CustomMenu.MenuItem onClick={handleExistingIssue}>{t("issue.add.existing")}</CustomMenu.MenuItem>
)}
</CustomMenu>
buttonAsChild
/>
</div>
}
isEpic={isEpic}

View File

@ -13,7 +13,8 @@ import { PlusIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TIssue, ISearchIssueResponse, TIssueKanbanFilters, TIssueGroupByOptions } from "@plane/types";
// ui
import { CustomMenu } from "@plane/ui";
import type { TContextMenuItem } from "@plane/ui";
import { ActionDropdown } from "@plane/ui";
// components
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
@ -65,6 +66,23 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
const renderExistingIssueModal = moduleId || cycleId;
const ExistingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
const actionItems: TContextMenuItem[] = [
{
key: "create-work-item",
action: () => {
setIsOpen(true);
},
title: "Create work item",
},
{
key: "add-existing-work-item",
action: () => {
setOpenExistingIssueListModal(true);
},
title: "Add an existing work item",
shouldRender: !!renderExistingIssueModal,
},
];
const handleAddIssuesToView = async (data: ISearchIssueResponse[]) => {
if (!workspaceSlug || !projectId) return;
@ -156,29 +174,19 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
{!disableIssueCreation &&
(renderExistingIssueModal ? (
<CustomMenu
customButton={
<span className="flex h-[20px] w-[20px] flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-sm bg-layer-transparent transition-all hover:bg-layer-transparent-hover">
<ActionDropdown
items={actionItems}
button={
<button
type="button"
className="flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm bg-layer-transparent transition-all hover:bg-layer-transparent-hover"
>
<PlusIcon height={14} width={14} strokeWidth={2} />
</span>
</button>
}
buttonAsChild
placement="bottom-end"
>
<CustomMenu.MenuItem
onClick={() => {
setIsOpen(true);
}}
>
<span className="flex items-center justify-start gap-2">Create work item</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
setOpenExistingIssueListModal(true);
}}
>
<span className="flex items-center justify-start gap-2">Add an existing work item</span>
</CustomMenu.MenuItem>
</CustomMenu>
/>
) : (
<button
className="flex h-[20px] w-[20px] flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-sm bg-layer-transparent transition-all hover:bg-layer-transparent-hover"

View File

@ -13,7 +13,8 @@ import { PlusIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TIssue, ISearchIssueResponse, TIssueGroupByOptions } from "@plane/types";
// ui
import { CustomMenu } from "@plane/ui";
import type { TContextMenuItem } from "@plane/ui";
import { ActionDropdown } from "@plane/ui";
// components
import { cn } from "@plane/utils";
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
@ -67,6 +68,23 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
const renderExistingIssueModal = moduleId || cycleId;
const existingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
const isGroupSelectionEmpty = selectionHelpers.isGroupSelected(groupID) === "empty";
const actionItems: TContextMenuItem[] = [
{
key: "create-work-item",
action: () => {
setIsOpen(true);
},
title: "Create work item",
},
{
key: "add-existing-work-item",
action: () => {
setOpenExistingIssueListModal(true);
},
title: "Add an existing work item",
shouldRender: !!renderExistingIssueModal,
},
];
// auth
const canSelectIssues = canEditProperties(projectId?.toString()) && !selectionHelpers.isSelectionDisabled;
@ -127,28 +145,18 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
{!disableIssueCreation &&
(renderExistingIssueModal ? (
<CustomMenu
customButton={
<span className="flex h-5 w-5 flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-xs transition-all hover:bg-layer-1">
<ActionDropdown
items={actionItems}
button={
<button
type="button"
className="flex h-5 w-5 flex-shrink-0 items-center justify-center overflow-hidden rounded-xs transition-all hover:bg-layer-1"
>
<PlusIcon className="h-3.5 w-3.5" strokeWidth={2} />
</span>
</button>
}
>
<CustomMenu.MenuItem
onClick={() => {
setIsOpen(true);
}}
>
<span className="flex items-center justify-start gap-2">Create work item</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={() => {
setOpenExistingIssueListModal(true);
}}
>
<span className="flex items-center justify-start gap-2">Add an existing work item</span>
</CustomMenu.MenuItem>
</CustomMenu>
buttonAsChild
/>
) : (
<div
className="flex h-5 w-5 flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-xs transition-all hover:bg-layer-1"