114 lines
4.4 KiB
TypeScript
114 lines
4.4 KiB
TypeScript
/**
|
|
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
* See the LICENSE file for details.
|
|
*/
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { observer } from "mobx-react";
|
|
import useSWR from "swr";
|
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
|
import type { TNameDescriptionLoader } from "@plane/types";
|
|
import { useProjectExternalContours } from "@/hooks/store/use-project-external-contours";
|
|
import { useUser, useUserPermissions } from "@/hooks/store/user";
|
|
import { useAppRouter } from "@/hooks/use-app-router";
|
|
import { ExternalContoursPeekShell } from "./peek-shell";
|
|
import { ExternalContoursIssueMainContent } from "./issue-root";
|
|
|
|
type Props = {
|
|
workspaceSlug: string;
|
|
projectId: string;
|
|
inboxIssueId: string;
|
|
embedIssue?: boolean;
|
|
embedRemoveCurrentNotification?: () => void;
|
|
};
|
|
|
|
export const ExternalContoursContentRoot = observer(function ExternalContoursContentRoot(props: Props) {
|
|
const {
|
|
workspaceSlug,
|
|
projectId,
|
|
inboxIssueId,
|
|
embedIssue = false,
|
|
embedRemoveCurrentNotification,
|
|
} = props;
|
|
const router = useAppRouter();
|
|
const [isSubmitting, setIsSubmitting] = useState<TNameDescriptionLoader>("saved");
|
|
const [isDetailResolved, setIsDetailResolved] = useState(false);
|
|
const { data: currentUser } = useUser();
|
|
const { currentTab, fetchRequestById, getRequestById } = useProjectExternalContours();
|
|
const contourRequest = getRequestById(inboxIssueId);
|
|
const issue = contourRequest?.issue;
|
|
const targetProjectId = issue?.project_id || projectId;
|
|
const { allowPermissions, getProjectRoleByWorkspaceSlugAndProjectId } = useUserPermissions();
|
|
const hasDirectTargetAccess = !!(
|
|
targetProjectId && getProjectRoleByWorkspaceSlugAndProjectId(workspaceSlug, targetProjectId) !== undefined
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (isDetailResolved && !contourRequest && inboxIssueId) {
|
|
router.replace(`/${workspaceSlug}/projects/${projectId}/external-contours?currentTab=${currentTab}`);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [contourRequest, currentTab, inboxIssueId, isDetailResolved, projectId, router, workspaceSlug]);
|
|
|
|
useSWR(
|
|
workspaceSlug && projectId && inboxIssueId
|
|
? `PROJECT_EXTERNAL_CONTOUR_DETAIL_${workspaceSlug}_${projectId}_${inboxIssueId}`
|
|
: null,
|
|
workspaceSlug && projectId && inboxIssueId
|
|
? async () => {
|
|
const request = await fetchRequestById(workspaceSlug, projectId, inboxIssueId);
|
|
setIsDetailResolved(true);
|
|
return request;
|
|
}
|
|
: null,
|
|
{
|
|
revalidateOnFocus: !hasDirectTargetAccess,
|
|
revalidateIfStale: !hasDirectTargetAccess,
|
|
refreshInterval: hasDirectTargetAccess ? 0 : 15000,
|
|
}
|
|
);
|
|
|
|
const isEditable =
|
|
hasDirectTargetAccess &&
|
|
(allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT, workspaceSlug, targetProjectId) ||
|
|
issue?.created_by === currentUser?.id);
|
|
const sourceRequesterId = contourRequest?.requested_by_id || issue?.created_by || contourRequest?.created_by;
|
|
const isSourceEditable =
|
|
!hasDirectTargetAccess &&
|
|
contourRequest?.status === "open" &&
|
|
!!currentUser?.id &&
|
|
String(sourceRequesterId) === String(currentUser.id);
|
|
|
|
const isGuest =
|
|
!!targetProjectId && getProjectRoleByWorkspaceSlugAndProjectId(workspaceSlug, targetProjectId) === EUserPermissions.GUEST;
|
|
const isOwner = issue?.created_by === currentUser?.id;
|
|
const readOnly = !isOwner && isGuest;
|
|
|
|
if (!contourRequest || !issue) return <></>;
|
|
|
|
return (
|
|
<ExternalContoursPeekShell
|
|
workspaceSlug={workspaceSlug}
|
|
projectId={projectId}
|
|
contourRequest={contourRequest}
|
|
hasDirectTargetAccess={hasDirectTargetAccess}
|
|
isSubmitting={isSubmitting}
|
|
embedIssue={embedIssue}
|
|
embedRemoveCurrentNotification={embedRemoveCurrentNotification}
|
|
onClose={() => router.replace(`/${workspaceSlug}/projects/${projectId}/external-contours?currentTab=${currentTab}`)}
|
|
>
|
|
<ExternalContoursIssueMainContent
|
|
workspaceSlug={workspaceSlug}
|
|
sourceProjectId={projectId}
|
|
contourRequest={contourRequest}
|
|
hasDirectTargetAccess={hasDirectTargetAccess}
|
|
isEditable={!!isEditable && !readOnly}
|
|
isSourceEditable={isSourceEditable}
|
|
isSubmitting={isSubmitting}
|
|
setIsSubmitting={setIsSubmitting}
|
|
/>
|
|
</ExternalContoursPeekShell>
|
|
);
|
|
});
|