From 79639931713d5b1f5be22b3d2e33d41445d201c4 Mon Sep 17 00:00:00 2001 From: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:34:05 +0530 Subject: [PATCH] fix: workspace settings bugs (#2743) * fix: double layout in exports * fix: typo in jira email address section * fix: workspace members not mutating * fix: removed un-used variable * fix: workspace members can't be filtered using email * fix: autocomplete in workspace delete * fix: autocomplete in project delete modal * fix: update member function in store * fix: sidebar link not active when in github/jira * style: margin top & icon inconsistency * fix: typo in create workspace * fix: workspace leave flow * fix: redirection to delete issue * fix: autocomplete off in jira api token * refactor: reduced api call, added optional chaining & removed variable with low scope --- web/components/core/activity.tsx | 9 ++- web/components/integration/github/root.tsx | 6 +- .../integration/jira/give-details.tsx | 3 +- web/components/integration/jira/root.tsx | 8 +-- .../project/delete-project-modal.tsx | 2 + .../workspace/create-workspace-form.tsx | 2 +- .../workspace/delete-workspace-modal.tsx | 2 + .../workspace/settings/members-list-item.tsx | 36 ++++++++---- .../workspace/settings/members-list.tsx | 10 +++- .../settings-layout/workspace/sidebar.tsx | 2 +- .../[workspaceSlug]/settings/exports.tsx | 12 ++-- web/store/workspace/workspace-member.store.ts | 55 +++++++++++++------ 12 files changed, 96 insertions(+), 51 deletions(-) diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index 1712dd53e..5f60a9174 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -42,9 +42,12 @@ const IssueLink = ({ activity }: { activity: IIssueActivity }) => { return ( {activity.issue_detail ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` : "Issue"} diff --git a/web/components/integration/github/root.tsx b/web/components/integration/github/root.tsx index 6d0d7e6c2..aac2b10e9 100644 --- a/web/components/integration/github/root.tsx +++ b/web/components/integration/github/root.tsx @@ -163,7 +163,7 @@ export const GithubImporterRoot: React.FC = ({ user }) => { return (
-
+
@@ -191,9 +191,7 @@ export const GithubImporterRoot: React.FC = ({ user }) => { }`} >
{index < integrationWorkflowData.length - 1 && ( diff --git a/web/components/integration/jira/give-details.tsx b/web/components/integration/jira/give-details.tsx index 8a7c841de..04d6453db 100644 --- a/web/components/integration/jira/give-details.tsx +++ b/web/components/integration/jira/give-details.tsx @@ -56,6 +56,7 @@ export const JiraGetImportDetail: React.FC = observer(() => { ref={ref} placeholder="XXXXXXXX" className="w-full" + autoComplete="off" /> )} /> @@ -94,7 +95,7 @@ export const JiraGetImportDetail: React.FC = observer(() => {

Jira Email Address

-

Enter the Gmail account that you use in Jira account

+

Enter the Email account that you use in Jira account

= ({ user }) => { }; return ( -
+
@@ -136,9 +136,7 @@ export const JiraImporterRoot: React.FC = ({ user }) => { }`} > {index < integrationWorkflowData.length - 1 && ( diff --git a/web/components/project/delete-project-modal.tsx b/web/components/project/delete-project-modal.tsx index e6b90ebec..90217e69e 100644 --- a/web/components/project/delete-project-modal.tsx +++ b/web/components/project/delete-project-modal.tsx @@ -139,6 +139,7 @@ export const DeleteProjectModal: React.FC = (props) => { hasError={Boolean(errors.projectName)} placeholder="Project name" className="mt-2 w-full" + autoComplete="off" /> )} /> @@ -162,6 +163,7 @@ export const DeleteProjectModal: React.FC = (props) => { hasError={Boolean(errors.confirmDelete)} placeholder="Enter 'delete my project'" className="mt-2 w-full" + autoComplete="off" /> )} /> diff --git a/web/components/workspace/create-workspace-form.tsx b/web/components/workspace/create-workspace-form.tsx index 67ac0cf58..a0792fe70 100644 --- a/web/components/workspace/create-workspace-form.tsx +++ b/web/components/workspace/create-workspace-form.tsx @@ -161,7 +161,7 @@ export const CreateWorkspaceForm: FC = observer((props) => { }} ref={ref} hasError={Boolean(errors.slug)} - placeholder="Enter workspace name..." + placeholder="Enter workspace url..." className="block rounded-md bg-transparent py-2 !px-0 text-sm w-full border-none" /> )} diff --git a/web/components/workspace/delete-workspace-modal.tsx b/web/components/workspace/delete-workspace-modal.tsx index 060ad8ded..3fb4a8a51 100644 --- a/web/components/workspace/delete-workspace-modal.tsx +++ b/web/components/workspace/delete-workspace-modal.tsx @@ -141,6 +141,7 @@ export const DeleteWorkspaceModal: React.FC = observer((props) => { hasError={Boolean(errors.workspaceName)} placeholder="Workspace name" className="mt-2 w-full" + autoComplete="off" /> )} /> @@ -165,6 +166,7 @@ export const DeleteWorkspaceModal: React.FC = observer((props) => { hasError={Boolean(errors.confirmDelete)} placeholder="Enter 'delete my workspace'" className="mt-2 w-full" + autoComplete="off" /> )} /> diff --git a/web/components/workspace/settings/members-list-item.tsx b/web/components/workspace/settings/members-list-item.tsx index 3129e63d7..d98846e74 100644 --- a/web/components/workspace/settings/members-list-item.tsx +++ b/web/components/workspace/settings/members-list-item.tsx @@ -1,6 +1,7 @@ import { useState, FC } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; +import { mutate } from "swr"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // hooks @@ -39,7 +40,7 @@ export const WorkspaceMembersListItem: FC = (props) => { // store const { workspaceMember: { removeMember, updateMember, deleteWorkspaceInvitation }, - user: { currentWorkspaceMemberInfo, currentWorkspaceRole }, + user: { currentWorkspaceMemberInfo, currentWorkspaceRole, currentUser, currentUserSettings }, } = useMobxStore(); const isAdmin = currentWorkspaceRole === 20; // states @@ -51,14 +52,22 @@ export const WorkspaceMembersListItem: FC = (props) => { if (!workspaceSlug) return; if (member.member) - await removeMember(workspaceSlug.toString(), member.id).catch((err) => { - const error = err?.error; - setToastAlert({ - type: "error", - title: "Error", - message: error || "Something went wrong", + await removeMember(workspaceSlug.toString(), member.id) + .then(() => { + const memberId = member.memberId; + + if (memberId === currentUser?.id && currentUserSettings) { + if (currentUserSettings.workspace?.invites > 0) router.push("/invitations"); + else router.push("/create-workspace"); + } + }) + .catch((err) => { + setToastAlert({ + type: "error", + title: "Error", + message: err?.error || "Something went wrong", + }); }); - }); else await deleteWorkspaceInvitation(workspaceSlug.toString(), member.id) .then(() => { @@ -69,12 +78,17 @@ export const WorkspaceMembersListItem: FC = (props) => { }); }) .catch((err) => { - const error = err?.error; - setToastAlert({ type: "error", title: "Error", - message: error || "Something went wrong", + message: err?.error || "Something went wrong", + }); + }) + .finally(() => { + mutate(`WORKSPACE_INVITATIONS_${workspaceSlug.toString()}`, (prevData: any) => { + if (!prevData) return prevData; + + return prevData.filter((item: any) => item.id !== member.id); }); }); }; diff --git a/web/components/workspace/settings/members-list.tsx b/web/components/workspace/settings/members-list.tsx index ef94a44e8..b4f263c49 100644 --- a/web/components/workspace/settings/members-list.tsx +++ b/web/components/workspace/settings/members-list.tsx @@ -29,9 +29,15 @@ export const WorkspaceMembersList: FC<{ searchQuery: string }> = observer(({ sea ); const searchedMembers = workspaceMembersWithInvitations?.filter((member: any) => { - const fullName = `${member.first_name} ${member.last_name}`.toLowerCase(); + const email = member.email?.toLowerCase(); const displayName = member.display_name.toLowerCase(); - return displayName.includes(searchQuery.toLowerCase()) || fullName.includes(searchQuery.toLowerCase()); + const fullName = `${member.first_name} ${member.last_name}`.toLowerCase(); + + return ( + displayName.includes(searchQuery.toLowerCase()) || + fullName.includes(searchQuery.toLowerCase()) || + email?.includes(searchQuery.toLowerCase()) + ); }); if ( diff --git a/web/layouts/settings-layout/workspace/sidebar.tsx b/web/layouts/settings-layout/workspace/sidebar.tsx index caf4f8358..34ef39dd1 100644 --- a/web/layouts/settings-layout/workspace/sidebar.tsx +++ b/web/layouts/settings-layout/workspace/sidebar.tsx @@ -64,7 +64,7 @@ export const WorkspaceSettingsSidebar = () => {
( -
-
-

Exports

-
- -
+
+
+

Exports

+
+ +
); ExportsPage.getLayout = function getLayout(page: ReactElement) { diff --git a/web/store/workspace/workspace-member.store.ts b/web/store/workspace/workspace-member.store.ts index 010023736..b9803d1f1 100644 --- a/web/store/workspace/workspace-member.store.ts +++ b/web/store/workspace/workspace-member.store.ts @@ -208,29 +208,38 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore { * @param data */ updateMember = async (workspaceSlug: string, memberId: string, data: Partial) => { - const members = this.members?.[workspaceSlug]; - members?.map((m) => (m.id === memberId ? { ...m, ...data } : m)); + const originalMembers = [...this.members?.[workspaceSlug]]; // in case of error, we will revert back to original members + + const members = [...this.members?.[workspaceSlug]]; + + const index = members.findIndex((m) => m.id === memberId); + members[index] = { ...members[index], ...data }; + + // optimistic update + runInAction(() => { + this.loader = true; + this.error = null; + this.members = { + ...this.members, + [workspaceSlug]: members, + }; + }); try { - runInAction(() => { - this.loader = true; - this.error = null; - }); - await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberId, data); runInAction(() => { this.loader = false; this.error = null; - this.members = { - ...this.members, - [workspaceSlug]: members, - }; }); } catch (error) { runInAction(() => { this.loader = false; this.error = error; + this.members = { + ...this.members, + [workspaceSlug]: originalMembers, + }; }); throw error; @@ -243,8 +252,20 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore { * @param memberId */ removeMember = async (workspaceSlug: string, memberId: string) => { - const members = this.members?.[workspaceSlug]; - members?.filter((m) => m.id !== memberId); + const members = [...this.members?.[workspaceSlug]]; + const originalMembers = this.members?.[workspaceSlug]; // in case of error, we will revert back to original members + + // removing member from the array + const index = members.findIndex((m) => m.id === memberId); + members.splice(index, 1); + + // optimistic update + runInAction(() => { + this.members = { + ...this.members, + [workspaceSlug]: members, + }; + }); try { runInAction(() => { @@ -257,15 +278,15 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore { runInAction(() => { this.loader = false; this.error = null; - this.members = { - ...this.members, - [workspaceSlug]: members, - }; }); } catch (error) { runInAction(() => { this.loader = false; this.error = error; + this.members = { + ...this.members, + [workspaceSlug]: originalMembers, + }; }); throw error;