feat: init
This commit is contained in:
9
apps/web/ce/store/analytics.store.ts
Normal file
9
apps/web/ce/store/analytics.store.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { IBaseAnalyticsStore } from "@/store/analytics.store";
|
||||
import { BaseAnalyticsStore } from "@/store/analytics.store";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface IAnalyticsStore extends IBaseAnalyticsStore {
|
||||
//observables
|
||||
}
|
||||
|
||||
export class AnalyticsStore extends BaseAnalyticsStore {}
|
||||
27
apps/web/ce/store/command-palette.store.ts
Normal file
27
apps/web/ce/store/command-palette.store.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { computed, makeObservable } from "mobx";
|
||||
// types / constants
|
||||
import type { IBaseCommandPaletteStore } from "@/store/base-command-palette.store";
|
||||
import { BaseCommandPaletteStore } from "@/store/base-command-palette.store";
|
||||
|
||||
export interface ICommandPaletteStore extends IBaseCommandPaletteStore {
|
||||
// computed
|
||||
isAnyModalOpen: boolean;
|
||||
}
|
||||
|
||||
export class CommandPaletteStore extends BaseCommandPaletteStore implements ICommandPaletteStore {
|
||||
constructor() {
|
||||
super();
|
||||
makeObservable(this, {
|
||||
// computed
|
||||
isAnyModalOpen: computed,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any modal is open or not in the base command palette.
|
||||
* @returns boolean
|
||||
*/
|
||||
get isAnyModalOpen(): boolean {
|
||||
return Boolean(super.getCoreModalsState());
|
||||
}
|
||||
}
|
||||
1
apps/web/ce/store/cycle/index.ts
Normal file
1
apps/web/ce/store/cycle/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type { ICycleStore } from "@/store/cycle.store";
|
||||
155
apps/web/ce/store/estimates/estimate.ts
Normal file
155
apps/web/ce/store/estimates/estimate.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import { orderBy, set } from "lodash-es";
|
||||
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||
import { computedFn } from "mobx-utils";
|
||||
// types
|
||||
import type {
|
||||
IEstimate as IEstimateType,
|
||||
IEstimatePoint as IEstimatePointType,
|
||||
TEstimateSystemKeys,
|
||||
} from "@plane/types";
|
||||
// plane web services
|
||||
import estimateService from "@/plane-web/services/project/estimate.service";
|
||||
// store
|
||||
import type { IEstimatePoint } from "@/store/estimates/estimate-point";
|
||||
import { EstimatePoint } from "@/store/estimates/estimate-point";
|
||||
import type { CoreRootStore } from "@/store/root.store";
|
||||
|
||||
type TErrorCodes = {
|
||||
status: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export interface IEstimate extends Omit<IEstimateType, "points"> {
|
||||
// observables
|
||||
error: TErrorCodes | undefined;
|
||||
estimatePoints: Record<string, IEstimatePoint>;
|
||||
// computed
|
||||
asJson: Omit<IEstimateType, "points">;
|
||||
estimatePointIds: string[] | undefined;
|
||||
estimatePointById: (estimatePointId: string) => IEstimatePointType | undefined;
|
||||
// actions
|
||||
creteEstimatePoint: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
payload: Partial<IEstimatePointType>
|
||||
) => Promise<IEstimatePointType | undefined>;
|
||||
}
|
||||
|
||||
export class Estimate implements IEstimate {
|
||||
// data model observables
|
||||
id: string | undefined = undefined;
|
||||
name: string | undefined = undefined;
|
||||
description: string | undefined = undefined;
|
||||
type: TEstimateSystemKeys | undefined = undefined;
|
||||
workspace: string | undefined = undefined;
|
||||
project: string | undefined = undefined;
|
||||
last_used: boolean | undefined = undefined;
|
||||
created_at: Date | undefined = undefined;
|
||||
updated_at: Date | undefined = undefined;
|
||||
created_by: string | undefined = undefined;
|
||||
updated_by: string | undefined = undefined;
|
||||
// observables
|
||||
error: TErrorCodes | undefined = undefined;
|
||||
estimatePoints: Record<string, IEstimatePoint> = {};
|
||||
|
||||
constructor(
|
||||
public store: CoreRootStore,
|
||||
public data: IEstimateType
|
||||
) {
|
||||
makeObservable(this, {
|
||||
// data model observables
|
||||
id: observable.ref,
|
||||
name: observable.ref,
|
||||
description: observable.ref,
|
||||
type: observable.ref,
|
||||
workspace: observable.ref,
|
||||
project: observable.ref,
|
||||
last_used: observable.ref,
|
||||
created_at: observable.ref,
|
||||
updated_at: observable.ref,
|
||||
created_by: observable.ref,
|
||||
updated_by: observable.ref,
|
||||
// observables
|
||||
error: observable.ref,
|
||||
estimatePoints: observable,
|
||||
// computed
|
||||
asJson: computed,
|
||||
estimatePointIds: computed,
|
||||
// actions
|
||||
creteEstimatePoint: action,
|
||||
});
|
||||
this.id = this.data.id;
|
||||
this.name = this.data.name;
|
||||
this.description = this.data.description;
|
||||
this.type = this.data.type;
|
||||
this.workspace = this.data.workspace;
|
||||
this.project = this.data.project;
|
||||
this.last_used = this.data.last_used;
|
||||
this.created_at = this.data.created_at;
|
||||
this.updated_at = this.data.updated_at;
|
||||
this.created_by = this.data.created_by;
|
||||
this.updated_by = this.data.updated_by;
|
||||
this.data.points?.forEach((estimationPoint) => {
|
||||
if (estimationPoint.id)
|
||||
set(this.estimatePoints, [estimationPoint.id], new EstimatePoint(this.store, this.data, estimationPoint));
|
||||
});
|
||||
}
|
||||
|
||||
// computed
|
||||
get asJson() {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
type: this.type,
|
||||
workspace: this.workspace,
|
||||
project: this.project,
|
||||
last_used: this.last_used,
|
||||
created_at: this.created_at,
|
||||
updated_at: this.updated_at,
|
||||
created_by: this.created_by,
|
||||
updated_by: this.updated_by,
|
||||
};
|
||||
}
|
||||
|
||||
get estimatePointIds() {
|
||||
const { estimatePoints } = this;
|
||||
if (!estimatePoints) return undefined;
|
||||
let currentEstimatePoints = Object.values(estimatePoints).filter(
|
||||
(estimatePoint) => estimatePoint?.estimate === this.id
|
||||
);
|
||||
currentEstimatePoints = orderBy(currentEstimatePoints, ["key"], "asc");
|
||||
const estimatePointIds = currentEstimatePoints.map((estimatePoint) => estimatePoint.id) as string[];
|
||||
return estimatePointIds ?? undefined;
|
||||
}
|
||||
|
||||
estimatePointById = computedFn((estimatePointId: string) => {
|
||||
if (!estimatePointId) return undefined;
|
||||
return this.estimatePoints[estimatePointId] ?? undefined;
|
||||
});
|
||||
|
||||
// actions
|
||||
/**
|
||||
* @description create an estimate point
|
||||
* @param { string } workspaceSlug
|
||||
* @param { string } projectId
|
||||
* @param { Partial<IEstimatePointType> } payload
|
||||
* @returns { IEstimatePointType | undefined }
|
||||
*/
|
||||
creteEstimatePoint = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
payload: Partial<IEstimatePointType>
|
||||
): Promise<IEstimatePointType | undefined> => {
|
||||
if (!this.id || !payload) return;
|
||||
|
||||
const estimatePoint = await estimateService.createEstimatePoint(workspaceSlug, projectId, this.id, payload);
|
||||
if (estimatePoint) {
|
||||
runInAction(() => {
|
||||
if (estimatePoint.id) {
|
||||
set(this.estimatePoints, [estimatePoint.id], new EstimatePoint(this.store, this.data, estimatePoint));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
1
apps/web/ce/store/global-view.store.ts
Normal file
1
apps/web/ce/store/global-view.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@/store/global-view.store";
|
||||
16
apps/web/ce/store/issue/epic/filter.store.ts
Normal file
16
apps/web/ce/store/issue/epic/filter.store.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { IProjectIssuesFilter } from "@/store/issue/project";
|
||||
import { ProjectIssuesFilter } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type IProjectEpicsFilter = IProjectIssuesFilter;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class ProjectEpicsFilter extends ProjectIssuesFilter implements IProjectEpicsFilter {
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
// root store
|
||||
this.rootIssueStore = _rootStore;
|
||||
}
|
||||
}
|
||||
2
apps/web/ce/store/issue/epic/index.ts
Normal file
2
apps/web/ce/store/issue/epic/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
||||
15
apps/web/ce/store/issue/epic/issue.store.ts
Normal file
15
apps/web/ce/store/issue/epic/issue.store.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { IProjectIssues } from "@/store/issue/project";
|
||||
import { ProjectIssues } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
import type { IProjectEpicsFilter } from "./filter.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
|
||||
export type IProjectEpics = IProjectIssues;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class ProjectEpics extends ProjectIssues implements IProjectEpics {
|
||||
constructor(_rootStore: IIssueRootStore, issueFilterStore: IProjectEpicsFilter) {
|
||||
super(_rootStore, issueFilterStore);
|
||||
}
|
||||
}
|
||||
4
apps/web/ce/store/issue/helpers/base-issue-store.ts
Normal file
4
apps/web/ce/store/issue/helpers/base-issue-store.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { TIssue } from "@plane/types";
|
||||
import { getIssueIds } from "@/store/issue/helpers/base-issues-utils";
|
||||
|
||||
export const workItemSortWithOrderByExtended = (array: TIssue[], key?: string) => getIssueIds(array);
|
||||
4
apps/web/ce/store/issue/helpers/base-issue.store.ts
Normal file
4
apps/web/ce/store/issue/helpers/base-issue.store.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { TIssue } from "@plane/types";
|
||||
import { getIssueIds } from "@/store/issue/helpers/base-issues-utils";
|
||||
|
||||
export const workItemSortWithOrderByExtended = (array: TIssue[], key?: string) => getIssueIds(array);
|
||||
173
apps/web/ce/store/issue/issue-details/activity.store.ts
Normal file
173
apps/web/ce/store/issue/issue-details/activity.store.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { concat, orderBy, set, uniq, update } from "lodash-es";
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
import { computedFn } from "mobx-utils";
|
||||
// plane package imports
|
||||
import type { E_SORT_ORDER } from "@plane/constants";
|
||||
import { EActivityFilterType } from "@plane/constants";
|
||||
import type {
|
||||
TIssueActivityComment,
|
||||
TIssueActivity,
|
||||
TIssueActivityMap,
|
||||
TIssueActivityIdMap,
|
||||
TIssueServiceType,
|
||||
} from "@plane/types";
|
||||
import { EIssueServiceType } from "@plane/types";
|
||||
// plane web constants
|
||||
// services
|
||||
import { IssueActivityService } from "@/services/issue";
|
||||
// store
|
||||
import type { CoreRootStore } from "@/store/root.store";
|
||||
|
||||
export type TActivityLoader = "fetch" | "mutate" | undefined;
|
||||
|
||||
export interface IIssueActivityStoreActions {
|
||||
// actions
|
||||
fetchActivities: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
loaderType?: TActivityLoader
|
||||
) => Promise<TIssueActivity[]>;
|
||||
}
|
||||
|
||||
export interface IIssueActivityStore extends IIssueActivityStoreActions {
|
||||
// observables
|
||||
loader: TActivityLoader;
|
||||
activities: TIssueActivityIdMap;
|
||||
activityMap: TIssueActivityMap;
|
||||
// helper methods
|
||||
getActivitiesByIssueId: (issueId: string) => string[] | undefined;
|
||||
getActivityById: (activityId: string) => TIssueActivity | undefined;
|
||||
getActivityAndCommentsByIssueId: (issueId: string, sortOrder: E_SORT_ORDER) => TIssueActivityComment[] | undefined;
|
||||
}
|
||||
|
||||
export class IssueActivityStore implements IIssueActivityStore {
|
||||
// observables
|
||||
loader: TActivityLoader = "fetch";
|
||||
activities: TIssueActivityIdMap = {};
|
||||
activityMap: TIssueActivityMap = {};
|
||||
// services
|
||||
serviceType;
|
||||
issueActivityService;
|
||||
|
||||
constructor(
|
||||
protected store: CoreRootStore,
|
||||
serviceType: TIssueServiceType = EIssueServiceType.ISSUES
|
||||
) {
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
loader: observable.ref,
|
||||
activities: observable,
|
||||
activityMap: observable,
|
||||
// actions
|
||||
fetchActivities: action,
|
||||
});
|
||||
this.serviceType = serviceType;
|
||||
// services
|
||||
this.issueActivityService = new IssueActivityService(this.serviceType);
|
||||
}
|
||||
|
||||
// helper methods
|
||||
getActivitiesByIssueId = (issueId: string) => {
|
||||
if (!issueId) return undefined;
|
||||
return this.activities[issueId] ?? undefined;
|
||||
};
|
||||
|
||||
getActivityById = (activityId: string) => {
|
||||
if (!activityId) return undefined;
|
||||
return this.activityMap[activityId] ?? undefined;
|
||||
};
|
||||
|
||||
protected buildActivityAndCommentItems(issueId: string): TIssueActivityComment[] | undefined {
|
||||
if (!issueId) return undefined;
|
||||
|
||||
const activityComments: TIssueActivityComment[] = [];
|
||||
|
||||
const currentStore =
|
||||
this.serviceType === EIssueServiceType.EPICS ? this.store.issue.epicDetail : this.store.issue.issueDetail;
|
||||
|
||||
const activities = this.getActivitiesByIssueId(issueId);
|
||||
const comments = currentStore.comment.getCommentsByIssueId(issueId);
|
||||
|
||||
if (!activities || !comments) return undefined;
|
||||
|
||||
activities.forEach((activityId) => {
|
||||
const activity = this.getActivityById(activityId);
|
||||
if (!activity) return;
|
||||
const type =
|
||||
activity.field === "state"
|
||||
? EActivityFilterType.STATE
|
||||
: activity.field === "assignees"
|
||||
? EActivityFilterType.ASSIGNEE
|
||||
: activity.field === null
|
||||
? EActivityFilterType.DEFAULT
|
||||
: EActivityFilterType.ACTIVITY;
|
||||
activityComments.push({
|
||||
id: activity.id,
|
||||
activity_type: type,
|
||||
created_at: activity.created_at,
|
||||
});
|
||||
});
|
||||
|
||||
comments.forEach((commentId) => {
|
||||
const comment = currentStore.comment.getCommentById(commentId);
|
||||
if (!comment) return;
|
||||
activityComments.push({
|
||||
id: comment.id,
|
||||
activity_type: EActivityFilterType.COMMENT,
|
||||
created_at: comment.created_at,
|
||||
});
|
||||
});
|
||||
|
||||
return activityComments;
|
||||
}
|
||||
|
||||
protected sortActivityComments(items: TIssueActivityComment[], sortOrder: E_SORT_ORDER): TIssueActivityComment[] {
|
||||
return orderBy(items, (e) => new Date(e.created_at || 0), sortOrder);
|
||||
}
|
||||
|
||||
getActivityAndCommentsByIssueId = computedFn((issueId: string, sortOrder: E_SORT_ORDER) => {
|
||||
const baseItems = this.buildActivityAndCommentItems(issueId);
|
||||
if (!baseItems) return undefined;
|
||||
return this.sortActivityComments(baseItems, sortOrder);
|
||||
});
|
||||
|
||||
// actions
|
||||
public async fetchActivities(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
loaderType: TActivityLoader = "fetch"
|
||||
) {
|
||||
try {
|
||||
this.loader = loaderType;
|
||||
|
||||
let props = {};
|
||||
const currentActivityIds = this.getActivitiesByIssueId(issueId);
|
||||
if (currentActivityIds && currentActivityIds.length > 0) {
|
||||
const currentActivity = this.getActivityById(currentActivityIds[currentActivityIds.length - 1]);
|
||||
if (currentActivity) props = { created_at__gt: currentActivity.created_at };
|
||||
}
|
||||
|
||||
const activities = await this.issueActivityService.getIssueActivities(workspaceSlug, projectId, issueId, props);
|
||||
|
||||
const activityIds = activities.map((activity) => activity.id);
|
||||
|
||||
runInAction(() => {
|
||||
update(this.activities, issueId, (currentActivityIds) => {
|
||||
if (!currentActivityIds) return activityIds;
|
||||
return uniq(concat(currentActivityIds, activityIds));
|
||||
});
|
||||
activities.forEach((activity) => {
|
||||
set(this.activityMap, activity.id, activity);
|
||||
});
|
||||
this.loader = undefined;
|
||||
});
|
||||
|
||||
return activities;
|
||||
} catch (error) {
|
||||
this.loader = undefined;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
apps/web/ce/store/issue/issue-details/root.store.ts
Normal file
16
apps/web/ce/store/issue/issue-details/root.store.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { makeObservable } from "mobx";
|
||||
import type { TIssueServiceType } from "@plane/types";
|
||||
import type { IIssueDetail as IIssueDetailCore } from "@/store/issue/issue-details/root.store";
|
||||
import { IssueDetail as IssueDetailCore } from "@/store/issue/issue-details/root.store";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
|
||||
export type IIssueDetail = IIssueDetailCore;
|
||||
|
||||
export class IssueDetail extends IssueDetailCore {
|
||||
constructor(rootStore: IIssueRootStore, serviceType: TIssueServiceType) {
|
||||
super(rootStore, serviceType);
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
});
|
||||
}
|
||||
}
|
||||
13
apps/web/ce/store/issue/team-project/filter.store.ts
Normal file
13
apps/web/ce/store/issue/team-project/filter.store.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { IProjectIssuesFilter } from "@/store/issue/project";
|
||||
import { ProjectIssuesFilter } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamProjectWorkItemsFilter = IProjectIssuesFilter;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamProjectWorkItemsFilter extends ProjectIssuesFilter implements ITeamProjectWorkItemsFilter {
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
}
|
||||
}
|
||||
2
apps/web/ce/store/issue/team-project/index.ts
Normal file
2
apps/web/ce/store/issue/team-project/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
||||
14
apps/web/ce/store/issue/team-project/issue.store.ts
Normal file
14
apps/web/ce/store/issue/team-project/issue.store.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { IProjectIssues } from "@/store/issue/project";
|
||||
import { ProjectIssues } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
import type { ITeamProjectWorkItemsFilter } from "./filter.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamProjectWorkItems = IProjectIssues;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamProjectWorkItems extends ProjectIssues implements ITeamProjectWorkItems {
|
||||
constructor(_rootStore: IIssueRootStore, teamProjectWorkItemsFilterStore: ITeamProjectWorkItemsFilter) {
|
||||
super(_rootStore, teamProjectWorkItemsFilterStore);
|
||||
}
|
||||
}
|
||||
13
apps/web/ce/store/issue/team-views/filter.store.ts
Normal file
13
apps/web/ce/store/issue/team-views/filter.store.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { IProjectViewIssuesFilter } from "@/store/issue/project-views";
|
||||
import { ProjectViewIssuesFilter } from "@/store/issue/project-views";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamViewIssuesFilter = IProjectViewIssuesFilter;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamViewIssuesFilter extends ProjectViewIssuesFilter implements IProjectViewIssuesFilter {
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
}
|
||||
}
|
||||
2
apps/web/ce/store/issue/team-views/index.ts
Normal file
2
apps/web/ce/store/issue/team-views/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
||||
14
apps/web/ce/store/issue/team-views/issue.store.ts
Normal file
14
apps/web/ce/store/issue/team-views/issue.store.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { IProjectViewIssues } from "@/store/issue/project-views";
|
||||
import { ProjectViewIssues } from "@/store/issue/project-views";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
import type { ITeamViewIssuesFilter } from "./filter.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamViewIssues = IProjectViewIssues;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamViewIssues extends ProjectViewIssues implements IProjectViewIssues {
|
||||
constructor(_rootStore: IIssueRootStore, teamViewFilterStore: ITeamViewIssuesFilter) {
|
||||
super(_rootStore, teamViewFilterStore);
|
||||
}
|
||||
}
|
||||
13
apps/web/ce/store/issue/team/filter.store.ts
Normal file
13
apps/web/ce/store/issue/team/filter.store.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { IProjectIssuesFilter } from "@/store/issue/project";
|
||||
import { ProjectIssuesFilter } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamIssuesFilter = IProjectIssuesFilter;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamIssuesFilter extends ProjectIssuesFilter implements IProjectIssuesFilter {
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
}
|
||||
}
|
||||
2
apps/web/ce/store/issue/team/index.ts
Normal file
2
apps/web/ce/store/issue/team/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
||||
14
apps/web/ce/store/issue/team/issue.store.ts
Normal file
14
apps/web/ce/store/issue/team/issue.store.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { IProjectIssues } from "@/store/issue/project";
|
||||
import { ProjectIssues } from "@/store/issue/project";
|
||||
import type { IIssueRootStore } from "@/store/issue/root.store";
|
||||
import type { ITeamIssuesFilter } from "./filter.store";
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export type ITeamIssues = IProjectIssues;
|
||||
|
||||
// @ts-nocheck - This class will never be used, extending similar class to avoid type errors
|
||||
export class TeamIssues extends ProjectIssues implements IProjectIssues {
|
||||
constructor(_rootStore: IIssueRootStore, teamIssueFilterStore: ITeamIssuesFilter) {
|
||||
super(_rootStore, teamIssueFilterStore);
|
||||
}
|
||||
}
|
||||
1
apps/web/ce/store/issue/workspace/issue.store.ts
Normal file
1
apps/web/ce/store/issue/workspace/issue.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@/store/issue/workspace/issue.store";
|
||||
44
apps/web/ce/store/member/project-member.store.ts
Normal file
44
apps/web/ce/store/member/project-member.store.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { computedFn } from "mobx-utils";
|
||||
import type { EUserProjectRoles } from "@plane/types";
|
||||
// plane imports
|
||||
// plane web imports
|
||||
import type { RootStore } from "@/plane-web/store/root.store";
|
||||
// store
|
||||
import type { IMemberRootStore } from "@/store/member";
|
||||
import type { IBaseProjectMemberStore } from "@/store/member/project/base-project-member.store";
|
||||
import { BaseProjectMemberStore } from "@/store/member/project/base-project-member.store";
|
||||
|
||||
export type IProjectMemberStore = IBaseProjectMemberStore;
|
||||
|
||||
export class ProjectMemberStore extends BaseProjectMemberStore implements IProjectMemberStore {
|
||||
constructor(_memberRoot: IMemberRootStore, rootStore: RootStore) {
|
||||
super(_memberRoot, rootStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the highest role from the project membership
|
||||
* @param { string } userId
|
||||
* @param { string } projectId
|
||||
* @returns { EUserProjectRoles | undefined }
|
||||
*/
|
||||
getUserProjectRole = computedFn((userId: string, projectId: string): EUserProjectRoles | undefined =>
|
||||
this.getRoleFromProjectMembership(userId, projectId)
|
||||
);
|
||||
|
||||
/**
|
||||
* @description Returns the role from the project membership
|
||||
* @param projectId
|
||||
* @param userId
|
||||
* @param role
|
||||
*/
|
||||
getProjectMemberRoleForUpdate = (_projectId: string, _userId: string, role: EUserProjectRoles): EUserProjectRoles =>
|
||||
role;
|
||||
|
||||
/**
|
||||
* @description Processes the removal of a member from a project
|
||||
* This method handles the cleanup of member data from the project member map
|
||||
* @param projectId - The ID of the project to remove the member from
|
||||
* @param userId - The ID of the user to remove from the project
|
||||
*/
|
||||
processMemberRemoval = (projectId: string, userId: string) => this.handleMemberRemoval(projectId, userId);
|
||||
}
|
||||
16
apps/web/ce/store/pages/extended-base-page.ts
Normal file
16
apps/web/ce/store/pages/extended-base-page.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { TPage, TPageExtended } from "@plane/types";
|
||||
import type { RootStore } from "@/plane-web/store/root.store";
|
||||
import type { TBasePageServices } from "@/store/pages/base-page";
|
||||
|
||||
export type TExtendedPageInstance = TPageExtended & {
|
||||
asJSONExtended: TPageExtended;
|
||||
};
|
||||
|
||||
export class ExtendedBasePage implements TExtendedPageInstance {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
constructor(store: RootStore, page: TPage, services: TBasePageServices) {}
|
||||
|
||||
get asJSONExtended(): TExtendedPageInstance["asJSONExtended"] {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
1
apps/web/ce/store/project-inbox.store.ts
Normal file
1
apps/web/ce/store/project-inbox.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@/store/inbox/project-inbox.store";
|
||||
1
apps/web/ce/store/project-view.store.ts
Normal file
1
apps/web/ce/store/project-view.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@/store/project-view.store";
|
||||
14
apps/web/ce/store/root.store.ts
Normal file
14
apps/web/ce/store/root.store.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// store
|
||||
import { CoreRootStore } from "@/store/root.store";
|
||||
import type { ITimelineStore } from "./timeline";
|
||||
import { TimeLineStore } from "./timeline";
|
||||
|
||||
export class RootStore extends CoreRootStore {
|
||||
timelineStore: ITimelineStore;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.timelineStore = new TimeLineStore(this);
|
||||
}
|
||||
}
|
||||
1
apps/web/ce/store/state.store.ts
Normal file
1
apps/web/ce/store/state.store.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@/store/state.store";
|
||||
340
apps/web/ce/store/timeline/base-timeline.store.ts
Normal file
340
apps/web/ce/store/timeline/base-timeline.store.ts
Normal file
@@ -0,0 +1,340 @@
|
||||
import { isEqual, set } from "lodash-es";
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
import { computedFn } from "mobx-utils";
|
||||
// components
|
||||
import type {
|
||||
ChartDataType,
|
||||
IBlockUpdateDependencyData,
|
||||
IGanttBlock,
|
||||
TGanttViews,
|
||||
EGanttBlockType,
|
||||
} from "@plane/types";
|
||||
import { renderFormattedPayloadDate } from "@plane/utils";
|
||||
import { currentViewDataWithView } from "@/components/gantt-chart/data";
|
||||
import {
|
||||
getDateFromPositionOnGantt,
|
||||
getItemPositionWidth,
|
||||
getPositionFromDate,
|
||||
} from "@/components/gantt-chart/views/helpers";
|
||||
// helpers
|
||||
// store
|
||||
import type { RootStore } from "@/plane-web/store/root.store";
|
||||
|
||||
// types
|
||||
type BlockData = {
|
||||
id: string;
|
||||
name: string;
|
||||
sort_order: number | null;
|
||||
start_date?: string | undefined | null;
|
||||
target_date?: string | undefined | null;
|
||||
project_id?: string | undefined | null;
|
||||
};
|
||||
|
||||
export interface IBaseTimelineStore {
|
||||
// observables
|
||||
currentView: TGanttViews;
|
||||
currentViewData: ChartDataType | undefined;
|
||||
activeBlockId: string | null;
|
||||
renderView: any;
|
||||
isDragging: boolean;
|
||||
isDependencyEnabled: boolean;
|
||||
//
|
||||
setBlockIds: (ids: string[]) => void;
|
||||
getBlockById: (blockId: string) => IGanttBlock;
|
||||
// computed functions
|
||||
getIsCurrentDependencyDragging: (blockId: string) => boolean;
|
||||
isBlockActive: (blockId: string) => boolean;
|
||||
// actions
|
||||
updateCurrentView: (view: TGanttViews) => void;
|
||||
updateCurrentViewData: (data: ChartDataType | undefined) => void;
|
||||
updateActiveBlockId: (blockId: string | null) => void;
|
||||
updateRenderView: (data: any) => void;
|
||||
updateAllBlocksOnChartChangeWhileDragging: (addedWidth: number) => void;
|
||||
getUpdatedPositionAfterDrag: (
|
||||
id: string,
|
||||
shouldUpdateHalfBlock: boolean,
|
||||
ignoreDependencies?: boolean
|
||||
) => IBlockUpdateDependencyData[];
|
||||
updateBlockPosition: (id: string, deltaLeft: number, deltaWidth: number, ignoreDependencies?: boolean) => void;
|
||||
getNumberOfDaysFromPosition: (position: number | undefined) => number | undefined;
|
||||
setIsDragging: (isDragging: boolean) => void;
|
||||
initGantt: () => void;
|
||||
|
||||
getDateFromPositionOnGantt: (position: number, offsetDays: number) => Date | undefined;
|
||||
getPositionFromDateOnGantt: (date: string | Date, offSetWidth: number) => number | undefined;
|
||||
}
|
||||
|
||||
export class BaseTimeLineStore implements IBaseTimelineStore {
|
||||
blocksMap: Record<string, IGanttBlock> = {};
|
||||
blockIds: string[] | undefined = undefined;
|
||||
|
||||
isDragging: boolean = false;
|
||||
currentView: TGanttViews = "week";
|
||||
currentViewData: ChartDataType | undefined = undefined;
|
||||
activeBlockId: string | null = null;
|
||||
renderView: any = [];
|
||||
|
||||
rootStore: RootStore;
|
||||
|
||||
isDependencyEnabled = false;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
blocksMap: observable,
|
||||
blockIds: observable,
|
||||
isDragging: observable.ref,
|
||||
currentView: observable.ref,
|
||||
currentViewData: observable,
|
||||
activeBlockId: observable.ref,
|
||||
renderView: observable,
|
||||
// actions
|
||||
setIsDragging: action,
|
||||
setBlockIds: action.bound,
|
||||
initGantt: action.bound,
|
||||
updateCurrentView: action.bound,
|
||||
updateCurrentViewData: action.bound,
|
||||
updateActiveBlockId: action.bound,
|
||||
updateRenderView: action.bound,
|
||||
});
|
||||
|
||||
this.initGantt();
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Block Ids to derive blocks from
|
||||
* @param ids
|
||||
*/
|
||||
setBlockIds = (ids: string[]) => {
|
||||
this.blockIds = ids;
|
||||
};
|
||||
|
||||
/**
|
||||
* setIsDragging
|
||||
* @param isDragging
|
||||
*/
|
||||
setIsDragging = (isDragging: boolean) => {
|
||||
runInAction(() => {
|
||||
this.isDragging = isDragging;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description check if block is active
|
||||
* @param {string} blockId
|
||||
*/
|
||||
isBlockActive = computedFn((blockId: string): boolean => this.activeBlockId === blockId);
|
||||
|
||||
/**
|
||||
* @description update current view
|
||||
* @param {TGanttViews} view
|
||||
*/
|
||||
updateCurrentView = (view: TGanttViews) => {
|
||||
this.currentView = view;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description update current view data
|
||||
* @param {ChartDataType | undefined} data
|
||||
*/
|
||||
updateCurrentViewData = (data: ChartDataType | undefined) => {
|
||||
runInAction(() => {
|
||||
this.currentViewData = data;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description update active block
|
||||
* @param {string | null} block
|
||||
*/
|
||||
updateActiveBlockId = (blockId: string | null) => {
|
||||
this.activeBlockId = blockId;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description update render view
|
||||
* @param {any[]} data
|
||||
*/
|
||||
updateRenderView = (data: any[]) => {
|
||||
this.renderView = data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description initialize gantt chart with month view
|
||||
*/
|
||||
initGantt = () => {
|
||||
const newCurrentViewData = currentViewDataWithView(this.currentView);
|
||||
|
||||
runInAction(() => {
|
||||
this.currentViewData = newCurrentViewData;
|
||||
this.blocksMap = {};
|
||||
this.blockIds = undefined;
|
||||
});
|
||||
};
|
||||
|
||||
/** Gets Block from Id */
|
||||
getBlockById = computedFn((blockId: string) => this.blocksMap[blockId]);
|
||||
|
||||
/**
|
||||
* updates the BlocksMap from blockIds
|
||||
* @param getDataById
|
||||
* @returns
|
||||
*/
|
||||
updateBlocks(getDataById: (id: string) => BlockData | undefined | null, type?: EGanttBlockType, index?: number) {
|
||||
if (!this.blockIds || !Array.isArray(this.blockIds) || this.isDragging) return true;
|
||||
|
||||
const updatedBlockMaps: { path: string[]; value: any }[] = [];
|
||||
const newBlocks: IGanttBlock[] = [];
|
||||
|
||||
// Loop through blockIds to generate blocks Data
|
||||
for (const blockId of this.blockIds) {
|
||||
const blockData = getDataById(blockId);
|
||||
if (!blockData) continue;
|
||||
|
||||
const block: IGanttBlock = {
|
||||
data: blockData,
|
||||
id: blockData?.id,
|
||||
name: blockData.name,
|
||||
sort_order: blockData?.sort_order ?? undefined,
|
||||
start_date: blockData?.start_date ?? undefined,
|
||||
target_date: blockData?.target_date ?? undefined,
|
||||
meta: {
|
||||
type,
|
||||
index,
|
||||
project_id: blockData?.project_id,
|
||||
},
|
||||
};
|
||||
if (this.currentViewData && (this.currentViewData?.data?.startDate || this.currentViewData?.data?.dayWidth)) {
|
||||
block.position = getItemPositionWidth(this.currentViewData, block);
|
||||
}
|
||||
|
||||
// create block updates if the block already exists, or push them to newBlocks
|
||||
if (this.blocksMap[blockId]) {
|
||||
for (const key of Object.keys(block)) {
|
||||
const currValue = this.blocksMap[blockId][key as keyof IGanttBlock];
|
||||
const nextValue = block[key as keyof IGanttBlock];
|
||||
if (!isEqual(currValue, nextValue)) {
|
||||
updatedBlockMaps.push({ path: [blockId, key], value: nextValue });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newBlocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
// update the store with the block updates
|
||||
runInAction(() => {
|
||||
for (const updatedBlock of updatedBlockMaps) {
|
||||
set(this.blocksMap, updatedBlock.path, updatedBlock.value);
|
||||
}
|
||||
|
||||
for (const newBlock of newBlocks) {
|
||||
set(this.blocksMap, [newBlock.id], newBlock);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* returns number of days that the position pixels span across the timeline chart
|
||||
* @param position
|
||||
* @returns
|
||||
*/
|
||||
getNumberOfDaysFromPosition = (position: number | undefined) => {
|
||||
if (!this.currentViewData || !position) return;
|
||||
|
||||
return Math.round(position / this.currentViewData.data.dayWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
* returns position of the date on chart
|
||||
*/
|
||||
getPositionFromDateOnGantt = computedFn((date: string | Date, offSetWidth: number) => {
|
||||
if (!this.currentViewData) return;
|
||||
|
||||
return getPositionFromDate(this.currentViewData, date, offSetWidth);
|
||||
});
|
||||
|
||||
/**
|
||||
* returns the date at which the position corresponds to on the timeline chart
|
||||
*/
|
||||
getDateFromPositionOnGantt = computedFn((position: number, offsetDays: number) => {
|
||||
if (!this.currentViewData) return;
|
||||
|
||||
return getDateFromPositionOnGantt(position, this.currentViewData, offsetDays);
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds width on Chart position change while the blocks are being dragged
|
||||
* @param addedWidth
|
||||
*/
|
||||
updateAllBlocksOnChartChangeWhileDragging = action((addedWidth: number) => {
|
||||
if (!this.blockIds || !this.isDragging) return;
|
||||
|
||||
runInAction(() => {
|
||||
this.blockIds?.forEach((blockId) => {
|
||||
const currBlock = this.blocksMap[blockId];
|
||||
|
||||
if (!currBlock || !currBlock.position) return;
|
||||
|
||||
currBlock.position.marginLeft += addedWidth;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* returns updates dates of blocks post drag.
|
||||
* @param id
|
||||
* @param shouldUpdateHalfBlock if is a half block then update the incomplete block only if this is true
|
||||
* @returns
|
||||
*/
|
||||
getUpdatedPositionAfterDrag = action((id: string, shouldUpdateHalfBlock: boolean) => {
|
||||
const currBlock = this.blocksMap[id];
|
||||
|
||||
if (!currBlock?.position || !this.currentViewData) return [];
|
||||
|
||||
const updatePayload: IBlockUpdateDependencyData = { id, meta: currBlock.meta };
|
||||
|
||||
// If shouldUpdateHalfBlock or the start date is available then update start date
|
||||
if (shouldUpdateHalfBlock || currBlock.start_date) {
|
||||
updatePayload.start_date = renderFormattedPayloadDate(
|
||||
getDateFromPositionOnGantt(currBlock.position.marginLeft, this.currentViewData)
|
||||
);
|
||||
}
|
||||
// If shouldUpdateHalfBlock or the target date is available then update target date
|
||||
if (shouldUpdateHalfBlock || currBlock.target_date) {
|
||||
updatePayload.target_date = renderFormattedPayloadDate(
|
||||
getDateFromPositionOnGantt(currBlock.position.marginLeft + currBlock.position.width, this.currentViewData, -1)
|
||||
);
|
||||
}
|
||||
|
||||
return [updatePayload];
|
||||
});
|
||||
|
||||
/**
|
||||
* updates the block's position such as marginLeft and width while dragging
|
||||
* @param id
|
||||
* @param deltaLeft
|
||||
* @param deltaWidth
|
||||
* @returns
|
||||
*/
|
||||
updateBlockPosition = action((id: string, deltaLeft: number, deltaWidth: number) => {
|
||||
const currBlock = this.blocksMap[id];
|
||||
|
||||
if (!currBlock?.position) return;
|
||||
|
||||
const newMarginLeft = currBlock.position.marginLeft + deltaLeft;
|
||||
const newWidth = currBlock.position.width + deltaWidth;
|
||||
|
||||
runInAction(() => {
|
||||
set(this.blocksMap, [id, "position"], {
|
||||
marginLeft: newMarginLeft ?? currBlock.position?.marginLeft,
|
||||
width: newWidth ?? currBlock.position?.width,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Dummy method to return if the current Block's dependency is being dragged
|
||||
getIsCurrentDependencyDragging = computedFn((blockId: string) => false);
|
||||
}
|
||||
29
apps/web/ce/store/timeline/index.ts
Normal file
29
apps/web/ce/store/timeline/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { RootStore } from "@/plane-web/store/root.store";
|
||||
import { IssuesTimeLineStore } from "@/store/timeline/issues-timeline.store";
|
||||
import type { IIssuesTimeLineStore } from "@/store/timeline/issues-timeline.store";
|
||||
import { ModulesTimeLineStore } from "@/store/timeline/modules-timeline.store";
|
||||
import type { IModulesTimeLineStore } from "@/store/timeline/modules-timeline.store";
|
||||
import { BaseTimeLineStore } from "./base-timeline.store";
|
||||
import type { IBaseTimelineStore } from "./base-timeline.store";
|
||||
|
||||
export interface ITimelineStore {
|
||||
issuesTimeLineStore: IIssuesTimeLineStore;
|
||||
modulesTimeLineStore: IModulesTimeLineStore;
|
||||
projectTimeLineStore: IBaseTimelineStore;
|
||||
groupedTimeLineStore: IBaseTimelineStore;
|
||||
}
|
||||
|
||||
export class TimeLineStore implements ITimelineStore {
|
||||
issuesTimeLineStore: IIssuesTimeLineStore;
|
||||
modulesTimeLineStore: IModulesTimeLineStore;
|
||||
projectTimeLineStore: IBaseTimelineStore;
|
||||
groupedTimeLineStore: IBaseTimelineStore;
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
this.issuesTimeLineStore = new IssuesTimeLineStore(rootStore);
|
||||
this.modulesTimeLineStore = new ModulesTimeLineStore(rootStore);
|
||||
// Dummy store
|
||||
this.projectTimeLineStore = new BaseTimeLineStore(rootStore);
|
||||
this.groupedTimeLineStore = new BaseTimeLineStore(rootStore);
|
||||
}
|
||||
}
|
||||
24
apps/web/ce/store/user/permission.store.ts
Normal file
24
apps/web/ce/store/user/permission.store.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { computedFn } from "mobx-utils";
|
||||
import type { EUserPermissions } from "@plane/constants";
|
||||
import type { RootStore } from "@/plane-web/store/root.store";
|
||||
import { BaseUserPermissionStore } from "@/store/user/base-permissions.store";
|
||||
import type { IBaseUserPermissionStore } from "@/store/user/base-permissions.store";
|
||||
|
||||
export type IUserPermissionStore = IBaseUserPermissionStore;
|
||||
|
||||
export class UserPermissionStore extends BaseUserPermissionStore implements IUserPermissionStore {
|
||||
constructor(store: RootStore) {
|
||||
super(store);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the project role from the workspace
|
||||
* @param { string } workspaceSlug
|
||||
* @param { string } projectId
|
||||
* @returns { EUserPermissions | undefined }
|
||||
*/
|
||||
getProjectRoleByWorkspaceSlugAndProjectId = computedFn(
|
||||
(workspaceSlug: string, projectId: string): EUserPermissions | undefined =>
|
||||
this.getProjectRole(workspaceSlug, projectId)
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user