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
1 change: 1 addition & 0 deletions web/ce/components/issues/issue-details/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./issue-identifier";
export * from "./issue-properties-activity";
export * from "./issue-type-switcher";
export * from "./issue-type-activity";
export * from "./parent-select-root";
82 changes: 82 additions & 0 deletions web/ce/components/issues/issue-details/parent-select-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";

import React from "react";
import { observer } from "mobx-react";
import { useTranslation } from "@plane/i18n";
// ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { IssueParentSelect, TIssueOperations } from "@/components/issues";
// hooks
import { useIssueDetail } from "@/hooks/store";

type TIssueParentSelect = {
className?: string;
disabled?: boolean;
issueId: string;
issueOperations: TIssueOperations;
projectId: string;
workspaceSlug: string;
};

export const IssueParentSelectRoot: React.FC<TIssueParentSelect> = observer((props) => {
const { issueId, issueOperations, projectId, workspaceSlug } = props;
const { t } = useTranslation();
// store hooks
const {
issue: { getIssueById },
} = useIssueDetail();
const {
toggleParentIssueModal,
removeSubIssue,
subIssues: { setSubIssueHelpers, fetchSubIssues },
} = useIssueDetail();

// derived values
const issue = getIssueById(issueId);
const parentIssue = issue?.parent_id ? getIssueById(issue.parent_id) : undefined;

const handleParentIssue = async (_issueId: string | null = null) => {
try {
await issueOperations.update(workspaceSlug, projectId, issueId, { parent_id: _issueId });
await issueOperations.fetch(workspaceSlug, projectId, issueId, false);
if (_issueId) await fetchSubIssues(workspaceSlug, projectId, _issueId);
toggleParentIssueModal(null);
} catch (error) {
console.error("something went wrong while fetching the issue");
}
};

const handleRemoveSubIssue = async (
workspaceSlug: string,
projectId: string,
parentIssueId: string,
issueId: string
) => {
try {
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
await removeSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
await fetchSubIssues(workspaceSlug, projectId, parentIssueId);
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
} catch (error) {
setToast({
type: TOAST_TYPE.ERROR,
title: t("common.error.label"),
message: t("common.something_went_wrong"),
});
}
};

const workItemLink = `/${workspaceSlug}/projects/${parentIssue?.project_id}/issues/${parentIssue?.id}`;

if (!issue) return <></>;

return (
<IssueParentSelect
{...props}
handleParentIssue={handleParentIssue}
handleRemoveSubIssue={handleRemoveSubIssue}
workItemLink={workItemLink}
/>
);
});
67 changes: 21 additions & 46 deletions web/core/components/issues/issue-detail/parent-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Link from "next/link";
import { Pencil, X } from "lucide-react";
import { useTranslation } from "@plane/i18n";
// ui
import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
import { Tooltip } from "@plane/ui";
// components
import { ParentIssuesListModal } from "@/components/issues";
// helpers
Expand All @@ -17,68 +17,48 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
import { TIssueOperations } from "./root";

type TIssueParentSelect = {
className?: string;
disabled?: boolean;
issueId: string;
issueOperations: TIssueOperations;
projectId: string;
workspaceSlug: string;
handleParentIssue: (_issueId?: string | null) => Promise<void>;
handleRemoveSubIssue: (
workspaceSlug: string,
projectId: string,
parentIssueId: string,
issueId: string
) => Promise<void>;
workItemLink: string;
};

export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props) => {
const { className = "", disabled = false, issueId, issueOperations, projectId, workspaceSlug } = props;
const {
className = "",
disabled = false,
issueId,
projectId,
workspaceSlug,
handleParentIssue,
handleRemoveSubIssue,
workItemLink,
} = props;
const { t } = useTranslation();
// store hooks
const { getProjectById } = useProject();
const {
issue: { getIssueById },
} = useIssueDetail();
const {
isParentIssueModalOpen,
toggleParentIssueModal,
removeSubIssue,
subIssues: { setSubIssueHelpers, fetchSubIssues },
} = useIssueDetail();
const { isParentIssueModalOpen, toggleParentIssueModal } = useIssueDetail();

// derived values
const issue = getIssueById(issueId);
const parentIssue = issue?.parent_id ? getIssueById(issue.parent_id) : undefined;
const parentIssueProjectDetails =
parentIssue && parentIssue.project_id ? getProjectById(parentIssue.project_id) : undefined;
const { isMobile } = usePlatformOS();
const handleParentIssue = async (_issueId: string | null = null) => {
try {
await issueOperations.update(workspaceSlug, projectId, issueId, { parent_id: _issueId });
await issueOperations.fetch(workspaceSlug, projectId, issueId, false);
_issueId && (await fetchSubIssues(workspaceSlug, projectId, _issueId));
toggleParentIssueModal(null);
} catch (error) {
console.error("something went wrong while fetching the issue");
}
};

const handleRemoveSubIssue = async (
workspaceSlug: string,
projectId: string,
parentIssueId: string,
issueId: string
) => {
try {
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
await removeSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
await fetchSubIssues(workspaceSlug, projectId, parentIssueId);
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
} catch (error) {
setToast({
type: TOAST_TYPE.ERROR,
title: t("common.error.label"),
message: t("common.something_went_wrong"),
});
}
};

if (!issue) return <></>;

Expand Down Expand Up @@ -109,12 +89,7 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
{issue.parent_id && parentIssue ? (
<div className="flex items-center gap-1 bg-green-500/20 rounded px-1.5 py-1">
<Tooltip tooltipHeading="Title" tooltipContent={parentIssue.name} isMobile={isMobile}>
<Link
href={`/${workspaceSlug}/projects/${parentIssue.project_id}/issues/${parentIssue?.id}`}
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
>
<Link href={workItemLink} target="_blank" rel="noopener noreferrer" onClick={(e) => e.stopPropagation()}>
{parentIssue?.project_id && parentIssueProjectDetails && (
<IssueIdentifier
projectId={parentIssue.project_id}
Expand Down
9 changes: 8 additions & 1 deletion web/core/components/issues/issue-detail/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import { FC, useMemo } from "react";
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
// types
import { EIssuesStoreType, ISSUE_UPDATED, ISSUE_DELETED, ISSUE_ARCHIVED,EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import {
EIssuesStoreType,
ISSUE_UPDATED,
ISSUE_DELETED,
ISSUE_ARCHIVED,
EUserPermissions,
EUserPermissionsLevel,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { TIssue } from "@plane/types";
// ui
Expand Down
6 changes: 3 additions & 3 deletions web/core/components/issues/issue-detail/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
StateDropdown,
} from "@/components/dropdowns";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { IssueCycleSelect, IssueLabel, IssueModuleSelect, IssueParentSelect } from "@/components/issues";
import { IssueCycleSelect, IssueLabel, IssueModuleSelect } from "@/components/issues";
// helpers
import { cn } from "@/helpers/common.helper";
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
Expand All @@ -25,7 +25,7 @@ import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
import { useProjectEstimates, useIssueDetail, useProject, useProjectState, useMember } from "@/hooks/store";
// plane web components
import { IssueAdditionalPropertyValuesUpdate } from "@/plane-web/components/issue-types/values";
import { IssueWorklogProperty } from "@/plane-web/components/issues";
import { IssueParentSelectRoot, IssueWorklogProperty } from "@/plane-web/components/issues";
// components
import type { TIssueOperations } from "./root";

Expand Down Expand Up @@ -261,7 +261,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
<LayoutPanelTop className="h-4 w-4 flex-shrink-0" />
<span>{t("common.parent")}</span>
</div>
<IssueParentSelect
<IssueParentSelectRoot
className="h-full w-3/5 flex-grow"
workspaceSlug={workspaceSlug}
projectId={projectId}
Expand Down
12 changes: 3 additions & 9 deletions web/core/components/issues/peek-overview/properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,15 @@ import {
StateDropdown,
} from "@/components/dropdowns";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import {
IssueCycleSelect,
IssueModuleSelect,
IssueParentSelect,
IssueLabel,
TIssueOperations,
} from "@/components/issues";
import { IssueCycleSelect, IssueModuleSelect, IssueLabel, TIssueOperations } from "@/components/issues";
// helpers
import { cn } from "@/helpers/common.helper";
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
import { useIssueDetail, useMember, useProject, useProjectState } from "@/hooks/store";
// plane web components
import { IssueAdditionalPropertyValuesUpdate } from "@/plane-web/components/issue-types/values";
import { IssueWorklogProperty } from "@/plane-web/components/issues";
import { IssueParentSelectRoot, IssueWorklogProperty } from "@/plane-web/components/issues";

interface IPeekOverviewProperties {
workspaceSlug: string;
Expand Down Expand Up @@ -269,7 +263,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
<LayoutPanelTop className="h-4 w-4 flex-shrink-0" />
<p>{t("common.parent")}</p>
</div>
<IssueParentSelect
<IssueParentSelectRoot
className="w-3/4 flex-grow h-full"
disabled={disabled}
issueId={issueId}
Expand Down
1 change: 1 addition & 0 deletions web/ee/components/issues/issue-details/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./issue-identifier";
export * from "./issue-properties-activity";
export * from "./issue-type-switcher";
export * from "./issue-type-activity";
export * from "./parent-select-root";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "ce/components/issues/issue-details/parent-select-root";