Skip to content

Commit 5ef51ed

Browse files
[WEB-1134] fix: module link create and delete mutation (#4373)
* fix: module link create and delete mutation * chore: module link mutation store updates * chore: code refactor --------- Co-authored-by: gurusainath <gurusainath007@gmail.com>
1 parent 06a664f commit 5ef51ed

File tree

3 files changed

+132
-111
lines changed

3 files changed

+132
-111
lines changed

web/components/core/sidebar/links-list.tsx

Lines changed: 92 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -7,107 +7,111 @@ import { Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
77
// helpers
88
import { calculateTimeAgo } from "@/helpers/date-time.helper";
99
// hooks
10-
import { useMember } from "@/hooks/store";
10+
import { useMember, useModule } from "@/hooks/store";
1111
import { usePlatformOS } from "@/hooks/use-platform-os";
1212
// types
1313

1414
type Props = {
15-
links: ILinkDetails[];
15+
moduleId: string;
16+
1617
handleDeleteLink: (linkId: string) => void;
1718
handleEditLink: (link: ILinkDetails) => void;
1819
userAuth: UserAuth;
1920
disabled?: boolean;
2021
};
2122

22-
export const LinksList: React.FC<Props> = observer(
23-
({ links, handleDeleteLink, handleEditLink, userAuth, disabled }) => {
24-
const { getUserDetails } = useMember();
25-
const { isMobile } = usePlatformOS();
26-
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disabled;
23+
export const LinksList: React.FC<Props> = observer((props) => {
24+
const { moduleId, handleDeleteLink, handleEditLink, userAuth, disabled } = props;
25+
// hooks
26+
const { getUserDetails } = useMember();
27+
const { isMobile } = usePlatformOS();
28+
const { getModuleById } = useModule();
29+
// derived values
30+
const currentModule = getModuleById(moduleId);
31+
const moduleLinks = currentModule?.link_module || undefined;
32+
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disabled;
2733

28-
const copyToClipboard = (text: string) => {
29-
navigator.clipboard.writeText(text);
30-
setToast({
31-
type: TOAST_TYPE.SUCCESS,
32-
title: "Copied to clipboard",
33-
message: "The URL has been successfully copied to your clipboard",
34-
});
35-
};
34+
const copyToClipboard = (text: string) => {
35+
navigator.clipboard.writeText(text);
36+
setToast({
37+
type: TOAST_TYPE.SUCCESS,
38+
title: "Copied to clipboard",
39+
message: "The URL has been successfully copied to your clipboard",
40+
});
41+
};
3642

37-
return (
38-
<>
39-
{links.map((link) => {
40-
const createdByDetails = getUserDetails(link.created_by);
41-
return (
42-
<div key={link.id} className="relative flex flex-col rounded-md bg-custom-background-90 p-2.5">
43-
<div className="flex w-full items-start justify-between gap-2">
44-
<div className="flex items-start gap-2 truncate">
45-
<span className="py-1">
46-
<LinkIcon className="h-3 w-3 flex-shrink-0" />
43+
if (!moduleLinks) return <></>;
44+
return (
45+
<>
46+
{moduleLinks.map((link) => {
47+
const createdByDetails = getUserDetails(link.created_by);
48+
return (
49+
<div key={link.id} className="relative flex flex-col rounded-md bg-custom-background-90 p-2.5">
50+
<div className="flex w-full items-start justify-between gap-2">
51+
<div className="flex items-start gap-2 truncate">
52+
<span className="py-1">
53+
<LinkIcon className="h-3 w-3 flex-shrink-0" />
54+
</span>
55+
<Tooltip tooltipContent={link.title && link.title !== "" ? link.title : link.url} isMobile={isMobile}>
56+
<span
57+
className="cursor-pointer truncate text-xs"
58+
onClick={() => copyToClipboard(link.title && link.title !== "" ? link.title : link.url)}
59+
>
60+
{link.title && link.title !== "" ? link.title : link.url}
4761
</span>
48-
<Tooltip tooltipContent={link.title && link.title !== "" ? link.title : link.url} isMobile={isMobile}>
49-
<span
50-
className="cursor-pointer truncate text-xs"
51-
onClick={() => copyToClipboard(link.title && link.title !== "" ? link.title : link.url)}
52-
>
53-
{link.title && link.title !== "" ? link.title : link.url}
54-
</span>
55-
</Tooltip>
56-
</div>
62+
</Tooltip>
63+
</div>
5764

58-
{!isNotAllowed && (
59-
<div className="z-[1] flex flex-shrink-0 items-center gap-2">
60-
<button
61-
type="button"
62-
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
63-
onClick={(e) => {
64-
e.preventDefault();
65-
e.stopPropagation();
66-
handleEditLink(link);
67-
}}
68-
>
69-
<Pencil className="h-3 w-3 stroke-[1.5] text-custom-text-200" />
70-
</button>
71-
<a
72-
href={link.url}
73-
target="_blank"
74-
rel="noopener noreferrer"
75-
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
76-
>
77-
<ExternalLink className="h-3 w-3 stroke-[1.5] text-custom-text-200" />
78-
</a>
79-
<button
80-
type="button"
81-
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
82-
onClick={(e) => {
83-
e.preventDefault();
84-
e.stopPropagation();
85-
handleDeleteLink(link.id);
86-
}}
87-
>
88-
<Trash2 className="h-3 w-3" />
89-
</button>
90-
</div>
65+
{!isNotAllowed && (
66+
<div className="z-[1] flex flex-shrink-0 items-center gap-2">
67+
<button
68+
type="button"
69+
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
70+
onClick={(e) => {
71+
e.preventDefault();
72+
e.stopPropagation();
73+
handleEditLink(link);
74+
}}
75+
>
76+
<Pencil className="h-3 w-3 stroke-[1.5] text-custom-text-200" />
77+
</button>
78+
<a
79+
href={link.url}
80+
target="_blank"
81+
rel="noopener noreferrer"
82+
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
83+
>
84+
<ExternalLink className="h-3 w-3 stroke-[1.5] text-custom-text-200" />
85+
</a>
86+
<button
87+
type="button"
88+
className="flex items-center justify-center p-1 hover:bg-custom-background-80"
89+
onClick={(e) => {
90+
e.preventDefault();
91+
e.stopPropagation();
92+
handleDeleteLink(link.id);
93+
}}
94+
>
95+
<Trash2 className="h-3 w-3" />
96+
</button>
97+
</div>
98+
)}
99+
</div>
100+
<div className="px-5">
101+
<p className="mt-0.5 stroke-[1.5] text-xs text-custom-text-300">
102+
Added {calculateTimeAgo(link.created_at)}
103+
<br />
104+
{createdByDetails && (
105+
<>
106+
by{" "}
107+
{createdByDetails?.is_bot ? createdByDetails?.first_name + " Bot" : createdByDetails?.display_name}
108+
</>
91109
)}
92-
</div>
93-
<div className="px-5">
94-
<p className="mt-0.5 stroke-[1.5] text-xs text-custom-text-300">
95-
Added {calculateTimeAgo(link.created_at)}
96-
<br />
97-
{createdByDetails && (
98-
<>
99-
by{" "}
100-
{createdByDetails?.is_bot
101-
? createdByDetails?.first_name + " Bot"
102-
: createdByDetails?.display_name}
103-
</>
104-
)}
105-
</p>
106-
</div>
110+
</p>
107111
</div>
108-
);
109-
})}
110-
</>
111-
);
112-
}
113-
);
112+
</div>
113+
);
114+
})}
115+
</>
116+
);
117+
});

web/components/modules/sidebar.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -673,18 +673,20 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
673673
</div>
674674
)}
675675

676-
<LinksList
677-
links={moduleDetails.link_module}
678-
handleEditLink={handleEditLink}
679-
handleDeleteLink={handleDeleteLink}
680-
userAuth={{
681-
isGuest: currentProjectRole === EUserProjectRoles.GUEST,
682-
isViewer: currentProjectRole === EUserProjectRoles.VIEWER,
683-
isMember: currentProjectRole === EUserProjectRoles.MEMBER,
684-
isOwner: currentProjectRole === EUserProjectRoles.ADMIN,
685-
}}
686-
disabled={isArchived}
687-
/>
676+
{moduleId && (
677+
<LinksList
678+
moduleId={moduleId}
679+
handleEditLink={handleEditLink}
680+
handleDeleteLink={handleDeleteLink}
681+
userAuth={{
682+
isGuest: currentProjectRole === EUserProjectRoles.GUEST,
683+
isViewer: currentProjectRole === EUserProjectRoles.VIEWER,
684+
isMember: currentProjectRole === EUserProjectRoles.MEMBER,
685+
isOwner: currentProjectRole === EUserProjectRoles.ADMIN,
686+
}}
687+
disabled={isArchived}
688+
/>
689+
)}
688690
</>
689691
) : (
690692
<div className="flex items-center justify-between gap-2">

web/store/module.store.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import concat from "lodash/concat";
12
import set from "lodash/set";
23
import sortBy from "lodash/sortBy";
34
import update from "lodash/update";
@@ -372,13 +373,22 @@ export class ModulesStore implements IModuleStore {
372373
* @param data
373374
* @returns ILinkDetails
374375
*/
375-
createModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, data: Partial<ILinkDetails>) =>
376-
await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data).then((response) => {
376+
createModuleLink = async (
377+
workspaceSlug: string,
378+
projectId: string,
379+
moduleId: string,
380+
data: Partial<ILinkDetails>
381+
) => {
382+
try {
383+
const moduleLink = await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data);
377384
runInAction(() => {
378-
set(this.moduleMap, [moduleId, "link_module"], [response]);
385+
update(this.moduleMap, [moduleId, "link_module"], (moduleLinks = []) => concat(moduleLinks, moduleLink));
379386
});
380-
return response;
381-
});
387+
return moduleLink;
388+
} catch (error) {
389+
throw error;
390+
}
391+
};
382392

383393
/**
384394
* @description updates module link details
@@ -422,14 +432,19 @@ export class ModulesStore implements IModuleStore {
422432
* @param moduleId
423433
* @param linkId
424434
*/
425-
deleteModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) =>
426-
await this.moduleService.deleteModuleLink(workspaceSlug, projectId, moduleId, linkId).then(() => {
427-
const moduleDetails = this.getModuleById(moduleId);
428-
const linkModules = moduleDetails?.link_module?.filter((link) => link.id !== linkId);
435+
deleteModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => {
436+
try {
437+
const moduleLink = await this.moduleService.deleteModuleLink(workspaceSlug, projectId, moduleId, linkId);
429438
runInAction(() => {
430-
set(this.moduleMap, [moduleId, "link_module"], linkModules);
439+
update(this.moduleMap, [moduleId, "link_module"], (moduleLinks = []) =>
440+
moduleLinks.filter((link: ILinkDetails) => link.id !== linkId)
441+
);
431442
});
432-
});
443+
return moduleLink;
444+
} catch (error) {
445+
throw error;
446+
}
447+
};
433448

434449
/**
435450
* @description adds a module to favorites

0 commit comments

Comments
 (0)