Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 66 additions & 47 deletions web/core/components/issues/issue-detail-widgets/action-buttons.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,93 @@
"use client";

import React, { FC } from "react";
import { Layers, Link, Paperclip, Waypoints } from "lucide-react";
//i18n
// plane imports
import { useTranslation } from "@plane/i18n";
import { TIssueServiceType } from "@plane/types";
// components
import {
IssueAttachmentActionButton,
IssueLinksActionButton,
RelationActionButton,
SubIssuesActionButton,
IssueDetailWidgetButton,
TWorkItemWidgets,
} from "@/components/issues/issue-detail-widgets";

type Props = {
workspaceSlug: string;
projectId: string;
issueId: string;
disabled: boolean;
issueServiceType: TIssueServiceType;
hideWidgets?: TWorkItemWidgets[];
};

export const IssueDetailWidgetActionButtons: FC<Props> = (props) => {
const { workspaceSlug, projectId, issueId, disabled } = props;
const { workspaceSlug, projectId, issueId, disabled, issueServiceType, hideWidgets } = props;
// translation
const { t } = useTranslation();

return (
<div className="flex items-center flex-wrap gap-2">
<SubIssuesActionButton
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("issue.add.sub_issue")}
icon={<Layers className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
/>
<RelationActionButton
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("issue.add.relation")}
icon={<Waypoints className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
/>
<IssueLinksActionButton
customButton={
<IssueDetailWidgetButton
title={t("issue.add.link")}
icon={<Link className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
/>
<IssueAttachmentActionButton
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("common.attach")}
icon={<Paperclip className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
/>
{!hideWidgets?.includes("sub-work-items") && (
<SubIssuesActionButton
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("issue.add.sub_issue")}
icon={<Layers className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{!hideWidgets?.includes("relations") && (
<RelationActionButton
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("issue.add.relation")}
icon={<Waypoints className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{!hideWidgets?.includes("links") && (
<IssueLinksActionButton
customButton={
<IssueDetailWidgetButton
title={t("issue.add.link")}
icon={<Link className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{!hideWidgets?.includes("attachments") && (
<IssueAttachmentActionButton
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issueId}
customButton={
<IssueDetailWidgetButton
title={t("common.attach")}
icon={<Paperclip className="h-3.5 w-3.5 flex-shrink-0" strokeWidth={2} />}
disabled={disabled}
/>
}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import React, { FC, useCallback, useState } from "react";
import { observer } from "mobx-react";
import { FileRejection, useDropzone } from "react-dropzone";
import { Plus } from "lucide-react";
import { EIssueServiceType } from "@plane/constants";
// plane imports
import { TIssueServiceType } from "@plane/types";
// plane ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// hooks
import { useIssueDetail } from "@/hooks/store";
// plane web hooks
import { useFileSize } from "@/plane-web/hooks/use-file-size";

// local imports
import { useAttachmentOperations } from "./helper";

type Props = {
Expand All @@ -21,18 +20,11 @@ type Props = {
issueId: string;
customButton?: React.ReactNode;
disabled?: boolean;
issueServiceType?: TIssueServiceType;
issueServiceType: TIssueServiceType;
};

export const IssueAttachmentActionButton: FC<Props> = observer((props) => {
const {
workspaceSlug,
projectId,
issueId,
customButton,
disabled = false,
issueServiceType = EIssueServiceType.ISSUES,
} = props;
const { workspaceSlug, projectId, issueId, customButton, disabled = false, issueServiceType } = props;
// state
const [isLoading, setIsLoading] = useState(false);
// store hooks
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
import React, { FC } from "react";
import { observer } from "mobx-react";
import { EIssueServiceType } from "@plane/constants";
// plane imports
import { TIssueServiceType } from "@plane/types";
import { Collapsible } from "@plane/ui";
// components
Expand All @@ -17,11 +17,11 @@ type Props = {
projectId: string;
issueId: string;
disabled?: boolean;
issueServiceType?: TIssueServiceType;
issueServiceType: TIssueServiceType;
};

export const AttachmentsCollapsible: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, issueId, disabled = false, issueServiceType = EIssueServiceType.ISSUES } = props;
const { workspaceSlug, projectId, issueId, disabled = false, issueServiceType } = props;
// store hooks
const { openWidgets, toggleOpenWidget } = useIssueDetail(issueServiceType);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"use client";
import React, { FC } from "react";
import { observer } from "mobx-react";
// plane imports
import { TIssueServiceType } from "@plane/types";
// components
import {
AttachmentsCollapsible,
LinksCollapsible,
RelationsCollapsible,
SubIssuesCollapsible,
TWorkItemWidgets,
} from "@/components/issues/issue-detail-widgets";
// hooks
import { useIssueDetail } from "@/hooks/store";
Expand All @@ -19,31 +22,33 @@ type Props = {
projectId: string;
issueId: string;
disabled: boolean;
issueServiceType: TIssueServiceType;
hideWidgets?: TWorkItemWidgets[];
};

export const IssueDetailWidgetCollapsibles: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, issueId, disabled } = props;
const { workspaceSlug, projectId, issueId, disabled, issueServiceType, hideWidgets } = props;
// store hooks
const {
issue: { getIssueById },
subIssues: { subIssuesByIssueId },
attachment: { getAttachmentsCountByIssueId, getAttachmentsUploadStatusByIssueId },
relation: { getRelationCountByIssueId },
} = useIssueDetail();

} = useIssueDetail(issueServiceType);
// derived values
const issue = getIssueById(issueId);
const subIssues = subIssuesByIssueId(issueId);
const ISSUE_RELATION_OPTIONS = useTimeLineRelationOptions();
const issueRelationsCount = getRelationCountByIssueId(issueId, ISSUE_RELATION_OPTIONS);

// render conditions
const shouldRenderSubIssues = !!subIssues && subIssues.length > 0;
const shouldRenderRelations = issueRelationsCount > 0;
const shouldRenderLinks = !!issue?.link_count && issue?.link_count > 0;
const shouldRenderSubIssues = !!subIssues && subIssues.length > 0 && !hideWidgets?.includes("sub-work-items");
const shouldRenderRelations = issueRelationsCount > 0 && !hideWidgets?.includes("relations");
const shouldRenderLinks = !!issue?.link_count && issue?.link_count > 0 && !hideWidgets?.includes("links");
const attachmentUploads = getAttachmentsUploadStatusByIssueId(issueId);
const attachmentsCount = getAttachmentsCountByIssueId(issueId);
const shouldRenderAttachments = attachmentsCount > 0 || (!!attachmentUploads && attachmentUploads.length > 0);
const shouldRenderAttachments =
attachmentsCount > 0 ||
(!!attachmentUploads && attachmentUploads.length > 0 && !hideWidgets?.includes("attachments"));

return (
<div className="flex flex-col">
Expand All @@ -53,23 +58,35 @@ export const IssueDetailWidgetCollapsibles: FC<Props> = observer((props) => {
projectId={projectId}
issueId={issueId}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{shouldRenderRelations && (
<RelationsCollapsible workspaceSlug={workspaceSlug} issueId={issueId} disabled={disabled} />
<RelationsCollapsible
workspaceSlug={workspaceSlug}
issueId={issueId}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{shouldRenderLinks && (
<LinksCollapsible workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} disabled={disabled} />
<LinksCollapsible
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issueId}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}
{shouldRenderAttachments && (
<AttachmentsCollapsible
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issueId}
disabled={disabled}
issueServiceType={issueServiceType}
/>
)}

<WorkItemAdditionalWidgets
workspaceSlug={workspaceSlug}
projectId={projectId}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC } from "react";
import { observer } from "mobx-react";
import { ISearchIssueResponse, TIssue } from "@plane/types";
import { ISearchIssueResponse, TIssue, TIssueServiceType } from "@plane/types";
import { setToast, TOAST_TYPE } from "@plane/ui";
// components
import { ExistingIssuesListModal } from "@/components/core";
Expand All @@ -17,10 +17,11 @@ type Props = {
workspaceSlug: string;
projectId: string;
issueId: string;
issueServiceType: TIssueServiceType;
};

export const IssueDetailWidgetModals: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, issueId } = props;
const { workspaceSlug, projectId, issueId, issueServiceType } = props;
// store hooks
const {
isIssueLinkModalOpen,
Expand Down Expand Up @@ -146,6 +147,7 @@ export const IssueDetailWidgetModals: FC<Props> = observer((props) => {
isModalOpen={isIssueLinkModalOpen}
handleOnClose={handleIssueLinkModalOnClose}
linkOperations={handleLinkOperations}
issueServiceType={issueServiceType}
/>

{shouldRenderCreateUpdateModal && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";
import React, { FC } from "react";
import { EIssueServiceType } from "@plane/constants";
import { TIssueServiceType } from "@plane/types";
// components
import { LinkList } from "../../issue-detail/links";
Expand All @@ -12,11 +11,11 @@ type Props = {
projectId: string;
issueId: string;
disabled: boolean;
issueServiceType?: TIssueServiceType;
issueServiceType: TIssueServiceType;
};

export const IssueLinksCollapsibleContent: FC<Props> = (props) => {
const { workspaceSlug, projectId, issueId, disabled, issueServiceType = EIssueServiceType.ISSUES } = props;
const { workspaceSlug, projectId, issueId, disabled, issueServiceType } = props;

// helper
const handleLinkOperations = useLinkOperations(workspaceSlug, projectId, issueId, issueServiceType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
import React, { FC } from "react";
import { observer } from "mobx-react";
import { Plus } from "lucide-react";
import { EIssueServiceType } from "@plane/constants";
// plane imports
import { TIssueServiceType } from "@plane/types";
// hooks
import { useIssueDetail } from "@/hooks/store";

type Props = {
customButton?: React.ReactNode;
disabled?: boolean;
issueServiceType?: TIssueServiceType;
issueServiceType: TIssueServiceType;
};

export const IssueLinksActionButton: FC<Props> = observer((props) => {
const { customButton, disabled = false, issueServiceType = EIssueServiceType.ISSUES } = props;
const { customButton, disabled = false, issueServiceType } = props;
// store hooks
const { toggleIssueLinkModal } = useIssueDetail(issueServiceType);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
import React, { FC } from "react";
import { observer } from "mobx-react";
import { EIssueServiceType } from "@plane/constants";
// plane imports
import { TIssueServiceType } from "@plane/types";
import { Collapsible } from "@plane/ui";
// components
Expand All @@ -14,14 +14,13 @@ type Props = {
projectId: string;
issueId: string;
disabled?: boolean;
issueServiceType?: TIssueServiceType;
issueServiceType: TIssueServiceType;
};

export const LinksCollapsible: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, issueId, disabled = false, issueServiceType = EIssueServiceType.ISSUES } = props;
const { workspaceSlug, projectId, issueId, disabled = false, issueServiceType } = props;
// store hooks
const { openWidgets, toggleOpenWidget } = useIssueDetail(issueServiceType);

// derived values
const isCollapsibleOpen = openWidgets.includes("links");

Expand Down
Loading