Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { SettingsMobileNav } from "@/components/settings/mobile";
import { WORKSPACE_SETTINGS_ACCESS } from "@plane/constants";
import type { EUserWorkspaceRoles } from "@plane/types";
// plane web components
import { WorkspaceSettingsRightSidebar } from "@/plane-web/components/workspace/right-sidebar";
import { SettingsRightSidebar } from "@/plane-web/components/settings/right-sidebar";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
// local components
Expand Down Expand Up @@ -48,7 +48,7 @@ const WorkspaceSettingLayout = observer(function WorkspaceSettingLayout({ params
<div className="w-full h-full overflow-y-scroll md:pt-page-y">
<Outlet />
</div>
<WorkspaceSettingsRightSidebar workspaceSlug={workspaceSlug} />
<SettingsRightSidebar workspaceSlug={workspaceSlug} />
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const WorkspaceMembersSettingsPage = observer(function WorkspaceMembersSettingsP
const {
workspace: { workspaceMemberIds, inviteMembersToWorkspace, filtersStore },
} = useMember();
const { currentWorkspace, mutateWorkspaceMembersActivity } = useWorkspace();
const { currentWorkspace } = useWorkspace();
const { t } = useTranslation();

// derived values
Expand All @@ -55,7 +55,6 @@ const WorkspaceMembersSettingsPage = observer(function WorkspaceMembersSettingsP
const handleWorkspaceInvite = async (data: IWorkspaceBulkInviteFormData) => {
try {
await inviteMembersToWorkspace(workspaceSlug, data);
void mutateWorkspaceMembersActivity(workspaceSlug);

setInviteModal(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import { SettingsMobileNav } from "@/components/settings/mobile";
import { ProjectSettingsSidebar } from "@/components/settings/project/sidebar";
// plane web imports
import { ProjectAuthWrapper } from "@/plane-web/layouts/project-wrapper";
import { SettingsRightSidebar } from "@/plane-web/components/settings/right-sidebar";
// types
import type { Route } from "./+types/layout";

function ProjectDetailSettingsLayout({ params }: Route.ComponentProps) {
export const ProjectDetailSettingsLayout = observer(function ProjectDetailSettingsLayout({
params,
}: Route.ComponentProps) {
const { workspaceSlug, projectId } = params;
// router
const pathname = usePathname();
Expand All @@ -24,10 +27,11 @@ function ProjectDetailSettingsLayout({ params }: Route.ComponentProps) {
<div className="w-full h-full overflow-y-scroll md:pt-page-y">
<Outlet />
</div>
<SettingsRightSidebar workspaceSlug={workspaceSlug} projectId={projectId} />
</ProjectAuthWrapper>
</div>
</>
);
}
});

export default observer(ProjectDetailSettingsLayout);
export default ProjectDetailSettingsLayout;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { observer } from "mobx-react";

type TProjectMembersActivityButtonProps = { workspaceSlug: string; projectId: string };

export const ProjectMembersActivityButton = observer(function ProjectMembersActivityButton(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
props: TProjectMembersActivityButtonProps
) {
return <></>;
});
10 changes: 10 additions & 0 deletions apps/web/ce/components/settings/right-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { observer } from "mobx-react";

type TSettingsRightSidebarProps = { workspaceSlug: string; projectId?: string };

export const SettingsRightSidebar = observer(function SettingsRightSidebar(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
props: TSettingsRightSidebarProps
) {
return <></>;
});
1 change: 0 additions & 1 deletion apps/web/ce/components/workspace/right-sidebar/index.ts

This file was deleted.

10 changes: 0 additions & 10 deletions apps/web/ce/components/workspace/right-sidebar/root.tsx

This file was deleted.

9 changes: 9 additions & 0 deletions apps/web/ce/store/member/project-member.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,13 @@ export class ProjectMemberStore extends BaseProjectMemberStore implements IProje
* @param userId - The ID of the user to remove from the project
*/
processMemberRemoval = (projectId: string, userId: string) => this.handleMemberRemoval(projectId, userId);

/**
* @description Mutate project members activity
* @param workspaceSlug
* @param projectId
*/
mutateProjectMembersActivity = async (_workspaceSlug: string, _projectId: string) => {
// No-op in default/CE version
};
}
5 changes: 5 additions & 0 deletions apps/web/core/components/project/member-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { useUserPermissions } from "@/hooks/store/user";
import { MemberListFiltersDropdown } from "./dropdowns/filters/member-list";
import { ProjectMemberListItem } from "./member-list-item";
import { SendProjectInvitationModal } from "./send-project-invitation-modal";
// plane web components
import { ProjectMembersActivityButton } from "@/plane-web/components/projects/members/members-activity-button";

type TProjectMemberListProps = {
projectId: string;
Expand Down Expand Up @@ -84,6 +86,7 @@ export const ProjectMemberList = observer(function ProjectMemberList(props: TPro
className="w-full max-w-[234px] border-none bg-transparent text-13 focus:outline-none placeholder:text-placeholder"
placeholder="Search"
value={searchQuery}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
onChange={(e) => setSearchQuery(e.target.value)}
/>
Expand All @@ -93,9 +96,11 @@ export const ProjectMemberList = observer(function ProjectMemberList(props: TPro
handleUpdate={handleRoleFilterUpdate}
memberType="project"
/>
{isAdmin && <ProjectMembersActivityButton workspaceSlug={workspaceSlug} projectId={projectId} />}
{isAdmin && (
<Button
variant="primary"
size="lg"
onClick={() => {
setInviteModal(true);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { ConfirmWorkspaceMemberRemove } from "@/components/workspace/confirm-wor
import { captureClick } from "@/helpers/event-tracker.helper";
import { useMember } from "@/hooks/store/use-member";
import { useUserPermissions } from "@/hooks/store/user";
import { useWorkspace } from "@/hooks/store/use-workspace";

type Props = {
invitationId: string;
Expand All @@ -32,7 +31,6 @@ export const WorkspaceInvitationsListItem = observer(function WorkspaceInvitatio
const { t } = useTranslation();
// store hooks
const { allowPermissions, workspaceInfoBySlug } = useUserPermissions();
const { mutateWorkspaceMembersActivity } = useWorkspace();
const {
workspace: { updateMemberInvitation, deleteMemberInvitation, getWorkspaceInvitationDetails },
} = useMember();
Expand Down Expand Up @@ -61,7 +59,6 @@ export const WorkspaceInvitationsListItem = observer(function WorkspaceInvitatio
title: "Success!",
message: "Invitation removed successfully.",
});
void mutateWorkspaceMembersActivity(workspaceSlug);
} catch (err: unknown) {
const error = err as { error?: string };
setToast({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { getFileURL } from "@plane/utils";
// hooks
import { useMember } from "@/hooks/store/use-member";
import { useUser, useUserPermissions } from "@/hooks/store/user";
import { useWorkspace } from "@/hooks/store/use-workspace";
// plane web constants

export interface RowData {
Expand Down Expand Up @@ -121,7 +120,6 @@ export const AccountTypeColumn = observer(function AccountTypeColumn(props: Acco
const {
workspace: { updateMember },
} = useMember();
const { mutateWorkspaceMembersActivity } = useWorkspace();
const { data: currentUser } = useUser();

// derived values
Expand Down Expand Up @@ -156,7 +154,6 @@ export const AccountTypeColumn = observer(function AccountTypeColumn(props: Acco
await updateMember(workspaceSlug.toString(), rowData.member.id, {
role: value as unknown as EUserPermissions,
});
void mutateWorkspaceMembersActivity(workspaceSlug);
} catch (err: unknown) {
const error = err as { error?: string | string[] };
const errorString = Array.isArray(error?.error) ? error.error[0] : error?.error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const WorkspaceMembersListItem = observer(function WorkspaceMembersListIt
workspace: { removeMemberFromWorkspace },
} = useMember();
const { leaveWorkspace } = useUserPermissions();
const { getWorkspaceRedirectionUrl, mutateWorkspaceMembersActivity } = useWorkspace();
const { getWorkspaceRedirectionUrl } = useWorkspace();
const { fetchCurrentUserSettings } = useUserSettings();
const { t } = useTranslation();
// derived values
Expand Down Expand Up @@ -76,7 +76,6 @@ export const WorkspaceMembersListItem = observer(function WorkspaceMembersListIt

try {
await removeMemberFromWorkspace(workspaceSlug.toString(), memberId);
void mutateWorkspaceMembersActivity(workspaceSlug);
} catch (err: unknown) {
const error = err as { error?: string };
setToast({
Expand Down
6 changes: 4 additions & 2 deletions apps/web/core/constants/fetch-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ export const APPLICATION_BY_CLIENT_ID = (clientId: string) => `APPLICATION_BY_CL
export const APPLICATION_CATEGORIES_LIST = () => `APPLICATION_CATEGORIES_LIST`;

// project level keys
export const PROJECT_DETAILS = (workspaceSlug: string, projectId: string) =>
export const PROJECT_DETAILS = (_workspaceSlug: string, projectId: string) =>
`PROJECT_DETAILS_${projectId.toString().toUpperCase()}`;

export const PROJECT_ME_INFORMATION = (workspaceSlug: string, projectId: string) =>
export const PROJECT_ME_INFORMATION = (_workspaceSlug: string, projectId: string) =>
`PROJECT_ME_INFORMATION_${projectId.toString().toUpperCase()}`;

export const PROJECT_LABELS = (projectId: string, projectRole: EUserPermissions | undefined) =>
Expand All @@ -163,6 +163,8 @@ export const PROJECT_LABELS = (projectId: string, projectRole: EUserPermissions
export const PROJECT_MEMBERS = (projectId: string, projectRole: EUserPermissions | undefined) =>
`PROJECT_MEMBERS_${projectId.toString().toUpperCase()}_${projectRole}`;

export const PROJECT_MEMBER_ACTIVITY = (projectId: string) => `PROJECT_MEMBER_ACTIVITY_${projectId.toUpperCase()}`;

export const PROJECT_STATES = (projectId: string, projectRole: EUserPermissions | undefined) =>
`PROJECT_STATES_${projectId.toString().toUpperCase()}_${projectRole}`;

Expand Down
21 changes: 15 additions & 6 deletions apps/web/core/store/member/project/base-project-member.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export interface IBaseProjectMemberStore {
role: EUserProjectRoles
) => Promise<TProjectMembership>;
removeMemberFromProject: (workspaceSlug: string, projectId: string, userId: string) => Promise<void>;
mutateProjectMembersActivity: (workspaceSlug: string, projectId: string) => Promise<void>;
}

export abstract class BaseProjectMemberStore implements IBaseProjectMemberStore {
Expand Down Expand Up @@ -315,13 +316,13 @@ export abstract class BaseProjectMemberStore implements IBaseProjectMemberStore
});
});
});
update(this.projectRoot.projectMap, [projectId, "members"], (memberIds) =>
update(this.projectRoot.projectMap, [projectId, "members"], (memberIds: string[]) =>
uniq([...memberIds, ...data.members.map((m) => m.member_id)])
);
this.projectRoot.projectMap[projectId].members = this.projectRoot.projectMap?.[projectId]?.members?.concat(
data.members.map((m) => m.member_id)
);

void this.mutateProjectMembersActivity(workspaceSlug, projectId);
return response;
});

Expand Down Expand Up @@ -375,6 +376,7 @@ export abstract class BaseProjectMemberStore implements IBaseProjectMemberStore
role,
}
);
void this.mutateProjectMembersActivity(workspaceSlug, projectId);
return response;
} catch (error) {
// revert back to original members in case of error
Expand Down Expand Up @@ -429,11 +431,11 @@ export abstract class BaseProjectMemberStore implements IBaseProjectMemberStore
removeMemberFromProject = async (workspaceSlug: string, projectId: string, userId: string) => {
const memberDetails = this.getProjectMemberDetails(userId, projectId);
if (!memberDetails || !memberDetails?.id) throw new Error("Member not found");
await this.projectMemberService.deleteProjectMember(workspaceSlug, projectId, memberDetails?.id).then(() => {
runInAction(() => {
this.processMemberRemoval(projectId, userId);
});
await this.projectMemberService.deleteProjectMember(workspaceSlug, projectId, memberDetails?.id);
runInAction(() => {
this.processMemberRemoval(projectId, userId);
});
void this.mutateProjectMembersActivity(workspaceSlug, projectId);
};

/**
Expand Down Expand Up @@ -501,4 +503,11 @@ export abstract class BaseProjectMemberStore implements IBaseProjectMemberStore
throw error;
}
};

/**
* Mutate project members activity
* @param workspaceSlug
* @param projectId
*/
abstract mutateProjectMembersActivity(workspaceSlug: string, projectId: string): Promise<void>;
}
38 changes: 21 additions & 17 deletions apps/web/core/store/member/workspace/workspace-member.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { computedFn } from "mobx-utils";
// types
import type { EUserPermissions } from "@plane/constants";
import type { IWorkspaceBulkInviteFormData, IWorkspaceMember, IWorkspaceMemberInvitation } from "@plane/types";
// plane-web constants
// plane-web imports
import type { RootStore } from "@/plane-web/store/root.store";
// services
import { WorkspaceService } from "@/plane-web/services";
// types
import type { IRouterStore } from "@/store/router.store";
import type { IUserStore } from "@/store/user";
// store
import type { CoreRootStore } from "../../root.store";
import type { IMemberRootStore } from "../index.ts";
import type { IWorkspaceMemberFiltersStore } from "./workspace-member-filters.store";
import { WorkspaceMemberFiltersStore } from "./workspace-member-filters.store";
Expand Down Expand Up @@ -69,10 +69,11 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
routerStore: IRouterStore;
userStore: IUserStore;
memberRoot: IMemberRootStore;
rootStore: RootStore;
// services
workspaceService;

constructor(_memberRoot: IMemberRootStore, _rootStore: CoreRootStore) {
constructor(_memberRoot: IMemberRootStore, _rootStore: RootStore) {
makeObservable(this, {
// observables
workspaceMemberMap: observable,
Expand All @@ -95,6 +96,7 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
this.routerStore = _rootStore.router;
this.userStore = _rootStore.user;
this.memberRoot = _memberRoot;
this.rootStore = _rootStore;
// services
this.workspaceService = new WorkspaceService();
}
Expand Down Expand Up @@ -259,6 +261,7 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
set(this.workspaceMemberMap, [workspaceSlug, userId, "role"], data.role);
});
await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberDetails.id, data);
void this.rootStore.workspaceRoot.mutateWorkspaceMembersActivity(workspaceSlug);
} catch (error) {
// revert back to original members in case of error
runInAction(() => {
Expand All @@ -276,11 +279,11 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
removeMemberFromWorkspace = async (workspaceSlug: string, userId: string) => {
const memberDetails = this.getWorkspaceMemberDetails(userId);
if (!memberDetails) throw new Error("Member not found");
await this.workspaceService.deleteWorkspaceMember(workspaceSlug, memberDetails?.id).then(() => {
runInAction(() => {
set(this.workspaceMemberMap, [workspaceSlug, userId, "is_active"], false);
});
await this.workspaceService.deleteWorkspaceMember(workspaceSlug, memberDetails?.id);
runInAction(() => {
set(this.workspaceMemberMap, [workspaceSlug, userId, "is_active"], false);
});
void this.rootStore.workspaceRoot.mutateWorkspaceMembersActivity(workspaceSlug);
};

/**
Expand All @@ -301,9 +304,9 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
* @param data
*/
inviteMembersToWorkspace = async (workspaceSlug: string, data: IWorkspaceBulkInviteFormData) => {
const response = await this.workspaceService.inviteWorkspace(workspaceSlug, data);
await this.workspaceService.inviteWorkspace(workspaceSlug, data);
await this.fetchWorkspaceMemberInvitations(workspaceSlug);
return response;
void this.rootStore.workspaceRoot.mutateWorkspaceMembersActivity(workspaceSlug);
};

/**
Expand All @@ -317,7 +320,7 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
invitationId: string,
data: Partial<IWorkspaceMemberInvitation>
) => {
const originalMemberInvitations = [...this.workspaceMemberInvitations?.[workspaceSlug]]; // in case of error, we will revert back to original members
const originalMemberInvitations = [...(this.workspaceMemberInvitations?.[workspaceSlug] ?? [])]; // in case of error, we will revert back to original members
try {
const memberInvitations = originalMemberInvitations?.map((invitation) => ({
...invitation,
Expand All @@ -342,14 +345,15 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
* @param workspaceSlug
* @param memberId
*/
deleteMemberInvitation = async (workspaceSlug: string, invitationId: string) =>
await this.workspaceService.deleteWorkspaceInvitations(workspaceSlug.toString(), invitationId).then(() => {
runInAction(() => {
this.workspaceMemberInvitations[workspaceSlug] = this.workspaceMemberInvitations[workspaceSlug].filter(
(inv) => inv.id !== invitationId
);
});
deleteMemberInvitation = async (workspaceSlug: string, invitationId: string) => {
await this.workspaceService.deleteWorkspaceInvitations(workspaceSlug.toString(), invitationId);
runInAction(() => {
this.workspaceMemberInvitations[workspaceSlug] = this.workspaceMemberInvitations[workspaceSlug].filter(
(inv) => inv.id !== invitationId
);
});
void this.rootStore.workspaceRoot.mutateWorkspaceMembersActivity(workspaceSlug);
};

isUserSuspended = computedFn((userId: string, workspaceSlug: string) => {
if (!workspaceSlug) return false;
Expand Down
Loading