mirror of
https://github.com/makeplane/plane.git
synced 2026-07-13 05:49:40 +02: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 * chore: workItemLink updated * fix: issues navigation tab active status * fix: issues navigation tab active status * fix: invalid workitem error state * fix: invalid workitem error state * chore: peek view parent issue redirection improvement * chore: peek view parent issue redirection improvement * chore: code refactor * fix: issue detail endpoint to not return epics and intake issue * fix: build error * fix: workitem empty state redirection and header * fix: workitem empty state redirection and header * fix: build error and code refactor * fix: yarn lock --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com> Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
124 lines
5.1 KiB
TypeScript
124 lines
5.1 KiB
TypeScript
import { FC } from "react";
|
|
import { observer } from "mobx-react";
|
|
import Link from "next/link";
|
|
import useSWR from "swr";
|
|
import { CalendarCheck } from "lucide-react";
|
|
// plane constants
|
|
import { EIssuesStoreType } from "@plane/constants";
|
|
// types
|
|
import { IActiveCycle } from "@plane/types";
|
|
// ui
|
|
import { Tooltip, Loader, PriorityIcon } from "@plane/ui";
|
|
// components
|
|
import { StateDropdown } from "@/components/dropdowns";
|
|
// constants
|
|
import { CYCLE_ISSUES_WITH_PARAMS } from "@/constants/fetch-keys";
|
|
// helpers
|
|
import { renderFormattedDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper";
|
|
import { generateWorkItemLink } from "@/helpers/issue.helper";
|
|
// hooks
|
|
import { useIssues, useProject, useProjectState } from "@/hooks/store";
|
|
// plane web components
|
|
import { IssueIdentifier } from "@/plane-web/components/issues";
|
|
|
|
export type ActiveCyclePriorityIssuesProps = {
|
|
workspaceSlug: string;
|
|
projectId: string;
|
|
cycle: IActiveCycle;
|
|
};
|
|
|
|
export const ActiveCyclePriorityIssues: FC<ActiveCyclePriorityIssuesProps> = observer((props) => {
|
|
const { workspaceSlug, projectId, cycle } = props;
|
|
// store hooks
|
|
const {
|
|
issues: { fetchActiveCycleIssues },
|
|
} = useIssues(EIssuesStoreType.CYCLE);
|
|
const { fetchWorkspaceStates } = useProjectState();
|
|
const { getProjectIdentifierById } = useProject();
|
|
|
|
// derived values
|
|
const projectIdentifier = getProjectIdentifierById(projectId);
|
|
|
|
const { data: activeCycleIssues } = useSWR(
|
|
workspaceSlug && projectId && cycle.id ? CYCLE_ISSUES_WITH_PARAMS(cycle.id, { priority: "urgent,high" }) : null,
|
|
workspaceSlug && projectId && cycle.id
|
|
? () => fetchActiveCycleIssues(workspaceSlug, projectId, 10, cycle.id)
|
|
: null,
|
|
{
|
|
revalidateOnFocus: false,
|
|
}
|
|
);
|
|
|
|
useSWR(
|
|
workspaceSlug ? `WORKSPACE_STATES_${workspaceSlug}` : null,
|
|
workspaceSlug ? () => fetchWorkspaceStates(workspaceSlug.toString()) : null
|
|
);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-4 p-4 min-h-52 overflow-hidden col-span-1 lg:col-span-2 xl:col-span-1 border border-custom-border-200 rounded-lg">
|
|
<div className="flex items-center justify-between gap-4">
|
|
<h3 className="text-lg text-custom-text-300 font-medium">High-priority work items</h3>
|
|
</div>
|
|
<div className="flex flex-col gap-1 h-full w-full max-h-40 overflow-y-auto">
|
|
{activeCycleIssues ? (
|
|
activeCycleIssues.count > 0 && Array.isArray(activeCycleIssues.results) ? (
|
|
activeCycleIssues.results.map((issue: any) => (
|
|
<Link
|
|
key={issue.id}
|
|
href={generateWorkItemLink({
|
|
workspaceSlug,
|
|
projectId: issue?.project_id,
|
|
issueId: issue?.id,
|
|
projectIdentifier,
|
|
sequenceId: issue?.sequence_id,
|
|
})}
|
|
className="group flex cursor-pointer items-center justify-between gap-2 rounded-md hover:bg-custom-background-90 p-1"
|
|
>
|
|
<div className="flex items-center gap-1.5 flex-grow w-full truncate">
|
|
<IssueIdentifier
|
|
issueId={issue.id}
|
|
projectId={projectId}
|
|
textContainerClassName="text-xs text-custom-text-200"
|
|
/>
|
|
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
|
|
<span className="text-[0.825rem] text-custom-text-100 truncate">{issue.name}</span>
|
|
</Tooltip>
|
|
</div>
|
|
<PriorityIcon priority={issue.priority} withContainer size={12} />
|
|
<div className="flex items-center gap-1.5 flex-shrink-0">
|
|
<StateDropdown
|
|
value={issue.state_id ?? undefined}
|
|
onChange={() => {}}
|
|
projectId={projectId?.toString() ?? ""}
|
|
buttonVariant="background-with-text"
|
|
buttonContainerClassName="cursor-pointer"
|
|
buttonClassName="group-hover:bg-custom-background-100"
|
|
/>
|
|
{issue.target_date && (
|
|
<Tooltip tooltipHeading="Target Date" tooltipContent={renderFormattedDate(issue.target_date)}>
|
|
<div className="h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80 group-hover:bg-custom-background-100 cursor-pointer">
|
|
<CalendarCheck className="h-3 w-3 flex-shrink-0" />
|
|
<span className="text-xs">{renderFormattedDateWithoutYear(issue.target_date)}</span>
|
|
</div>
|
|
</Tooltip>
|
|
)}
|
|
</div>
|
|
</Link>
|
|
))
|
|
) : (
|
|
<div className="flex items-center justify-center h-full text-sm text-custom-text-200">
|
|
<span>There are no high priority work items present in this cycle.</span>
|
|
</div>
|
|
)
|
|
) : (
|
|
<Loader className="space-y-3">
|
|
<Loader.Item height="50px" />
|
|
<Loader.Item height="50px" />
|
|
<Loader.Item height="50px" />
|
|
</Loader>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|