fix: spliting out the project members from project store and service (#2739)
This commit is contained in:
parent
7676aab773
commit
79df59f618
66 changed files with 496 additions and 415 deletions
|
|
@ -3,7 +3,7 @@ import { observable, computed, makeObservable, action, runInAction } from "mobx"
|
|||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
import { ProjectService } from "services/project";
|
||||
import { ProjectService, ProjectMemberService } from "services/project";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import {
|
||||
|
|
@ -25,6 +25,7 @@ export interface IArchivedIssueFilterStore {
|
|||
|
||||
// services
|
||||
projectService: ProjectService;
|
||||
projectMemberService: ProjectMemberService;
|
||||
issueService: IssueService;
|
||||
|
||||
// computed
|
||||
|
|
@ -87,6 +88,7 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore {
|
|||
|
||||
// services
|
||||
projectService: ProjectService;
|
||||
projectMemberService: ProjectMemberService;
|
||||
issueService: IssueService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
|
|
@ -111,6 +113,7 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore {
|
|||
// services
|
||||
this.issueService = new IssueService();
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
}
|
||||
|
||||
computedFilter = (filters: any, filteredParams: any) => {
|
||||
|
|
@ -222,7 +225,7 @@ export class ArchivedIssueFilterStore implements IArchivedIssueFilterStore {
|
|||
|
||||
fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId);
|
||||
const memberResponse = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
|
||||
const issueProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export class MentionsStore implements IMentionsStore {
|
|||
}
|
||||
|
||||
get mentionSuggestions() {
|
||||
const projectMembers = this.rootStore.project.projectMembers;
|
||||
const projectMembers = this.rootStore.projectMember.projectMembers;
|
||||
|
||||
const suggestions =
|
||||
projectMembers === null
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { ProjectService, ProjectMemberService } from "services/project";
|
||||
import { IssueService } from "services/issue";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
|
|
@ -72,6 +72,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||
|
||||
// services
|
||||
projectService;
|
||||
projectMemberService;
|
||||
issueService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
|
|
@ -98,6 +99,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||
this.rootStore = _rootStore;
|
||||
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.issueService = new IssueService();
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +147,7 @@ export class IssueFilterStore implements IIssueFilterStore {
|
|||
|
||||
fetchUserProjectFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId);
|
||||
const memberResponse = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
|
||||
const issueProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export * from "./project_publish.store";
|
||||
export * from "./project.store";
|
||||
export * from "./project_estimates.store";
|
||||
export * from "./project_label_store";
|
||||
export * from "./project_state.store";
|
||||
export * from "./project-estimates.store";
|
||||
export * from "./project-label.store";
|
||||
export * from "./project-members.store";
|
||||
export * from "./project-publish.store";
|
||||
export * from "./project-state.store";
|
||||
|
|
|
|||
182
web/store/project/project-members.store.ts
Normal file
182
web/store/project/project-members.store.ts
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IProjectMember } from "types";
|
||||
// services
|
||||
import { ProjectMemberService } from "services/project";
|
||||
|
||||
export interface IProjectMemberStore {
|
||||
// observables
|
||||
members: {
|
||||
[projectId: string]: IProjectMember[] | null; // project_id: members
|
||||
};
|
||||
// computed
|
||||
projectMembers: IProjectMember[] | null;
|
||||
// actions
|
||||
getProjectMemberById: (memberId: string) => IProjectMember | null;
|
||||
getProjectMemberByUserId: (memberId: string) => IProjectMember | null;
|
||||
fetchProjectMembers: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
removeMemberFromProject: (workspaceSlug: string, projectId: string, memberId: string) => Promise<void>;
|
||||
updateMember: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
memberId: string,
|
||||
data: Partial<IProjectMember>
|
||||
) => Promise<IProjectMember>;
|
||||
|
||||
deleteProjectInvitation: (workspaceSlug: string, projectId: string, memberId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectMemberStore implements IProjectMemberStore {
|
||||
members: {
|
||||
[projectId: string]: IProjectMember[]; // projectId: members
|
||||
} = {};
|
||||
|
||||
// root store
|
||||
rootStore;
|
||||
// service
|
||||
projectMemberService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
members: observable.ref,
|
||||
// computed
|
||||
projectMembers: computed,
|
||||
// action
|
||||
getProjectMemberById: action,
|
||||
fetchProjectMembers: action,
|
||||
removeMemberFromProject: action,
|
||||
updateMember: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computed value of current members in the project
|
||||
*/
|
||||
get projectMembers() {
|
||||
if (!this.rootStore.project.projectId) return null;
|
||||
return this.members[this.rootStore.project.projectId] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all project information using membership id
|
||||
* @param memberId
|
||||
* @returns
|
||||
*/
|
||||
getProjectMemberById = (memberId: string) => {
|
||||
if (!this.rootStore.project.projectId) return null;
|
||||
const members = this.projectMembers;
|
||||
if (!members) return null;
|
||||
const memberInfo: IProjectMember | null = members.find((member) => member.id === memberId) || null;
|
||||
return memberInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get user information from the project members using user id
|
||||
* @param memberId
|
||||
* @returns
|
||||
*/
|
||||
getProjectMemberByUserId = (memberId: string) => {
|
||||
if (!this.rootStore.project.projectId) return null;
|
||||
const members = this.projectMembers;
|
||||
if (!members) return null;
|
||||
const memberInfo: IProjectMember | null = members.find((member) => member.member.id === memberId) || null;
|
||||
return memberInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* fetch the project members info using workspace id and project id
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
*/
|
||||
fetchProjectMembers = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const membersResponse = await this.projectMemberService.fetchProjectMembers(workspaceSlug, projectId);
|
||||
const _members = {
|
||||
...this.members,
|
||||
[projectId]: membersResponse,
|
||||
};
|
||||
runInAction(() => {
|
||||
this.members = _members;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove user from the project
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
* @param memberId
|
||||
*/
|
||||
removeMemberFromProject = async (workspaceSlug: string, projectId: string, memberId: string) => {
|
||||
const originalMembers = this.projectMembers || [];
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: this.projectMembers?.filter((member) => member.id !== memberId) || [],
|
||||
};
|
||||
});
|
||||
await this.projectMemberService.deleteProjectMember(workspaceSlug, projectId, memberId);
|
||||
await this.fetchProjectMembers(workspaceSlug, projectId);
|
||||
} catch (error) {
|
||||
console.log("Failed to delete project from project store");
|
||||
// revert back to original members in case of error
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: originalMembers,
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update member information
|
||||
* @param workspaceSlug
|
||||
* @param projectId
|
||||
* @param memberId
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
updateMember = async (workspaceSlug: string, projectId: string, memberId: string, data: Partial<IProjectMember>) => {
|
||||
const originalMembers = this.projectMembers || [];
|
||||
try {
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: (this.projectMembers || [])?.map((member) =>
|
||||
member.id === memberId ? { ...member, ...data } : member
|
||||
),
|
||||
};
|
||||
});
|
||||
const response = await this.projectMemberService.updateProjectMember(workspaceSlug, projectId, memberId, data);
|
||||
await this.fetchProjectMembers(workspaceSlug, projectId);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to update project member from project store");
|
||||
// revert back to original members in case of error
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: originalMembers,
|
||||
};
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
deleteProjectInvitation = async () => {
|
||||
try {
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IProject, IIssueLabels, IProjectMember, IEstimate } from "types";
|
||||
import { IProject, IIssueLabels, IEstimate } from "types";
|
||||
// services
|
||||
import { ProjectService, ProjectStateService, ProjectEstimateService } from "services/project";
|
||||
import { IssueService, IssueLabelService } from "services/issue";
|
||||
|
|
@ -19,9 +19,6 @@ export interface IProjectStore {
|
|||
labels: {
|
||||
[projectId: string]: IIssueLabels[] | null; // project_id: labels
|
||||
} | null;
|
||||
members: {
|
||||
[projectId: string]: IProjectMember[] | null; // project_id: members
|
||||
} | null;
|
||||
estimates: {
|
||||
[projectId: string]: IEstimate[] | null; // project_id: members
|
||||
} | null;
|
||||
|
|
@ -30,7 +27,6 @@ export interface IProjectStore {
|
|||
searchedProjects: IProject[];
|
||||
workspaceProjects: IProject[] | null;
|
||||
projectLabels: IIssueLabels[] | null;
|
||||
projectMembers: IProjectMember[] | null;
|
||||
projectEstimates: IEstimate[] | null;
|
||||
|
||||
joinedProjects: IProject[];
|
||||
|
|
@ -44,14 +40,11 @@ export interface IProjectStore {
|
|||
|
||||
getProjectById: (workspaceSlug: string, projectId: string) => IProject | null;
|
||||
getProjectLabelById: (labelId: string) => IIssueLabels | null;
|
||||
getProjectMemberById: (memberId: string) => IProjectMember | null;
|
||||
getProjectMemberByUserId: (memberId: string) => IProjectMember | null;
|
||||
getProjectEstimateById: (estimateId: string) => IEstimate | null;
|
||||
|
||||
fetchProjects: (workspaceSlug: string) => Promise<void>;
|
||||
fetchProjectDetails: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
fetchProjectLabels: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
fetchProjectMembers: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
fetchProjectEstimates: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
|
||||
addProjectToFavorites: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
|
|
@ -65,15 +58,6 @@ export interface IProjectStore {
|
|||
createProject: (workspaceSlug: string, data: any) => Promise<any>;
|
||||
updateProject: (workspaceSlug: string, projectId: string, data: Partial<IProject>) => Promise<any>;
|
||||
deleteProject: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
|
||||
// write operations
|
||||
removeMemberFromProject: (workspaceSlug: string, projectId: string, memberId: string) => Promise<void>;
|
||||
updateMember: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
memberId: string,
|
||||
data: Partial<IProjectMember>
|
||||
) => Promise<IProjectMember>;
|
||||
}
|
||||
|
||||
export class ProjectStore implements IProjectStore {
|
||||
|
|
@ -89,9 +73,6 @@ export class ProjectStore implements IProjectStore {
|
|||
labels: {
|
||||
[projectId: string]: IIssueLabels[]; // projectId: labels
|
||||
} | null = {};
|
||||
members: {
|
||||
[projectId: string]: IProjectMember[]; // projectId: members
|
||||
} | null = {};
|
||||
estimates: {
|
||||
[projectId: string]: IEstimate[]; // projectId: estimates
|
||||
} | null = {};
|
||||
|
|
@ -116,14 +97,12 @@ export class ProjectStore implements IProjectStore {
|
|||
projects: observable.ref,
|
||||
project_details: observable.ref,
|
||||
labels: observable.ref,
|
||||
members: observable.ref,
|
||||
estimates: observable.ref,
|
||||
|
||||
// computed
|
||||
searchedProjects: computed,
|
||||
workspaceProjects: computed,
|
||||
projectLabels: computed,
|
||||
projectMembers: computed,
|
||||
projectEstimates: computed,
|
||||
|
||||
currentProjectDetails: computed,
|
||||
|
|
@ -139,11 +118,9 @@ export class ProjectStore implements IProjectStore {
|
|||
|
||||
getProjectById: action,
|
||||
getProjectLabelById: action,
|
||||
getProjectMemberById: action,
|
||||
getProjectEstimateById: action,
|
||||
|
||||
fetchProjectLabels: action,
|
||||
fetchProjectMembers: action,
|
||||
fetchProjectEstimates: action,
|
||||
|
||||
addProjectToFavorites: action,
|
||||
|
|
@ -154,10 +131,6 @@ export class ProjectStore implements IProjectStore {
|
|||
createProject: action,
|
||||
updateProject: action,
|
||||
leaveProject: action,
|
||||
|
||||
// write operations
|
||||
removeMemberFromProject: action,
|
||||
updateMember: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
|
@ -209,11 +182,6 @@ export class ProjectStore implements IProjectStore {
|
|||
return this.labels?.[this.projectId] || null;
|
||||
}
|
||||
|
||||
get projectMembers() {
|
||||
if (!this.projectId) return null;
|
||||
return this.members?.[this.projectId] || null;
|
||||
}
|
||||
|
||||
get projectEstimates() {
|
||||
if (!this.projectId) return null;
|
||||
return this.estimates?.[this.projectId] || null;
|
||||
|
|
@ -281,22 +249,6 @@ export class ProjectStore implements IProjectStore {
|
|||
return labelInfo;
|
||||
};
|
||||
|
||||
getProjectMemberById = (memberId: string) => {
|
||||
if (!this.projectId) return null;
|
||||
const members = this.projectMembers;
|
||||
if (!members) return null;
|
||||
const memberInfo: IProjectMember | null = members.find((member) => member.id === memberId) || null;
|
||||
return memberInfo;
|
||||
};
|
||||
|
||||
getProjectMemberByUserId = (memberId: string) => {
|
||||
if (!this.projectId) return null;
|
||||
const members = this.projectMembers;
|
||||
if (!members) return null;
|
||||
const memberInfo: IProjectMember | null = members.find((member) => member.member.id === memberId) || null;
|
||||
return memberInfo;
|
||||
};
|
||||
|
||||
getProjectEstimateById = (estimateId: string) => {
|
||||
if (!this.projectId) return null;
|
||||
const estimates = this.projectEstimates;
|
||||
|
|
@ -327,29 +279,6 @@ export class ProjectStore implements IProjectStore {
|
|||
}
|
||||
};
|
||||
|
||||
fetchProjectMembers = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
this.loader = true;
|
||||
this.error = null;
|
||||
|
||||
const membersResponse = await this.projectService.fetchProjectMembers(workspaceSlug, projectId);
|
||||
const _members = {
|
||||
...this.members,
|
||||
[projectId]: membersResponse,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.members = _members;
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchProjectEstimates = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
this.loader = true;
|
||||
|
|
@ -576,58 +505,4 @@ export class ProjectStore implements IProjectStore {
|
|||
console.log("Failed to delete project from project store");
|
||||
}
|
||||
};
|
||||
|
||||
removeMemberFromProject = async (workspaceSlug: string, projectId: string, memberId: string) => {
|
||||
const originalMembers = this.projectMembers || [];
|
||||
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: this.projectMembers?.filter((member) => member.id !== memberId) || [],
|
||||
};
|
||||
});
|
||||
|
||||
try {
|
||||
await this.projectService.deleteProjectMember(workspaceSlug, projectId, memberId);
|
||||
await this.fetchProjectMembers(workspaceSlug, projectId);
|
||||
} catch (error) {
|
||||
console.log("Failed to delete project from project store");
|
||||
// revert back to original members in case of error
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: originalMembers,
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateMember = async (workspaceSlug: string, projectId: string, memberId: string, data: Partial<IProjectMember>) => {
|
||||
const originalMembers = this.projectMembers || [];
|
||||
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: (this.projectMembers || [])?.map((member) =>
|
||||
member.id === memberId ? { ...member, ...data } : member
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await this.projectService.updateProjectMember(workspaceSlug, projectId, memberId, data);
|
||||
await this.fetchProjectMembers(workspaceSlug, projectId);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("Failed to update project member from project store");
|
||||
// revert back to original members in case of error
|
||||
runInAction(() => {
|
||||
this.members = {
|
||||
...this.members,
|
||||
[projectId]: originalMembers,
|
||||
};
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import {
|
|||
ProjectLabelStore,
|
||||
ProjectEstimatesStore,
|
||||
IProjectEstimateStore,
|
||||
ProjectMemberStore,
|
||||
IProjectMemberStore,
|
||||
} from "store/project";
|
||||
import {
|
||||
IModuleFilterStore,
|
||||
|
|
@ -116,8 +118,8 @@ export class RootStore {
|
|||
user: IUserStore;
|
||||
theme: IThemeStore;
|
||||
appConfig: IAppConfigStore;
|
||||
|
||||
commandPalette: ICommandPaletteStore;
|
||||
|
||||
workspace: IWorkspaceStore;
|
||||
workspaceFilter: IWorkspaceFilterStore;
|
||||
workspaceMember: IWorkspaceMemberStore;
|
||||
|
|
@ -127,6 +129,8 @@ export class RootStore {
|
|||
projectState: IProjectStateStore;
|
||||
projectLabel: IProjectLabelStore;
|
||||
projectEstimates: IProjectEstimateStore;
|
||||
projectMember: IProjectMemberStore;
|
||||
|
||||
issue: IIssueStore;
|
||||
|
||||
module: IModuleStore;
|
||||
|
|
@ -191,6 +195,7 @@ export class RootStore {
|
|||
this.projectLabel = new ProjectLabelStore(this);
|
||||
this.projectEstimates = new ProjectEstimatesStore(this);
|
||||
this.projectPublish = new ProjectPublishStore(this);
|
||||
this.projectMember = new ProjectMemberStore(this);
|
||||
|
||||
this.module = new ModuleStore(this);
|
||||
this.moduleIssue = new ModuleIssueStore(this);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// mobx
|
||||
import { action, observable, runInAction, makeObservable, computed } from "mobx";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { ProjectMemberService, ProjectService } from "services/project";
|
||||
import { UserService } from "services/user.service";
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// interfaces
|
||||
|
|
@ -81,6 +81,7 @@ class UserStore implements IUserStore {
|
|||
userService;
|
||||
workspaceService;
|
||||
projectService;
|
||||
projectMemberService;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
|
|
@ -115,6 +116,7 @@ class UserStore implements IUserStore {
|
|||
this.userService = new UserService();
|
||||
this.workspaceService = new WorkspaceService();
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
}
|
||||
|
||||
get currentWorkspaceMemberInfo() {
|
||||
|
|
@ -219,7 +221,7 @@ class UserStore implements IUserStore {
|
|||
|
||||
fetchUserProjectInfo = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const response = await this.projectService.projectMemberMe(workspaceSlug, projectId);
|
||||
const response = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
|
||||
|
||||
runInAction(() => {
|
||||
this.projectMemberInfo = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue