mirror of
https://github.com/makeplane/plane.git
synced 2025-12-25 08:09:33 +01:00
* feat: meta endpoint for issue * chore: add detail endpoint * chore: getIssueMetaFromURL and retrieveWithIdentifier endpoint added * chore: issue store updated * chore: move issue detail to new route and add redirection for old route * fix: issue details permission * fix: work item detail header * chore: generateWorkItemLink helper function added * chore: copyTextToClipboard helper function updated * chore: workItemLink updated * chore: workItemLink updated * chore: workItemLink updated * fix: issues navigation tab active status * fix: invalid workitem error state * chore: peek view parent issue redirection improvement * fix: issue detail endpoint to not return epics and intake issue * fix: workitem empty state redirection and header * fix: workitem empty state redirection and header * chore: code refactor * chore: project auth wrapper improvement --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
"use client";
|
|
import React, { FC, useState } from "react";
|
|
import { observer } from "mobx-react";
|
|
// helpers
|
|
import { generateWorkItemLink } from "@/helpers/issue.helper";
|
|
import { copyUrlToClipboard } from "@/helpers/string.helper";
|
|
// hooks
|
|
import { useIssueDetail, useProject } from "@/hooks/store";
|
|
|
|
type TCreateIssueToastActionItems = {
|
|
workspaceSlug: string;
|
|
projectId: string;
|
|
issueId: string;
|
|
isEpic?: boolean;
|
|
};
|
|
|
|
export const CreateIssueToastActionItems: FC<TCreateIssueToastActionItems> = observer((props) => {
|
|
const { workspaceSlug, projectId, issueId, isEpic = false } = props;
|
|
// state
|
|
const [copied, setCopied] = useState(false);
|
|
// store hooks
|
|
const {
|
|
issue: { getIssueById },
|
|
} = useIssueDetail();
|
|
const { getProjectIdentifierById } = useProject();
|
|
|
|
// derived values
|
|
const issue = getIssueById(issueId);
|
|
const projectIdentifier = getProjectIdentifierById(issue?.project_id);
|
|
|
|
if (!issue) return null;
|
|
|
|
const workItemLink = generateWorkItemLink({
|
|
workspaceSlug,
|
|
projectId: issue?.project_id,
|
|
issueId,
|
|
projectIdentifier,
|
|
sequenceId: issue?.sequence_id,
|
|
isEpic,
|
|
});
|
|
|
|
const copyToClipboard = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
try {
|
|
await copyUrlToClipboard(workItemLink, false);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 3000);
|
|
} catch (error) {
|
|
setCopied(false);
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
};
|
|
|
|
return (
|
|
<div className="flex items-center gap-1 text-xs text-custom-text-200">
|
|
<a
|
|
href={workItemLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-custom-primary px-2 py-1 hover:bg-custom-background-90 font-medium rounded"
|
|
>
|
|
{`View ${isEpic ? "epic" : "work item"}`}
|
|
</a>
|
|
|
|
{copied ? (
|
|
<>
|
|
<span className="cursor-default px-2 py-1 text-custom-text-200">Copied!</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<button
|
|
className="cursor-pointer hidden group-hover:flex px-2 py-1 text-custom-text-300 hover:text-custom-text-200 hover:bg-custom-background-90 rounded"
|
|
onClick={copyToClipboard}
|
|
>
|
|
Copy link
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
});
|