mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: merge conflicts resolved
This commit is contained in:
commit
71d24c1c8c
@ -343,13 +343,6 @@ class MagicSignInEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
if str(token) == str(user_token):
|
if str(token) == str(user_token):
|
||||||
user = User.objects.get(email=email)
|
user = User.objects.get(email=email)
|
||||||
if not user.is_active:
|
|
||||||
return Response(
|
|
||||||
{
|
|
||||||
"error": "Your account has been deactivated. Please contact your site administrator."
|
|
||||||
},
|
|
||||||
status=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
|
||||||
# Send event
|
# Send event
|
||||||
auth_events.delay(
|
auth_events.delay(
|
||||||
user=user.id,
|
user=user.id,
|
||||||
|
@ -14,8 +14,8 @@ type Props = {
|
|||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
data?: ILinkDetails | null;
|
data?: ILinkDetails | null;
|
||||||
status: boolean;
|
status: boolean;
|
||||||
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<ILinkDetails> | Promise<void> | void;
|
||||||
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<void>;
|
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<ILinkDetails> | Promise<void> | void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: IIssueLink | ModuleLink = {
|
const defaultValues: IIssueLink | ModuleLink = {
|
||||||
@ -31,7 +31,7 @@ export const LinkModal: FC<Props> = (props) => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
reset,
|
reset,
|
||||||
} = useForm<ModuleLink>({
|
} = useForm<IIssueLink | ModuleLink>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -468,7 +468,7 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
{progressPercentage ? (
|
{progressPercentage ? (
|
||||||
<span className="flex h-5 w-9 items-center justify-center rounded bg-amber-50 text-xs font-medium text-amber-500">
|
<span className="flex h-5 w-9 items-center justify-center rounded bg-amber-500/20 text-xs font-medium text-amber-500">
|
||||||
{progressPercentage ? `${progressPercentage}%` : ""}
|
{progressPercentage ? `${progressPercentage}%` : ""}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
|
@ -84,10 +84,10 @@ export const IssueAttachmentUpload: React.FC<Props> = observer((props) => {
|
|||||||
disabled: isLoading || disabled,
|
disabled: isLoading || disabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const maxFileSize = envConfig?.file_size_limit ?? MAX_FILE_SIZE;
|
||||||
|
|
||||||
const fileError =
|
const fileError =
|
||||||
fileRejections.length > 0
|
fileRejections.length > 0 ? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)` : null;
|
||||||
? `Invalid file type or size (max ${envConfig?.file_size_limit ?? MAX_FILE_SIZE / 1024 / 1024} MB)`
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -3,6 +3,8 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
|
// hooks
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// types
|
// types
|
||||||
import type { IIssue } from "types";
|
import type { IIssue } from "types";
|
||||||
|
|
||||||
@ -18,6 +20,8 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
@ -31,7 +35,21 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
if (onSubmit)
|
if (onSubmit)
|
||||||
await onSubmit()
|
await onSubmit()
|
||||||
.then(() => onClose())
|
.then(() => {
|
||||||
|
setToastAlert({
|
||||||
|
title: "Success",
|
||||||
|
type: "success",
|
||||||
|
message: "Issue deleted successfully",
|
||||||
|
});
|
||||||
|
onClose();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setToastAlert({
|
||||||
|
title: "Error",
|
||||||
|
type: "error",
|
||||||
|
message: "Failed to delete issue",
|
||||||
|
});
|
||||||
|
})
|
||||||
.finally(() => setIsDeleteLoading(false));
|
.finally(() => setIsDeleteLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,20 +54,19 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
|||||||
|
|
||||||
const issues = issueIds.map((id) => issuesResponse?.[id]);
|
const issues = issueIds.map((id) => issuesResponse?.[id]);
|
||||||
|
|
||||||
const updateIssue = async (issue: IIssue, payload: IBlockUpdateData) => {
|
const updateIssueBlockStructure = async (issue: IIssue, data: IBlockUpdateData) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
//Todo fix sort order in the structure
|
const payload: any = { ...data };
|
||||||
await issueStore.updateIssue(
|
if (data.sort_order) payload.sort_order = data.sort_order.newSortOrder;
|
||||||
workspaceSlug.toString(),
|
|
||||||
issue.project,
|
await issueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, payload, viewId);
|
||||||
issue.id,
|
};
|
||||||
{
|
|
||||||
start_date: payload.start_date,
|
const updateIssue = async (projectId: string, issueId: string, payload: Partial<IIssue>) => {
|
||||||
target_date: payload.target_date,
|
if (!workspaceSlug) return;
|
||||||
},
|
|
||||||
viewId
|
await issueStore.updateIssue(workspaceSlug.toString(), projectId, issueId, payload, viewId);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
@ -80,7 +79,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
|||||||
title="Issues"
|
title="Issues"
|
||||||
loaderTitle="Issues"
|
loaderTitle="Issues"
|
||||||
blocks={issues ? renderIssueBlocksStructure(issues as IIssueUnGroupedStructure) : null}
|
blocks={issues ? renderIssueBlocksStructure(issues as IIssueUnGroupedStructure) : null}
|
||||||
blockUpdateHandler={updateIssue}
|
blockUpdateHandler={updateIssueBlockStructure}
|
||||||
blockToRender={(data: IIssue) => <IssueGanttBlock data={data} />}
|
blockToRender={(data: IIssue) => <IssueGanttBlock data={data} />}
|
||||||
sidebarToRender={(props) => (
|
sidebarToRender={(props) => (
|
||||||
<IssueGanttSidebar
|
<IssueGanttSidebar
|
||||||
@ -102,8 +101,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
|||||||
projectId={peekProjectId.toString()}
|
projectId={peekProjectId.toString()}
|
||||||
issueId={peekIssueId.toString()}
|
issueId={peekIssueId.toString()}
|
||||||
handleIssue={async (issueToUpdate) => {
|
handleIssue={async (issueToUpdate) => {
|
||||||
// TODO: update the logic here
|
await updateIssue(peekProjectId.toString(), peekIssueId.toString(), issueToUpdate);
|
||||||
await updateIssue(issueToUpdate as IIssue, {});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -7,9 +7,15 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
export const CycleGanttLayout: React.FC = observer(() => {
|
export const CycleGanttLayout: React.FC = observer(() => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { cycleId } = router.query as { cycleId: string };
|
const { cycleId } = router.query;
|
||||||
|
|
||||||
const { cycleIssues: cycleIssueStore, cycleIssuesFilter: cycleIssueFilterStore } = useMobxStore();
|
const { cycleIssues: cycleIssueStore, cycleIssuesFilter: cycleIssueFilterStore } = useMobxStore();
|
||||||
|
|
||||||
return <BaseGanttRoot issueFiltersStore={cycleIssueFilterStore} issueStore={cycleIssueStore} viewId={cycleId} />;
|
return (
|
||||||
|
<BaseGanttRoot
|
||||||
|
issueFiltersStore={cycleIssueFilterStore}
|
||||||
|
issueStore={cycleIssueStore}
|
||||||
|
viewId={cycleId?.toString()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -7,9 +7,15 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
export const ModuleGanttLayout: React.FC = observer(() => {
|
export const ModuleGanttLayout: React.FC = observer(() => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { moduleId } = router.query as { moduleId: string };
|
const { moduleId } = router.query;
|
||||||
|
|
||||||
const { moduleIssues: moduleIssueStore, moduleIssuesFilter: moduleIssueFilterStore } = useMobxStore();
|
const { moduleIssues: moduleIssueStore, moduleIssuesFilter: moduleIssueFilterStore } = useMobxStore();
|
||||||
|
|
||||||
return <BaseGanttRoot issueFiltersStore={moduleIssueFilterStore} issueStore={moduleIssueStore} viewId={moduleId} />;
|
return (
|
||||||
|
<BaseGanttRoot
|
||||||
|
issueFiltersStore={moduleIssueFilterStore}
|
||||||
|
issueStore={moduleIssueStore}
|
||||||
|
viewId={moduleId?.toString()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -195,25 +195,12 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
|||||||
|
|
||||||
const handleDeleteIssue = async () => {
|
const handleDeleteIssue = async () => {
|
||||||
if (!handleDragDrop) return;
|
if (!handleDragDrop) return;
|
||||||
await handleDragDrop(dragState.source, dragState.destination, sub_group_by, group_by, issues, issueIds)
|
await handleDragDrop(dragState.source, dragState.destination, sub_group_by, group_by, issues, issueIds).finally(
|
||||||
.then(() => {
|
() => {
|
||||||
setToastAlert({
|
|
||||||
title: "Success",
|
|
||||||
type: "success",
|
|
||||||
message: "Issue deleted successfully",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setToastAlert({
|
|
||||||
title: "Error",
|
|
||||||
type: "error",
|
|
||||||
message: "Failed to delete issue",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setDeleteIssueModal(false);
|
setDeleteIssueModal(false);
|
||||||
setDragState({});
|
setDragState({});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKanBanToggle = (toggle: "groupByHeaderMinMax" | "subgroupByIssuesVisibility", value: string) => {
|
const handleKanBanToggle = (toggle: "groupByHeaderMinMax" | "subgroupByIssuesVisibility", value: string) => {
|
||||||
|
@ -17,7 +17,7 @@ export const CycleIssueQuickActions: React.FC<IQuickActionProps> = (props) => {
|
|||||||
const { issue, handleDelete, handleUpdate, handleRemoveFromView, customActionButton } = props;
|
const { issue, handleDelete, handleUpdate, handleRemoveFromView, customActionButton } = props;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug, cycleId } = router.query;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [createUpdateIssueModal, setCreateUpdateIssueModal] = useState(false);
|
const [createUpdateIssueModal, setCreateUpdateIssueModal] = useState(false);
|
||||||
@ -75,7 +75,10 @@ export const CycleIssueQuickActions: React.FC<IQuickActionProps> = (props) => {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIssueToEdit(issue);
|
setIssueToEdit({
|
||||||
|
...issue,
|
||||||
|
cycle: cycleId?.toString() ?? null,
|
||||||
|
});
|
||||||
setCreateUpdateIssueModal(true);
|
setCreateUpdateIssueModal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -17,7 +17,7 @@ export const ModuleIssueQuickActions: React.FC<IQuickActionProps> = (props) => {
|
|||||||
const { issue, handleDelete, handleUpdate, handleRemoveFromView, customActionButton } = props;
|
const { issue, handleDelete, handleUpdate, handleRemoveFromView, customActionButton } = props;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug, moduleId } = router.query;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [createUpdateIssueModal, setCreateUpdateIssueModal] = useState(false);
|
const [createUpdateIssueModal, setCreateUpdateIssueModal] = useState(false);
|
||||||
@ -75,7 +75,7 @@ export const ModuleIssueQuickActions: React.FC<IQuickActionProps> = (props) => {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIssueToEdit(issue);
|
setIssueToEdit({ ...issue, module: moduleId?.toString() ?? null });
|
||||||
setCreateUpdateIssueModal(true);
|
setCreateUpdateIssueModal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -27,7 +27,7 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onC
|
|||||||
value={issue.assignees}
|
value={issue.assignees}
|
||||||
defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
|
defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
|
||||||
onChange={(data) => onChange({ assignees: data })}
|
onChange={(data) => onChange({ assignees: data })}
|
||||||
className="h-11 w-full"
|
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
|
||||||
buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1 "
|
buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1 "
|
||||||
noLabelBorder
|
noLabelBorder
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
|
@ -18,7 +18,7 @@ export const SpreadsheetAttachmentColumn: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs">
|
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200">
|
||||||
{issue.attachment_count} {issue.attachment_count === 1 ? "attachment" : "attachments"}
|
{issue.attachment_count} {issue.attachment_count === 1 ? "attachment" : "attachments"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export const SpreadsheetCreatedOnColumn: React.FC<Props> = ({ issue, expandedIss
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-11 w-full items-center justify-center text-xs">
|
<div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200">
|
||||||
{renderLongDetailDateFormat(issue.created_at)}
|
{renderLongDetailDateFormat(issue.created_at)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ export const SpreadsheetDueDateColumn: React.FC<Props> = ({ issue, onChange, exp
|
|||||||
<ViewDueDateSelect
|
<ViewDueDateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
onChange={(val) => onChange({ target_date: val })}
|
onChange={(val) => onChange({ target_date: val })}
|
||||||
className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1"
|
className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200"
|
||||||
noBorder
|
noBorder
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
|
@ -25,7 +25,7 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = (props) => {
|
|||||||
projectId={issue.project_detail?.id ?? null}
|
projectId={issue.project_detail?.id ?? null}
|
||||||
value={issue.estimate_point}
|
value={issue.estimate_point}
|
||||||
onChange={(data) => onChange({ estimate_point: data })}
|
onChange={(data) => onChange({ estimate_point: data })}
|
||||||
className="h-11 w-full"
|
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
|
||||||
buttonClassName="h-full w-full px-2.5 py-1 !shadow-none !border-0"
|
buttonClassName="h-full w-full px-2.5 py-1 !shadow-none !border-0"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -29,7 +29,7 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (props) => {
|
|||||||
value={issue.labels}
|
value={issue.labels}
|
||||||
defaultOptions={issue?.label_details ? issue.label_details : []}
|
defaultOptions={issue?.label_details ? issue.label_details : []}
|
||||||
onChange={(data) => onChange({ labels: data })}
|
onChange={(data) => onChange({ labels: data })}
|
||||||
className="h-11 w-full"
|
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
|
||||||
buttonClassName="px-2.5 h-full"
|
buttonClassName="px-2.5 h-full"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
maxRender={1}
|
maxRender={1}
|
||||||
|
@ -18,7 +18,7 @@ export const SpreadsheetLinkColumn: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs">
|
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200">
|
||||||
{issue.link_count} {issue.link_count === 1 ? "link" : "links"}
|
{issue.link_count} {issue.link_count === 1 ? "link" : "links"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ export const SpreadsheetPriorityColumn: React.FC<Props> = ({ issue, onChange, ex
|
|||||||
<PrioritySelect
|
<PrioritySelect
|
||||||
value={issue.priority}
|
value={issue.priority}
|
||||||
onChange={(data) => onChange({ priority: data })}
|
onChange={(data) => onChange({ priority: data })}
|
||||||
className="h-11 w-full"
|
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
|
||||||
buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1"
|
buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1"
|
||||||
showTitle
|
showTitle
|
||||||
highlightUrgentPriority={false}
|
highlightUrgentPriority={false}
|
||||||
|
@ -24,7 +24,7 @@ export const SpreadsheetStartDateColumn: React.FC<Props> = ({ issue, onChange, e
|
|||||||
<ViewStartDateSelect
|
<ViewStartDateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
onChange={(val) => onChange({ start_date: val })}
|
onChange={(val) => onChange({ start_date: val })}
|
||||||
className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1"
|
className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200"
|
||||||
noBorder
|
noBorder
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +29,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = (props) => {
|
|||||||
value={issue.state}
|
value={issue.state}
|
||||||
defaultOptions={issue?.state_detail ? [issue.state_detail] : []}
|
defaultOptions={issue?.state_detail ? [issue.state_detail] : []}
|
||||||
onChange={(data) => onChange({ state: data.id, state_detail: data })}
|
onChange={(data) => onChange({ state: data.id, state_detail: data })}
|
||||||
className="w-full !h-11"
|
className="w-full !h-11 border-b-[0.5px] border-custom-border-200"
|
||||||
buttonClassName="!shadow-none !border-0 h-full w-full"
|
buttonClassName="!shadow-none !border-0 h-full w-full"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -18,7 +18,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs">
|
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200">
|
||||||
{issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
|
{issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const SpreadsheetUpdatedOnColumn: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex h-11 w-full items-center justify-center text-xs">
|
<div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200">
|
||||||
{renderLongDetailDateFormat(issue.updated_at)}
|
{renderLongDetailDateFormat(issue.updated_at)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -159,13 +159,13 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
|||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="h-full w-full divide-y-[0.5px] border-b-[0.5px] min-w-[8rem]">
|
<div className="h-full w-full min-w-[8rem]">
|
||||||
{issues?.map((issue) => {
|
{issues?.map((issue) => {
|
||||||
const disableUserActions = !canEditProperties(issue.project);
|
const disableUserActions = !canEditProperties(issue.project);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${property}-${issue.id}`}
|
key={`${property}-${issue.id}`}
|
||||||
className={`h-fit divide-y-[0.5px] border-custom-border-200 ${
|
className={`h-fit ${
|
||||||
disableUserActions ? "" : "cursor-pointer hover:bg-custom-background-80"
|
disableUserActions ? "" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -77,6 +77,13 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
if (!issues || issues.length === 0)
|
||||||
|
return (
|
||||||
|
<div className="grid h-full w-full place-items-center">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex h-full w-full overflow-x-auto whitespace-nowrap rounded-lg bg-custom-background-200 text-custom-text-200">
|
<div className="relative flex h-full w-full overflow-x-auto whitespace-nowrap rounded-lg bg-custom-background-200 text-custom-text-200">
|
||||||
<div className="flex h-full w-full flex-col">
|
<div className="flex h-full w-full flex-col">
|
||||||
@ -84,7 +91,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
|||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className="horizontal-scroll-enable flex divide-x-[0.5px] divide-custom-border-200 overflow-y-auto"
|
className="horizontal-scroll-enable flex divide-x-[0.5px] divide-custom-border-200 overflow-y-auto"
|
||||||
>
|
>
|
||||||
{issues && issues.length > 0 ? (
|
{issues && issues.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<div className="sticky left-0 z-[2] w-[28rem]">
|
<div className="sticky left-0 z-[2] w-[28rem]">
|
||||||
<div
|
<div
|
||||||
@ -134,10 +141,6 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
|||||||
states={states}
|
states={states}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<div className="grid h-full w-full place-items-center">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
<div /> {/* empty div to show right most border */}
|
<div /> {/* empty div to show right most border */}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { mutate } from "swr";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// mobx store
|
// mobx store
|
||||||
@ -17,30 +17,25 @@ import {
|
|||||||
SidebarPrioritySelect,
|
SidebarPrioritySelect,
|
||||||
SidebarStateSelect,
|
SidebarStateSelect,
|
||||||
} from "../sidebar-select";
|
} from "../sidebar-select";
|
||||||
// services
|
|
||||||
import { IssueService } from "services/issue";
|
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { CustomDatePicker } from "components/ui";
|
import { CustomDatePicker } from "components/ui";
|
||||||
import { LinkModal, LinksList } from "components/core";
|
import { LinkModal, LinksList } from "components/core";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueLink, TIssuePriorities, ILinkDetails } from "types";
|
import { IIssue, TIssuePriorities, ILinkDetails, IIssueLink } from "types";
|
||||||
// fetch-keys
|
|
||||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
interface IPeekOverviewProperties {
|
interface IPeekOverviewProperties {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
issueUpdate: (issue: Partial<IIssue>) => void;
|
issueUpdate: (issue: Partial<IIssue>) => void;
|
||||||
|
issueLinkCreate: (data: IIssueLink) => Promise<ILinkDetails>;
|
||||||
|
issueLinkUpdate: (data: IIssueLink, linkId: string) => Promise<ILinkDetails>;
|
||||||
|
issueLinkDelete: (linkId: string) => Promise<void>;
|
||||||
disableUserActions: boolean;
|
disableUserActions: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const issueService = new IssueService();
|
|
||||||
|
|
||||||
export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((props) => {
|
export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((props) => {
|
||||||
const { issue, issueUpdate, disableUserActions } = props;
|
const { issue, issueUpdate, issueLinkCreate, issueLinkUpdate, issueLinkDelete, disableUserActions } = props;
|
||||||
// states
|
// states
|
||||||
const [linkModal, setLinkModal] = useState(false);
|
const [linkModal, setLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
@ -54,8 +49,6 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleState = (_state: string) => {
|
const handleState = (_state: string) => {
|
||||||
issueUpdate({ ...issue, state: _state });
|
issueUpdate({ ...issue, state: _state });
|
||||||
};
|
};
|
||||||
@ -81,61 +74,6 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
issueUpdate({ ...issue, ...formData });
|
issueUpdate({ ...issue, ...formData });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateLink = async (formData: IIssueLink) => {
|
|
||||||
if (!workspaceSlug || !projectId || !issue) return;
|
|
||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.createIssueLink(workspaceSlug as string, projectId as string, issue.id, payload)
|
|
||||||
.then(() => mutate(ISSUE_DETAILS(issue.id)))
|
|
||||||
.catch((err) => {
|
|
||||||
if (err.status === 400)
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "This URL already exists for this issue.",
|
|
||||||
});
|
|
||||||
else
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "Something went wrong. Please try again.",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateLink = async (formData: IIssueLink, linkId: string) => {
|
|
||||||
if (!workspaceSlug || !projectId || !issue) return;
|
|
||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
|
||||||
|
|
||||||
const updatedLinks = issue.issue_link.map((l) =>
|
|
||||||
l.id === linkId
|
|
||||||
? {
|
|
||||||
...l,
|
|
||||||
title: formData.title,
|
|
||||||
url: formData.url,
|
|
||||||
}
|
|
||||||
: l
|
|
||||||
);
|
|
||||||
|
|
||||||
mutate<IIssue>(
|
|
||||||
ISSUE_DETAILS(issue.id),
|
|
||||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.updateIssueLink(workspaceSlug as string, projectId as string, issue.id, linkId, payload)
|
|
||||||
.then(() => {
|
|
||||||
mutate(ISSUE_DETAILS(issue.id));
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCycleOrModuleChange = async () => {
|
const handleCycleOrModuleChange = async () => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
@ -147,27 +85,6 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
setLinkModal(true);
|
setLinkModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
|
||||||
if (!workspaceSlug || !projectId || !issue) return;
|
|
||||||
|
|
||||||
const updatedLinks = issue.issue_link.filter((l) => l.id !== linkId);
|
|
||||||
|
|
||||||
mutate<IIssue>(
|
|
||||||
ISSUE_DETAILS(issue.id),
|
|
||||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.deleteIssueLink(workspaceSlug as string, projectId as string, issue.id, linkId)
|
|
||||||
.then(() => {
|
|
||||||
mutate(ISSUE_DETAILS(issue.id));
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const projectDetails = workspaceSlug ? getProjectById(workspaceSlug.toString(), issue.project) : null;
|
const projectDetails = workspaceSlug ? getProjectById(workspaceSlug.toString(), issue.project) : null;
|
||||||
const isEstimateEnabled = projectDetails?.estimate;
|
const isEstimateEnabled = projectDetails?.estimate;
|
||||||
|
|
||||||
@ -187,8 +104,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
}}
|
}}
|
||||||
data={selectedLinkToUpdate}
|
data={selectedLinkToUpdate}
|
||||||
status={selectedLinkToUpdate ? true : false}
|
status={selectedLinkToUpdate ? true : false}
|
||||||
createIssueLink={handleCreateLink}
|
createIssueLink={issueLinkCreate}
|
||||||
updateIssueLink={handleUpdateLink}
|
updateIssueLink={issueLinkUpdate}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="flex w-full flex-col gap-5 py-5">
|
<div className="flex w-full flex-col gap-5 py-5">
|
||||||
@ -373,7 +290,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
{issue?.issue_link && issue.issue_link.length > 0 ? (
|
{issue?.issue_link && issue.issue_link.length > 0 ? (
|
||||||
<LinksList
|
<LinksList
|
||||||
links={issue.issue_link}
|
links={issue.issue_link}
|
||||||
handleDeleteLink={handleDeleteLink}
|
handleDeleteLink={issueLinkDelete}
|
||||||
handleEditLink={handleEditLink}
|
handleEditLink={handleEditLink}
|
||||||
userAuth={{
|
userAuth={{
|
||||||
isGuest: currentProjectRole === EUserWorkspaceRoles.GUEST,
|
isGuest: currentProjectRole === EUserWorkspaceRoles.GUEST,
|
||||||
|
@ -10,7 +10,7 @@ import { IssueView } from "components/issues";
|
|||||||
// helpers
|
// helpers
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue, IIssueLink } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
@ -42,6 +42,9 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
removeIssueReaction,
|
removeIssueReaction,
|
||||||
createIssueSubscription,
|
createIssueSubscription,
|
||||||
removeIssueSubscription,
|
removeIssueSubscription,
|
||||||
|
createIssueLink,
|
||||||
|
updateIssueLink,
|
||||||
|
deleteIssueLink,
|
||||||
getIssue,
|
getIssue,
|
||||||
loader,
|
loader,
|
||||||
fetchPeekIssueDetails,
|
fetchPeekIssueDetails,
|
||||||
@ -121,6 +124,13 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
|
|
||||||
const issueSubscriptionRemove = () => removeIssueSubscription(workspaceSlug, projectId, issueId);
|
const issueSubscriptionRemove = () => removeIssueSubscription(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
const issueLinkCreate = (formData: IIssueLink) => createIssueLink(workspaceSlug, projectId, issueId, formData);
|
||||||
|
|
||||||
|
const issueLinkUpdate = (formData: IIssueLink, linkId: string) =>
|
||||||
|
updateIssueLink(workspaceSlug, projectId, issueId, linkId, formData);
|
||||||
|
|
||||||
|
const issueLinkDelete = (linkId: string) => deleteIssueLink(workspaceSlug, projectId, issueId, linkId);
|
||||||
|
|
||||||
const handleDeleteIssue = async () => {
|
const handleDeleteIssue = async () => {
|
||||||
if (isArchived) await deleteArchivedIssue(workspaceSlug, projectId, issue!);
|
if (isArchived) await deleteArchivedIssue(workspaceSlug, projectId, issue!);
|
||||||
else removeIssueFromStructure(workspaceSlug, projectId, issue!);
|
else removeIssueFromStructure(workspaceSlug, projectId, issue!);
|
||||||
@ -159,6 +169,9 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
issueCommentReactionRemove={issueCommentReactionRemove}
|
issueCommentReactionRemove={issueCommentReactionRemove}
|
||||||
issueSubscriptionCreate={issueSubscriptionCreate}
|
issueSubscriptionCreate={issueSubscriptionCreate}
|
||||||
issueSubscriptionRemove={issueSubscriptionRemove}
|
issueSubscriptionRemove={issueSubscriptionRemove}
|
||||||
|
issueLinkCreate={issueLinkCreate}
|
||||||
|
issueLinkUpdate={issueLinkUpdate}
|
||||||
|
issueLinkDelete={issueLinkDelete}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
disableUserActions={[5, 10].includes(userRole)}
|
disableUserActions={[5, 10].includes(userRole)}
|
||||||
showCommentAccessSpecifier={currentProjectDetails?.is_deployed}
|
showCommentAccessSpecifier={currentProjectDetails?.is_deployed}
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
// ui
|
// ui
|
||||||
import { Button, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon, Spinner } from "@plane/ui";
|
import { Button, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon, Spinner } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue, IIssueLink, ILinkDetails } from "types";
|
||||||
|
|
||||||
interface IIssueView {
|
interface IIssueView {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -38,6 +38,9 @@ interface IIssueView {
|
|||||||
issueCommentReactionRemove: (commentId: string, reaction: string) => void;
|
issueCommentReactionRemove: (commentId: string, reaction: string) => void;
|
||||||
issueSubscriptionCreate: () => void;
|
issueSubscriptionCreate: () => void;
|
||||||
issueSubscriptionRemove: () => void;
|
issueSubscriptionRemove: () => void;
|
||||||
|
issueLinkCreate: (formData: IIssueLink) => Promise<ILinkDetails>;
|
||||||
|
issueLinkUpdate: (formData: IIssueLink, linkId: string) => Promise<ILinkDetails>;
|
||||||
|
issueLinkDelete: (linkId: string) => Promise<void>;
|
||||||
handleDeleteIssue: () => Promise<void>;
|
handleDeleteIssue: () => Promise<void>;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
disableUserActions?: boolean;
|
disableUserActions?: boolean;
|
||||||
@ -84,6 +87,9 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||||||
issueCommentReactionRemove,
|
issueCommentReactionRemove,
|
||||||
issueSubscriptionCreate,
|
issueSubscriptionCreate,
|
||||||
issueSubscriptionRemove,
|
issueSubscriptionRemove,
|
||||||
|
issueLinkCreate,
|
||||||
|
issueLinkUpdate,
|
||||||
|
issueLinkDelete,
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
children,
|
children,
|
||||||
disableUserActions = false,
|
disableUserActions = false,
|
||||||
@ -286,6 +292,9 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||||||
<PeekOverviewProperties
|
<PeekOverviewProperties
|
||||||
issue={issue}
|
issue={issue}
|
||||||
issueUpdate={issueUpdate}
|
issueUpdate={issueUpdate}
|
||||||
|
issueLinkCreate={issueLinkCreate}
|
||||||
|
issueLinkUpdate={issueLinkUpdate}
|
||||||
|
issueLinkDelete={issueLinkDelete}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -342,6 +351,9 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||||||
<PeekOverviewProperties
|
<PeekOverviewProperties
|
||||||
issue={issue}
|
issue={issue}
|
||||||
issueUpdate={issueUpdate}
|
issueUpdate={issueUpdate}
|
||||||
|
issueLinkCreate={issueLinkCreate}
|
||||||
|
issueLinkUpdate={issueLinkUpdate}
|
||||||
|
issueLinkDelete={issueLinkDelete}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -84,6 +84,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
user: { currentUser, currentProjectRole },
|
user: { currentUser, currentProjectRole },
|
||||||
projectState: { states },
|
projectState: { states },
|
||||||
projectIssues: { removeIssue },
|
projectIssues: { removeIssue },
|
||||||
|
issueDetail: { createIssueLink, updateIssueLink, deleteIssueLink },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -129,80 +130,19 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
[workspaceSlug, projectId, issueId, issueDetail, currentUser]
|
[workspaceSlug, projectId, issueId, issueDetail, currentUser]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCreateLink = async (formData: IIssueLink) => {
|
const issueLinkCreate = (formData: IIssueLink) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueId) return;
|
||||||
|
createIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), formData);
|
||||||
const payload = { metadata: {}, ...formData };
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.createIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, payload)
|
|
||||||
.then(() => mutate(ISSUE_DETAILS(issueDetail.id)))
|
|
||||||
.catch((err) => {
|
|
||||||
if (err.status === 400)
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "This URL already exists for this issue.",
|
|
||||||
});
|
|
||||||
else
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "Something went wrong. Please try again.",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateLink = async (formData: IIssueLink, linkId: string) => {
|
const issueLinkUpdate = (formData: IIssueLink, linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueId) return;
|
||||||
|
updateIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), linkId, formData);
|
||||||
const payload = { metadata: {}, ...formData };
|
|
||||||
|
|
||||||
const updatedLinks = issueDetail.issue_link.map((l) =>
|
|
||||||
l.id === linkId
|
|
||||||
? {
|
|
||||||
...l,
|
|
||||||
title: formData.title,
|
|
||||||
url: formData.url,
|
|
||||||
}
|
|
||||||
: l
|
|
||||||
);
|
|
||||||
|
|
||||||
mutate<IIssue>(
|
|
||||||
ISSUE_DETAILS(issueDetail.id),
|
|
||||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.updateIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId, payload)
|
|
||||||
.then(() => {
|
|
||||||
mutate(ISSUE_DETAILS(issueDetail.id));
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
const issueLinkDelete = (linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueId) return;
|
||||||
|
deleteIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), linkId);
|
||||||
const updatedLinks = issueDetail.issue_link.filter((l) => l.id !== linkId);
|
|
||||||
|
|
||||||
mutate<IIssue>(
|
|
||||||
ISSUE_DETAILS(issueDetail.id),
|
|
||||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await issueService
|
|
||||||
.deleteIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId)
|
|
||||||
.then(() => {
|
|
||||||
mutate(ISSUE_DETAILS(issueDetail.id));
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
@ -264,8 +204,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
data={selectedLinkToUpdate}
|
data={selectedLinkToUpdate}
|
||||||
status={selectedLinkToUpdate ? true : false}
|
status={selectedLinkToUpdate ? true : false}
|
||||||
createIssueLink={handleCreateLink}
|
createIssueLink={issueLinkCreate}
|
||||||
updateIssueLink={handleUpdateLink}
|
updateIssueLink={issueLinkUpdate}
|
||||||
/>
|
/>
|
||||||
{workspaceSlug && projectId && issueDetail && (
|
{workspaceSlug && projectId && issueDetail && (
|
||||||
<DeleteIssueModal
|
<DeleteIssueModal
|
||||||
@ -659,7 +599,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
{
|
{
|
||||||
<LinksList
|
<LinksList
|
||||||
links={issueDetail.issue_link}
|
links={issueDetail.issue_link}
|
||||||
handleDeleteLink={handleDeleteLink}
|
handleDeleteLink={issueLinkDelete}
|
||||||
handleEditLink={handleEditLink}
|
handleEditLink={handleEditLink}
|
||||||
userAuth={{
|
userAuth={{
|
||||||
isGuest: currentProjectRole === 5,
|
isGuest: currentProjectRole === 5,
|
||||||
|
@ -311,7 +311,11 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<CustomSelect
|
<CustomSelect
|
||||||
customButton={
|
customButton={
|
||||||
<span
|
<span
|
||||||
className={`flex h-6 w-20 cursor-default items-center justify-center rounded-sm text-sm ${moduleStatus?.textColor} ${moduleStatus?.bgColor}`}
|
className="flex h-6 w-20 cursor-default items-center justify-center rounded-sm text-center text-xs"
|
||||||
|
style={{
|
||||||
|
color: moduleStatus ? moduleStatus.color : "#a3a3a2",
|
||||||
|
backgroundColor: moduleStatus ? `${moduleStatus.color}20` : "#a3a3a220",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{moduleStatus?.label ?? "Backlog"}
|
{moduleStatus?.label ?? "Backlog"}
|
||||||
</span>
|
</span>
|
||||||
@ -459,7 +463,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
{progressPercentage ? (
|
{progressPercentage ? (
|
||||||
<span className="flex h-5 w-9 items-center justify-center rounded bg-amber-50 text-xs font-medium text-amber-500">
|
<span className="flex h-5 w-9 items-center justify-center rounded bg-amber-500/20 text-xs font-medium text-amber-500">
|
||||||
{progressPercentage ? `${progressPercentage}%` : ""}
|
{progressPercentage ? `${progressPercentage}%` : ""}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
|
@ -54,7 +54,14 @@ export const ProjectViewForm: React.FC<Props> = observer(({ handleFormSubmit, ha
|
|||||||
|
|
||||||
// for removing filters from a key
|
// for removing filters from a key
|
||||||
const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => {
|
const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => {
|
||||||
if (!value) return;
|
// If value is null then remove all the filters of that key
|
||||||
|
if (!value) {
|
||||||
|
setValue("query_data", {
|
||||||
|
...selectedFilters,
|
||||||
|
[key]: null,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newValues = selectedFilters?.[key] ?? [];
|
const newValues = selectedFilters?.[key] ?? [];
|
||||||
|
|
||||||
|
@ -100,7 +100,9 @@ const ProfileActivityPage: NextPageWithLayout = () => {
|
|||||||
activityItem.field !== "estimate" ? (
|
activityItem.field !== "estimate" ? (
|
||||||
<span className="text-custom-text-200">
|
<span className="text-custom-text-200">
|
||||||
created{" "}
|
created{" "}
|
||||||
<Link href={`/${workspaceSlug}/projects/${activityItem.project}/issues/${activityItem.issue}`}>
|
<Link
|
||||||
|
href={`/${activityItem.workspace_detail.slug}/projects/${activityItem.project}/issues/${activityItem.issue}`}
|
||||||
|
>
|
||||||
<span className="inline-flex items-center hover:underline">
|
<span className="inline-flex items-center hover:underline">
|
||||||
this issue. <ExternalLinkIcon className="ml-1 h-3.5 w-3.5" />
|
this issue. <ExternalLinkIcon className="ml-1 h-3.5 w-3.5" />
|
||||||
</span>
|
</span>
|
||||||
|
@ -10,7 +10,7 @@ export abstract class APIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRefreshToken(token: string) {
|
setRefreshToken(token: string) {
|
||||||
Cookies.set("refreshToken", token);
|
Cookies.set("refreshToken", token, { expires: 30 });
|
||||||
}
|
}
|
||||||
|
|
||||||
getRefreshToken() {
|
getRefreshToken() {
|
||||||
@ -22,7 +22,7 @@ export abstract class APIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setAccessToken(token: string) {
|
setAccessToken(token: string) {
|
||||||
Cookies.set("accessToken", token);
|
Cookies.set("accessToken", token, { expires: 30 });
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccessToken() {
|
getAccessToken() {
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
// services
|
// services
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// type
|
// type
|
||||||
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse, IIssueDisplayProperties } from "types";
|
import type {
|
||||||
|
IIssue,
|
||||||
|
IIssueActivity,
|
||||||
|
ISubIssueResponse,
|
||||||
|
IIssueDisplayProperties,
|
||||||
|
ILinkDetails,
|
||||||
|
IIssueLink,
|
||||||
|
} from "types";
|
||||||
import { IIssueResponse } from "store_legacy/issues/types";
|
import { IIssueResponse } from "store_legacy/issues/types";
|
||||||
// helper
|
// helper
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
@ -184,12 +191,8 @@ export class IssueService extends APIService {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
issueId: string,
|
||||||
data: {
|
data: IIssueLink
|
||||||
metadata: any;
|
): Promise<ILinkDetails> {
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
): Promise<any> {
|
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, data)
|
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -202,12 +205,8 @@ export class IssueService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
issueId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
data: {
|
data: IIssueLink
|
||||||
metadata: any;
|
): Promise<ILinkDetails> {
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
): Promise<any> {
|
|
||||||
return this.patch(
|
return this.patch(
|
||||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`,
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`,
|
||||||
data
|
data
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// services
|
// services
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// types
|
// types
|
||||||
import type { IModule, IIssue, ILinkDetails } from "types";
|
import type { IModule, IIssue, ILinkDetails, ModuleLink } from "types";
|
||||||
import { IIssueResponse } from "store_legacy/issues/types";
|
import { IIssueResponse } from "store_legacy/issues/types";
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ export class ModuleService extends APIService {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
data: Partial<ILinkDetails>
|
data: ModuleLink
|
||||||
): Promise<ILinkDetails> {
|
): Promise<ILinkDetails> {
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
|
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
@ -146,7 +146,7 @@ export class ModuleService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
data: Partial<ILinkDetails>
|
data: ModuleLink
|
||||||
): Promise<ILinkDetails> {
|
): Promise<ILinkDetails> {
|
||||||
return this.patch(
|
return this.patch(
|
||||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
||||||
|
@ -4,7 +4,7 @@ import { IssueService, IssueReactionService, IssueCommentService } from "service
|
|||||||
import { NotificationService } from "services/notification.service";
|
import { NotificationService } from "services/notification.service";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
import type { IIssue, IIssueActivity } from "types";
|
import type { IIssue, IIssueActivity, IIssueLink, ILinkDetails } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { groupReactionEmojis } from "constants/issue";
|
import { groupReactionEmojis } from "constants/issue";
|
||||||
|
|
||||||
@ -51,6 +51,21 @@ export interface IIssueDetailStore {
|
|||||||
createIssueReaction: (workspaceSlug: string, projectId: string, issueId: string, reaction: string) => Promise<void>;
|
createIssueReaction: (workspaceSlug: string, projectId: string, issueId: string, reaction: string) => Promise<void>;
|
||||||
removeIssueReaction: (workspaceSlug: string, projectId: string, issueId: string, reaction: string) => Promise<void>;
|
removeIssueReaction: (workspaceSlug: string, projectId: string, issueId: string, reaction: string) => Promise<void>;
|
||||||
|
|
||||||
|
createIssueLink: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
data: IIssueLink
|
||||||
|
) => Promise<ILinkDetails>;
|
||||||
|
updateIssueLink: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: IIssueLink
|
||||||
|
) => Promise<ILinkDetails>;
|
||||||
|
deleteIssueLink: (workspaceSlug: string, projectId: string, issueId: string, linkId: string) => Promise<void>;
|
||||||
|
|
||||||
fetchIssueActivity: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
fetchIssueActivity: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
createIssueComment: (workspaceSlug: string, projectId: string, issueId: string, data: any) => Promise<void>;
|
createIssueComment: (workspaceSlug: string, projectId: string, issueId: string, data: any) => Promise<void>;
|
||||||
updateIssueComment: (
|
updateIssueComment: (
|
||||||
@ -147,6 +162,10 @@ export class IssueDetailStore implements IIssueDetailStore {
|
|||||||
createIssueReaction: action,
|
createIssueReaction: action,
|
||||||
removeIssueReaction: action,
|
removeIssueReaction: action,
|
||||||
|
|
||||||
|
createIssueLink: action,
|
||||||
|
updateIssueLink: action,
|
||||||
|
deleteIssueLink: action,
|
||||||
|
|
||||||
fetchIssueActivity: action,
|
fetchIssueActivity: action,
|
||||||
createIssueComment: action,
|
createIssueComment: action,
|
||||||
updateIssueComment: action,
|
updateIssueComment: action,
|
||||||
@ -590,6 +609,91 @@ export class IssueDetailStore implements IIssueDetailStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
createIssueLink = async (workspaceSlug: string, projectId: string, issueId: string, data: IIssueLink) => {
|
||||||
|
try {
|
||||||
|
const response = await this.issueService.createIssueLink(workspaceSlug, projectId, issueId, data);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues = {
|
||||||
|
...this.issues,
|
||||||
|
[issueId]: {
|
||||||
|
...this.issues[issueId],
|
||||||
|
issue_link: [response, ...this.issues[issueId].issue_link],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create link in store", error);
|
||||||
|
|
||||||
|
this.fetchIssueDetails(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateIssueLink = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: IIssueLink
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await this.issueService.updateIssueLink(workspaceSlug, projectId, issueId, linkId, data);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues = {
|
||||||
|
...this.issues,
|
||||||
|
[issueId]: {
|
||||||
|
...this.issues[issueId],
|
||||||
|
issue_link: this.issues[issueId].issue_link.map((link) => (link.id === linkId ? response : link)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update link in issue store", error);
|
||||||
|
|
||||||
|
this.fetchIssueDetails(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteIssueLink = async (workspaceSlug: string, projectId: string, issueId: string, linkId: string) => {
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues = {
|
||||||
|
...this.issues,
|
||||||
|
[issueId]: {
|
||||||
|
...this.issues[issueId],
|
||||||
|
issue_link: this.issues[issueId].issue_link.filter((link) => link.id !== linkId),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
await this.issueService.deleteIssueLink(workspaceSlug, projectId, issueId, linkId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete link in issue store", error);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// subscriptions
|
// subscriptions
|
||||||
fetchIssueSubscription = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
fetchIssueSubscription = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
|
@ -257,6 +257,7 @@ export class CycleIssuesStore extends IssueBaseStore implements ICycleIssuesStor
|
|||||||
if (!_issues) _issues = {};
|
if (!_issues) _issues = {};
|
||||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||||
delete _issues?.[cycleId]?.[issueId];
|
delete _issues?.[cycleId]?.[issueId];
|
||||||
|
_issues[cycleId] = { ..._issues[cycleId] };
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.issues = _issues;
|
this.issues = _issues;
|
||||||
|
@ -250,6 +250,7 @@ export class ModuleIssuesStore extends IssueBaseStore implements IModuleIssuesSt
|
|||||||
if (!_issues) _issues = {};
|
if (!_issues) _issues = {};
|
||||||
if (!_issues[moduleId]) _issues[moduleId] = {};
|
if (!_issues[moduleId]) _issues[moduleId] = {};
|
||||||
delete _issues?.[moduleId]?.[issueId];
|
delete _issues?.[moduleId]?.[issueId];
|
||||||
|
_issues[moduleId] = { ..._issues[moduleId] };
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.issues = _issues;
|
this.issues = _issues;
|
||||||
|
@ -175,6 +175,7 @@ export class ProjectIssuesStore extends IssueBaseStore implements IProjectIssues
|
|||||||
if (!_issues) _issues = {};
|
if (!_issues) _issues = {};
|
||||||
if (!_issues[projectId]) _issues[projectId] = {};
|
if (!_issues[projectId]) _issues[projectId] = {};
|
||||||
delete _issues?.[projectId]?.[issueId];
|
delete _issues?.[projectId]?.[issueId];
|
||||||
|
_issues[projectId] = { ..._issues[projectId] };
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.issues = _issues;
|
this.issues = _issues;
|
||||||
|
@ -3,15 +3,15 @@ import { action, computed, observable, makeObservable, runInAction } from "mobx"
|
|||||||
import { ProjectService } from "services/project";
|
import { ProjectService } from "services/project";
|
||||||
import { ModuleService } from "services/module.service";
|
import { ModuleService } from "services/module.service";
|
||||||
// types
|
// types
|
||||||
|
import { RootStore } from "../root";
|
||||||
import { IIssue, IModule, ILinkDetails } from "types";
|
import { IIssue, IModule, ILinkDetails, ModuleLink } from "types";
|
||||||
import {
|
import {
|
||||||
IIssueGroupWithSubGroupsStructure,
|
IIssueGroupWithSubGroupsStructure,
|
||||||
IIssueGroupedStructure,
|
IIssueGroupedStructure,
|
||||||
IIssueUnGroupedStructure,
|
IIssueUnGroupedStructure,
|
||||||
} from "../issue/issue.store";
|
} from "../issue/issue.store";
|
||||||
import { IBlockUpdateData } from "components/gantt-chart";
|
import { IBlockUpdateData } from "components/gantt-chart";
|
||||||
import { RootStore } from "store/root.store";
|
// import { RootStore } from "store/root.store";
|
||||||
|
|
||||||
export interface IModuleStore {
|
export interface IModuleStore {
|
||||||
// states
|
// states
|
||||||
@ -55,14 +55,14 @@ export interface IModuleStore {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
data: Partial<ILinkDetails>
|
data: ModuleLink
|
||||||
) => Promise<ILinkDetails>;
|
) => Promise<ILinkDetails>;
|
||||||
updateModuleLink: (
|
updateModuleLink: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
data: Partial<ILinkDetails>
|
data: ModuleLink
|
||||||
) => Promise<ILinkDetails>;
|
) => Promise<ILinkDetails>;
|
||||||
deleteModuleLink: (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => Promise<void>;
|
deleteModuleLink: (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => Promise<void>;
|
||||||
|
|
||||||
@ -310,12 +310,7 @@ export class ModuleStore implements IModuleStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createModuleLink = async (
|
createModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, data: ModuleLink) => {
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
moduleId: string,
|
|
||||||
data: Partial<ILinkDetails>
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const response = await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data);
|
const response = await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data);
|
||||||
|
|
||||||
@ -355,7 +350,7 @@ export class ModuleStore implements IModuleStore {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
data: Partial<ILinkDetails>
|
data: ModuleLink
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data);
|
const response = await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data);
|
||||||
|
Loading…
Reference in New Issue
Block a user