chore: issue activity, comments, and comment reaction store and component restructure (#3428)

* fix: issue activity and comment change

* chore: posthog enabled

* chore: comment creation in activity

* chore: comment crud in store mutation

* fix: issue activity/ comments `disable` and `showAccessSpecifier` logic.

* chore: comment reaction serializer change

* conflicts: merge conflicts resolved

* conflicts: merge conflicts resolved

* chore: add issue activity/ comments to peek-overview.
* imporve `showAccessIdentifier` logic.

* chore: remove quotes from issue activity.

* chore: use `projectLabels` instead of `workspaceLabels` in labels activity.

* fix: project publish `is_deployed` not updating bug.

* cleanup

* fix: posthog enabled

* fix: typos and the comment endpoint updates

* fix: issue activity icons update

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
This commit is contained in:
guru_sainath 2024-01-23 13:28:58 +05:30 committed by GitHub
parent bb50df0dff
commit f88109ef04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 2555 additions and 395 deletions

View file

@ -271,6 +271,11 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
const issueToCycle = await this.issueService.addIssueToCycle(workspaceSlug, projectId, cycleId, {
issues: issueIds,
});
issueIds.map((issueId) => {
this.rootIssueStore.issues.updateIssue(issueId, { cycle_id: cycleId });
});
return issueToCycle;
} catch (error) {
throw error;

View file

@ -1,57 +1,61 @@
import { action, computed, makeObservable, observable, runInAction } from "mobx";
import { action, makeObservable, observable, runInAction } from "mobx";
import set from "lodash/set";
import sortBy from "lodash/sortBy";
import update from "lodash/update";
import concat from "lodash/concat";
import uniq from "lodash/uniq";
// services
import { IssueService } from "services/issue";
import { IssueActivityService } from "services/issue";
// types
import { IIssueDetail } from "./root.store";
import { TIssueActivity, TIssueActivityIdMap, TIssueActivityMap } from "@plane/types";
import { TIssueActivityComment, TIssueActivity, TIssueActivityMap, TIssueActivityIdMap } from "@plane/types";
export type TActivityLoader = "fetch" | "mutate" | undefined;
export interface IIssueActivityStoreActions {
// actions
fetchActivities: (workspaceSlug: string, projectId: string, issueId: string) => Promise<TIssueActivity[]>;
fetchActivities: (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType?: TActivityLoader
) => Promise<TIssueActivity[]>;
}
export interface IIssueActivityStore extends IIssueActivityStoreActions {
// observables
loader: TActivityLoader;
activities: TIssueActivityIdMap;
activityMap: TIssueActivityMap;
// computed
issueActivities: string[] | undefined;
// helper methods
getActivitiesByIssueId: (issueId: string) => string[] | undefined;
getActivityById: (activityId: string) => TIssueActivity | undefined;
getActivityCommentByIssueId: (issueId: string) => TIssueActivityComment[] | undefined;
}
export class IssueActivityStore implements IIssueActivityStore {
// observables
loader: TActivityLoader = "fetch";
activities: TIssueActivityIdMap = {};
activityMap: TIssueActivityMap = {};
// root store
rootIssueDetailStore: IIssueDetail;
// services
issueService;
issueActivityService;
constructor(rootStore: IIssueDetail) {
makeObservable(this, {
// observables
loader: observable.ref,
activities: observable,
activityMap: observable,
// computed
issueActivities: computed,
// actions
fetchActivities: action,
});
// root store
this.rootIssueDetailStore = rootStore;
// services
this.issueService = new IssueService();
}
// computed
get issueActivities() {
const issueId = this.rootIssueDetailStore.peekIssue?.issueId;
if (!issueId) return undefined;
return this.activities[issueId] ?? undefined;
this.issueActivityService = new IssueActivityService();
}
// helper methods
@ -65,17 +69,73 @@ export class IssueActivityStore implements IIssueActivityStore {
return this.activityMap[activityId] ?? undefined;
};
getActivityCommentByIssueId = (issueId: string) => {
if (!issueId) return undefined;
let activityComments: TIssueActivityComment[] = [];
const activities = this.getActivitiesByIssueId(issueId) || [];
const comments = this.rootIssueDetailStore.comment.getCommentsByIssueId(issueId) || [];
activities.forEach((activityId) => {
const activity = this.getActivityById(activityId);
if (!activity) return;
activityComments.push({
id: activity.id,
activity_type: "ACTIVITY",
created_at: activity.created_at,
});
});
comments.forEach((commentId) => {
const comment = this.rootIssueDetailStore.comment.getCommentById(commentId);
if (!comment) return;
activityComments.push({
id: comment.id,
activity_type: "COMMENT",
created_at: comment.created_at,
});
});
activityComments = sortBy(activityComments, "created_at");
activityComments = activityComments.map((activityComment) => ({
id: activityComment.id,
activity_type: activityComment.activity_type,
}));
return activityComments;
};
// actions
fetchActivities = async (workspaceSlug: string, projectId: string, issueId: string) => {
fetchActivities = async (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType: TActivityLoader = "fetch"
) => {
try {
const activities = await this.issueService.getIssueActivities(workspaceSlug, projectId, issueId);
this.loader = loaderType;
let props = {};
const _activityIds = this.getActivitiesByIssueId(issueId);
if (_activityIds && _activityIds.length > 0) {
const _activity = this.getActivityById(_activityIds[_activityIds.length - 1]);
if (_activity) props = { created_at__gt: _activity.created_at };
}
const activities = await this.issueActivityService.getIssueActivities(workspaceSlug, projectId, issueId, props);
const activityIds = activities.map((activity) => activity.id);
runInAction(() => {
set(this.activities, issueId, activityIds);
update(this.activities, issueId, (_activityIds) => {
if (!_activityIds) return activityIds;
return uniq(concat(_activityIds, activityIds));
});
activities.forEach((activity) => {
set(this.activityMap, activity.id, activity);
});
this.loader = undefined;
});
return activities;

View file

@ -1,31 +1,55 @@
import { action, makeObservable, runInAction } from "mobx";
import { action, makeObservable, observable, runInAction } from "mobx";
import set from "lodash/set";
import update from "lodash/update";
import concat from "lodash/concat";
import uniq from "lodash/uniq";
import pull from "lodash/pull";
// services
import { IssueCommentService } from "services/issue";
// types
import { IIssueDetail } from "./root.store";
import { TIssueActivity } from "@plane/types";
import { TIssueComment, TIssueCommentMap, TIssueCommentIdMap } from "@plane/types";
export type TCommentLoader = "fetch" | "create" | "update" | "delete" | "mutate" | undefined;
export interface IIssueCommentStoreActions {
fetchComments: (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType?: TCommentLoader
) => Promise<TIssueComment[]>;
createComment: (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssueActivity>
data: Partial<TIssueComment>
) => Promise<any>;
updateComment: (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueActivity>
data: Partial<TIssueComment>
) => Promise<any>;
removeComment: (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => Promise<any>;
}
export interface IIssueCommentStore extends IIssueCommentStoreActions {}
export interface IIssueCommentStore extends IIssueCommentStoreActions {
// observables
loader: TCommentLoader;
comments: TIssueCommentIdMap;
commentMap: TIssueCommentMap;
// helper methods
getCommentsByIssueId: (issueId: string) => string[] | undefined;
getCommentById: (activityId: string) => TIssueComment | undefined;
}
export class IssueCommentStore implements IIssueCommentStore {
// observables
loader: TCommentLoader = "fetch";
comments: TIssueCommentIdMap = {};
commentMap: TIssueCommentMap = {};
// root store
rootIssueDetail: IIssueDetail;
// services
@ -33,7 +57,12 @@ export class IssueCommentStore implements IIssueCommentStore {
constructor(rootStore: IIssueDetail) {
makeObservable(this, {
// observables
loader: observable.ref,
comments: observable,
commentMap: observable,
// actions
fetchComments: action,
createComment: action,
updateComment: action,
removeComment: action,
@ -44,13 +73,64 @@ export class IssueCommentStore implements IIssueCommentStore {
this.issueCommentService = new IssueCommentService();
}
createComment = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssueActivity>) => {
// helper methods
getCommentsByIssueId = (issueId: string) => {
if (!issueId) return undefined;
return this.comments[issueId] ?? undefined;
};
getCommentById = (commentId: string) => {
if (!commentId) return undefined;
return this.commentMap[commentId] ?? undefined;
};
fetchComments = async (
workspaceSlug: string,
projectId: string,
issueId: string,
loaderType: TCommentLoader = "fetch"
) => {
try {
this.loader = loaderType;
let props = {};
const _commentIds = this.getCommentsByIssueId(issueId);
if (_commentIds && _commentIds.length > 0) {
const _comment = this.getCommentById(_commentIds[_commentIds.length - 1]);
if (_comment) props = { created_at__gt: _comment.created_at };
}
const comments = await this.issueCommentService.getIssueComments(workspaceSlug, projectId, issueId, props);
const commentIds = comments.map((comment) => comment.id);
runInAction(() => {
update(this.comments, issueId, (_commentIds) => {
if (!_commentIds) return commentIds;
return uniq(concat(_commentIds, commentIds));
});
comments.forEach((comment) => {
this.rootIssueDetail.commentReaction.applyCommentReactions(comment.id, comment?.comment_reactions || []);
set(this.commentMap, comment.id, comment);
});
this.loader = undefined;
});
return comments;
} catch (error) {
throw error;
}
};
createComment = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssueComment>) => {
try {
const response = await this.issueCommentService.createIssueComment(workspaceSlug, projectId, issueId, data);
runInAction(() => {
this.rootIssueDetail.activity.activities[issueId].push(response.id);
set(this.rootIssueDetail.activity.activityMap, response.id, response);
update(this.comments, issueId, (_commentIds) => {
if (!_commentIds) return [response.id];
return uniq(concat(_commentIds, [response.id]));
});
set(this.commentMap, response.id, response);
});
return response;
@ -64,12 +144,12 @@ export class IssueCommentStore implements IIssueCommentStore {
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueActivity>
data: Partial<TIssueComment>
) => {
try {
runInAction(() => {
Object.keys(data).forEach((key) => {
set(this.rootIssueDetail.activity.activityMap, [commentId, key], data[key as keyof TIssueActivity]);
set(this.commentMap, [commentId, key], data[key as keyof TIssueComment]);
});
});
@ -92,14 +172,10 @@ export class IssueCommentStore implements IIssueCommentStore {
try {
const response = await this.issueCommentService.deleteIssueComment(workspaceSlug, projectId, issueId, commentId);
const reactionIndex = this.rootIssueDetail.activity.activities[issueId].findIndex(
(_comment) => _comment === commentId
);
if (reactionIndex >= 0)
runInAction(() => {
this.rootIssueDetail.activity.activities[issueId].splice(reactionIndex, 1);
delete this.rootIssueDetail.activity.activityMap[commentId];
});
runInAction(() => {
pull(this.comments[issueId], commentId);
delete this.commentMap[commentId];
});
return response;
} catch (error) {

View file

@ -1,10 +1,16 @@
import { action, makeObservable, observable, runInAction } from "mobx";
import set from "lodash/set";
import update from "lodash/update";
import concat from "lodash/concat";
import find from "lodash/find";
import pull from "lodash/pull";
// services
import { IssueReactionService } from "services/issue";
// types
import { IIssueDetail } from "./root.store";
import { TIssueCommentReaction, TIssueCommentReactionIdMap, TIssueCommentReactionMap } from "@plane/types";
// helpers
import { groupReactions } from "helpers/emoji.helper";
export interface IIssueCommentReactionStoreActions {
// actions
@ -13,6 +19,7 @@ export interface IIssueCommentReactionStoreActions {
projectId: string,
commentId: string
) => Promise<TIssueCommentReaction[]>;
applyCommentReactions: (commentId: string, commentReactions: TIssueCommentReaction[]) => void;
createCommentReaction: (
workspaceSlug: string,
projectId: string,
@ -23,7 +30,8 @@ export interface IIssueCommentReactionStoreActions {
workspaceSlug: string,
projectId: string,
commentId: string,
reaction: string
reaction: string,
userId: string
) => Promise<any>;
}
@ -32,8 +40,9 @@ export interface IIssueCommentReactionStore extends IIssueCommentReactionStoreAc
commentReactions: TIssueCommentReactionIdMap;
commentReactionMap: TIssueCommentReactionMap;
// helper methods
getCommentReactionsByCommentId: (commentId: string) => string[] | undefined;
getCommentReactionsByCommentId: (commentId: string) => { [reaction_id: string]: string[] } | undefined;
getCommentReactionById: (reactionId: string) => TIssueCommentReaction | undefined;
commentReactionsByUser: (commentId: string, userId: string) => TIssueCommentReaction[];
}
export class IssueCommentReactionStore implements IIssueCommentReactionStore {
@ -52,6 +61,7 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
commentReactionMap: observable,
// actions
fetchCommentReactions: action,
applyCommentReactions: action,
createCommentReaction: action,
removeCommentReaction: action,
});
@ -72,25 +82,67 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
return this.commentReactionMap[reactionId] ?? undefined;
};
commentReactionsByUser = (commentId: string, userId: string) => {
if (!commentId || !userId) return [];
const reactions = this.getCommentReactionsByCommentId(commentId);
if (!reactions) return [];
const _userReactions: TIssueCommentReaction[] = [];
Object.keys(reactions).forEach((reaction) => {
if (reactions?.[reaction])
reactions?.[reaction].map((reactionId) => {
const currentReaction = this.getCommentReactionById(reactionId);
if (currentReaction && currentReaction.actor === userId) _userReactions.push(currentReaction);
});
});
return _userReactions;
};
// actions
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) => {
try {
const reactions = await this.issueReactionService.listIssueCommentReactions(workspaceSlug, projectId, commentId);
const response = await this.issueReactionService.listIssueCommentReactions(workspaceSlug, projectId, commentId);
const reactionIds = reactions.map((reaction) => reaction.id);
runInAction(() => {
set(this.commentReactions, commentId, reactionIds);
reactions.forEach((reaction) => {
set(this.commentReactionMap, reaction.id, reaction);
});
const groupedReactions = groupReactions(response || [], "reaction");
const commentReactionIdsMap: { [reaction: string]: string[] } = {};
Object.keys(groupedReactions).map((reactionId) => {
const reactionIds = (groupedReactions[reactionId] || []).map((reaction) => reaction.id);
commentReactionIdsMap[reactionId] = reactionIds;
});
return reactions;
runInAction(() => {
set(this.commentReactions, commentId, commentReactionIdsMap);
response.forEach((reaction) => set(this.commentReactionMap, reaction.id, reaction));
});
return response;
} catch (error) {
throw error;
}
};
applyCommentReactions = (commentId: string, commentReactions: TIssueCommentReaction[]) => {
const groupedReactions = groupReactions(commentReactions || [], "reaction");
const commentReactionIdsMap: { [reaction: string]: string[] } = {};
Object.keys(groupedReactions).map((reactionId) => {
const reactionIds = (groupedReactions[reactionId] || []).map((reaction) => reaction.id);
commentReactionIdsMap[reactionId] = reactionIds;
});
runInAction(() => {
set(this.commentReactions, commentId, commentReactionIdsMap);
commentReactions.forEach((reaction) => set(this.commentReactionMap, reaction.id, reaction));
});
return;
};
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) => {
try {
const response = await this.issueReactionService.createIssueCommentReaction(workspaceSlug, projectId, commentId, {
@ -98,7 +150,10 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
});
runInAction(() => {
this.commentReactions[commentId].push(response.id);
update(this.commentReactions, [commentId, reaction], (reactionId) => {
if (!reactionId) return [response.id];
return concat(reactionId, response.id);
});
set(this.commentReactionMap, response.id, response);
});
@ -108,14 +163,23 @@ export class IssueCommentReactionStore implements IIssueCommentReactionStore {
}
};
removeCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) => {
removeCommentReaction = async (
workspaceSlug: string,
projectId: string,
commentId: string,
reaction: string,
userId: string
) => {
try {
const reactionIndex = this.commentReactions[commentId].findIndex((_reaction) => _reaction === reaction);
if (reactionIndex >= 0)
const userReactions = this.commentReactionsByUser(commentId, userId);
const currentReaction = find(userReactions, { actor: userId, reaction: reaction });
if (currentReaction && currentReaction.id) {
runInAction(() => {
this.commentReactions[commentId].splice(reactionIndex, 1);
pull(this.commentReactions[commentId][reaction], currentReaction.id);
delete this.commentReactionMap[reaction];
});
}
const response = await this.issueReactionService.deleteIssueCommentReaction(
workspaceSlug,

View file

@ -77,6 +77,9 @@ export class IssueStore implements IIssueStore {
// fetch issue activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
// fetch issue comments
this.rootIssueDetailStore.comment.fetchComments(workspaceSlug, projectId, issueId);
// fetch issue subscription
this.rootIssueDetailStore.subscription.fetchSubscriptions(workspaceSlug, projectId, issueId);
@ -92,36 +95,63 @@ export class IssueStore implements IIssueStore {
}
};
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) =>
this.rootIssueDetailStore.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
const issue = await this.rootIssueDetailStore.rootIssueStore.projectIssues.updateIssue(
workspaceSlug,
projectId,
issueId,
data
);
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return issue;
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) =>
this.rootIssueDetailStore.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
addIssueToCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) =>
this.rootIssueDetailStore.rootIssueStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
addIssueToCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
const cycle = await this.rootIssueDetailStore.rootIssueStore.cycleIssues.addIssueToCycle(
workspaceSlug,
projectId,
cycleId,
issueIds
);
if (issueIds && issueIds.length > 0)
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueIds[0]);
return cycle;
};
removeIssueFromCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) =>
this.rootIssueDetailStore.rootIssueStore.cycleIssues.removeIssueFromCycle(
removeIssueFromCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
const cycle = await this.rootIssueDetailStore.rootIssueStore.cycleIssues.removeIssueFromCycle(
workspaceSlug,
projectId,
cycleId,
issueId
);
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return cycle;
};
addIssueToModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueIds: string[]) =>
this.rootIssueDetailStore.rootIssueStore.moduleIssues.addIssueToModule(
addIssueToModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueIds: string[]) => {
const _module = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.addIssueToModule(
workspaceSlug,
projectId,
moduleId,
issueIds
);
if (issueIds && issueIds.length > 0)
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueIds[0]);
return _module;
};
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) =>
this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeIssueFromModule(
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
const _module = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeIssueFromModule(
workspaceSlug,
projectId,
moduleId,
issueId
);
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return _module;
};
}

View file

@ -101,6 +101,8 @@ export class IssueLinkStore implements IIssueLinkStore {
set(this.linkMap, response.id, response);
});
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;
@ -123,6 +125,8 @@ export class IssueLinkStore implements IIssueLinkStore {
const response = await this.issueService.updateIssueLink(workspaceSlug, projectId, issueId, linkId, data);
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
// TODO: fetch issue detail
@ -141,6 +145,8 @@ export class IssueLinkStore implements IIssueLinkStore {
delete this.linkMap[linkId];
});
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;

View file

@ -79,10 +79,11 @@ export class IssueReactionStore implements IIssueReactionStore {
const _userReactions: TIssueReaction[] = [];
Object.keys(reactions).forEach((reaction) => {
reactions[reaction].map((reactionId) => {
const currentReaction = this.getReactionById(reactionId);
if (currentReaction && currentReaction.actor === userId) _userReactions.push(currentReaction);
});
if (reactions?.[reaction])
reactions?.[reaction].map((reactionId) => {
const currentReaction = this.getReactionById(reactionId);
if (currentReaction && currentReaction.actor === userId) _userReactions.push(currentReaction);
});
});
return _userReactions;
@ -126,6 +127,8 @@ export class IssueReactionStore implements IIssueReactionStore {
set(this.reactionMap, response.id, response);
});
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;
@ -152,6 +155,8 @@ export class IssueReactionStore implements IIssueReactionStore {
const response = await this.issueReactionService.deleteIssueReaction(workspaceSlug, projectId, issueId, reaction);
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;

View file

@ -124,6 +124,8 @@ export class IssueRelationStore implements IIssueRelationStore {
});
});
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;
@ -149,6 +151,8 @@ export class IssueRelationStore implements IIssueRelationStore {
related_issue,
});
// fetching activity
this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchRelations(workspaceSlug, projectId, issueId);

View file

@ -3,20 +3,20 @@ import { action, computed, makeObservable, observable } from "mobx";
import { IIssueRootStore } from "../root.store";
import { IIssueStore, IssueStore, IIssueStoreActions } from "./issue.store";
import { IIssueReactionStore, IssueReactionStore, IIssueReactionStoreActions } from "./reaction.store";
import { IIssueActivityStore, IssueActivityStore, IIssueActivityStoreActions } from "./activity.store";
import { IIssueCommentStore, IssueCommentStore, IIssueCommentStoreActions } from "./comment.store";
import {
IIssueCommentReactionStore,
IssueCommentReactionStore,
IIssueCommentReactionStoreActions,
} from "./comment_reaction.store";
import { IIssueLinkStore, IssueLinkStore, IIssueLinkStoreActions } from "./link.store";
import { IIssueSubscriptionStore, IssueSubscriptionStore, IIssueSubscriptionStoreActions } from "./subscription.store";
import { IIssueAttachmentStore, IssueAttachmentStore, IIssueAttachmentStoreActions } from "./attachment.store";
import { IIssueSubIssuesStore, IssueSubIssuesStore, IIssueSubIssuesStoreActions } from "./sub_issues.store";
import { IIssueRelationStore, IssueRelationStore, IIssueRelationStoreActions } from "./relation.store";
import { IIssueActivityStore, IssueActivityStore, IIssueActivityStoreActions, TActivityLoader } from "./activity.store";
import { IIssueCommentStore, IssueCommentStore, IIssueCommentStoreActions, TCommentLoader } from "./comment.store";
import {
IIssueCommentReactionStore,
IssueCommentReactionStore,
IIssueCommentReactionStoreActions,
} from "./comment_reaction.store";
import { TIssue, IIssueActivity, TIssueLink, TIssueRelationTypes } from "@plane/types";
import { TIssue, TIssueComment, TIssueCommentReaction, TIssueLink, TIssueRelationTypes } from "@plane/types";
export type TPeekIssue = {
workspaceSlug: string;
@ -27,14 +27,14 @@ export type TPeekIssue = {
export interface IIssueDetail
extends IIssueStoreActions,
IIssueReactionStoreActions,
IIssueActivityStoreActions,
IIssueCommentStoreActions,
IIssueCommentReactionStoreActions,
IIssueLinkStoreActions,
IIssueSubIssuesStoreActions,
IIssueSubscriptionStoreActions,
IIssueAttachmentStoreActions,
IIssueRelationStoreActions {
IIssueRelationStoreActions,
IIssueActivityStoreActions,
IIssueCommentStoreActions,
IIssueCommentReactionStoreActions {
// observables
peekIssue: TPeekIssue | undefined;
isIssueLinkModalOpen: boolean;
@ -72,13 +72,13 @@ export class IssueDetail implements IIssueDetail {
issue: IIssueStore;
reaction: IIssueReactionStore;
attachment: IIssueAttachmentStore;
activity: IIssueActivityStore;
comment: IIssueCommentStore;
commentReaction: IIssueCommentReactionStore;
subIssues: IIssueSubIssuesStore;
link: IIssueLinkStore;
subscription: IIssueSubscriptionStore;
relation: IIssueRelationStore;
activity: IIssueActivityStore;
comment: IIssueCommentStore;
commentReaction: IIssueCommentReactionStore;
constructor(rootStore: IIssueRootStore) {
makeObservable(this, {
@ -150,31 +150,6 @@ export class IssueDetail implements IIssueDetail {
userId: string
) => this.reaction.removeReaction(workspaceSlug, projectId, issueId, reaction, userId);
// activity
fetchActivities = async (workspaceSlug: string, projectId: string, issueId: string) =>
this.activity.fetchActivities(workspaceSlug, projectId, issueId);
// comment
createComment = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssueActivity>) =>
this.comment.createComment(workspaceSlug, projectId, issueId, data);
updateComment = async (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<IIssueActivity>
) => this.comment.updateComment(workspaceSlug, projectId, issueId, commentId, data);
removeComment = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) =>
this.comment.removeComment(workspaceSlug, projectId, issueId, commentId);
// comment reaction
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) =>
this.commentReaction.fetchCommentReactions(workspaceSlug, projectId, commentId);
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
this.commentReaction.createCommentReaction(workspaceSlug, projectId, commentId, reaction);
removeCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
this.commentReaction.removeCommentReaction(workspaceSlug, projectId, commentId, reaction);
// attachments
fetchAttachments = async (workspaceSlug: string, projectId: string, issueId: string) =>
this.attachment.fetchAttachments(workspaceSlug, projectId, issueId);
@ -240,4 +215,38 @@ export class IssueDetail implements IIssueDetail {
relationType: TIssueRelationTypes,
relatedIssue: string
) => this.relation.removeRelation(workspaceSlug, projectId, issueId, relationType, relatedIssue);
// activity
fetchActivities = async (workspaceSlug: string, projectId: string, issueId: string, loaderType?: TActivityLoader) =>
this.activity.fetchActivities(workspaceSlug, projectId, issueId, loaderType);
// comment
fetchComments = async (workspaceSlug: string, projectId: string, issueId: string, loaderType?: TCommentLoader) =>
this.comment.fetchComments(workspaceSlug, projectId, issueId, loaderType);
createComment = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssueComment>) =>
this.comment.createComment(workspaceSlug, projectId, issueId, data);
updateComment = async (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueComment>
) => this.comment.updateComment(workspaceSlug, projectId, issueId, commentId, data);
removeComment = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) =>
this.comment.removeComment(workspaceSlug, projectId, issueId, commentId);
// comment reaction
fetchCommentReactions = async (workspaceSlug: string, projectId: string, commentId: string) =>
this.commentReaction.fetchCommentReactions(workspaceSlug, projectId, commentId);
applyCommentReactions = async (commentId: string, commentReactions: TIssueCommentReaction[]) =>
this.commentReaction.applyCommentReactions(commentId, commentReactions);
createCommentReaction = async (workspaceSlug: string, projectId: string, commentId: string, reaction: string) =>
this.commentReaction.createCommentReaction(workspaceSlug, projectId, commentId, reaction);
removeCommentReaction = async (
workspaceSlug: string,
projectId: string,
commentId: string,
reaction: string,
userId: string
) => this.commentReaction.removeCommentReaction(workspaceSlug, projectId, commentId, reaction, userId);
}

View file

@ -264,6 +264,10 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
issues: issueIds,
});
issueIds.map((issueId) => {
this.rootIssueStore.issues.updateIssue(issueId, { module_id: moduleId });
});
return issueToModule;
} catch (error) {
throw error;