ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: отправка во внешний контур и source-side список
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useContext } from "react";
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
import type { IProjectExternalContoursStore } from "@/store/external-contours/project-external-contours.store";
|
||||
|
||||
export const useProjectExternalContours = (): IProjectExternalContoursStore => {
|
||||
const context = useContext(StoreContext);
|
||||
if (context === undefined) throw new Error("useProjectExternalContours must be used within StoreProvider");
|
||||
return context.projectExternalContours;
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { API_BASE_URL } from "@plane/constants";
|
||||
import type { TExternalContourRequest, TExternalContourRequestResponse, TIssue } from "@plane/types";
|
||||
import { APIService } from "@/services/api.service";
|
||||
|
||||
export class ExternalContourService extends APIService {
|
||||
constructor() {
|
||||
super(API_BASE_URL);
|
||||
}
|
||||
|
||||
async list(workspaceSlug: string, projectId: string): Promise<TExternalContourRequestResponse> {
|
||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/external-contours/`)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
async retrieve(workspaceSlug: string, projectId: string, requestId: string): Promise<TExternalContourRequest> {
|
||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/external-contours/${requestId}/`)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
async create(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: Partial<TIssue> & { target_project_id?: string | null }
|
||||
): Promise<TExternalContourRequest> {
|
||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/external-contours/`, {
|
||||
target_project_id: data.target_project_id,
|
||||
issue: {
|
||||
name: data.name,
|
||||
description_html: data.description_html,
|
||||
priority: data.priority,
|
||||
assignee_ids: data.assignee_ids,
|
||||
label_ids: data.label_ids,
|
||||
target_date: data.target_date || null,
|
||||
},
|
||||
})
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./external-contour.service";
|
||||
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { set } from "lodash-es";
|
||||
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||
import type { TExternalContourRequest, TInboxIssueCurrentTab, TIssue } from "@plane/types";
|
||||
import { EInboxIssueCurrentTab } from "@plane/types";
|
||||
import { ExternalContourService } from "@/services/external-contours";
|
||||
import type { CoreRootStore } from "../root.store";
|
||||
|
||||
type TLoader = "init-loading" | "mutation-loading" | "issue-loading" | undefined;
|
||||
|
||||
export interface IProjectExternalContoursStore {
|
||||
currentProjectId: string;
|
||||
currentTab: TInboxIssueCurrentTab;
|
||||
error: { message: string; status: "init-error" } | undefined;
|
||||
loader: TLoader;
|
||||
requestIds: string[];
|
||||
requests: Record<string, TExternalContourRequest>;
|
||||
createRequest: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: Partial<TIssue> & { target_project_id?: string | null }
|
||||
) => Promise<TExternalContourRequest | undefined>;
|
||||
fetchRequestById: (workspaceSlug: string, projectId: string, requestId: string) => Promise<TExternalContourRequest | undefined>;
|
||||
fetchRequests: (workspaceSlug: string, projectId: string, tab?: TInboxIssueCurrentTab) => Promise<void>;
|
||||
getIsRequestAvailable: (requestId: string) => boolean;
|
||||
getRequestById: (requestId: string) => TExternalContourRequest | undefined;
|
||||
handleCurrentTab: (workspaceSlug: string, projectId: string, tab: TInboxIssueCurrentTab) => Promise<void>;
|
||||
openRequestIds: string[];
|
||||
closedRequestIds: string[];
|
||||
filteredRequestIds: string[];
|
||||
upsertRequests: (requests: TExternalContourRequest[]) => void;
|
||||
updateRequestIssue: (requestId: string, issueData: Partial<TExternalContourRequest["issue"]>) => void;
|
||||
}
|
||||
|
||||
export class ProjectExternalContoursStore implements IProjectExternalContoursStore {
|
||||
currentProjectId = "";
|
||||
currentTab: TInboxIssueCurrentTab = EInboxIssueCurrentTab.OPEN;
|
||||
error: { message: string; status: "init-error" } | undefined = undefined;
|
||||
loader: TLoader = "init-loading";
|
||||
requestIds: string[] = [];
|
||||
requests: Record<string, TExternalContourRequest> = {};
|
||||
|
||||
externalContourService;
|
||||
|
||||
constructor(_store: CoreRootStore) {
|
||||
makeObservable(this, {
|
||||
currentProjectId: observable.ref,
|
||||
currentTab: observable.ref,
|
||||
error: observable.ref,
|
||||
loader: observable.ref,
|
||||
requestIds: observable.shallow,
|
||||
requests: observable,
|
||||
openRequestIds: computed,
|
||||
closedRequestIds: computed,
|
||||
filteredRequestIds: computed,
|
||||
fetchRequests: action,
|
||||
fetchRequestById: action,
|
||||
createRequest: action,
|
||||
handleCurrentTab: action,
|
||||
upsertRequests: action,
|
||||
updateRequestIssue: action,
|
||||
});
|
||||
|
||||
this.externalContourService = new ExternalContourService();
|
||||
}
|
||||
|
||||
get openRequestIds() {
|
||||
return this.requestIds.filter((requestId) => this.requests[requestId]?.status === "open");
|
||||
}
|
||||
|
||||
get closedRequestIds() {
|
||||
return this.requestIds.filter((requestId) => this.requests[requestId]?.status === "closed");
|
||||
}
|
||||
|
||||
get filteredRequestIds() {
|
||||
return this.currentTab === EInboxIssueCurrentTab.CLOSED ? this.closedRequestIds : this.openRequestIds;
|
||||
}
|
||||
|
||||
getRequestById = (requestId: string) => this.requests[requestId];
|
||||
|
||||
getIsRequestAvailable = (requestId: string) => this.requestIds.includes(requestId);
|
||||
|
||||
upsertRequests = (requests: TExternalContourRequest[]) => {
|
||||
requests.forEach((request) => {
|
||||
set(this.requests, request.id, request);
|
||||
if (!this.requestIds.includes(request.id)) this.requestIds.push(request.id);
|
||||
});
|
||||
this.requestIds = this.requestIds.sort((left, right) => {
|
||||
const leftUpdatedAt = this.requests[left]?.updated_at || "";
|
||||
const rightUpdatedAt = this.requests[right]?.updated_at || "";
|
||||
return rightUpdatedAt.localeCompare(leftUpdatedAt);
|
||||
});
|
||||
};
|
||||
|
||||
handleCurrentTab = async (workspaceSlug: string, projectId: string, tab: TInboxIssueCurrentTab) => {
|
||||
this.currentTab = tab;
|
||||
await this.fetchRequests(workspaceSlug, projectId, tab);
|
||||
};
|
||||
|
||||
fetchRequests = async (workspaceSlug: string, projectId: string, tab = this.currentTab) => {
|
||||
this.loader = "init-loading";
|
||||
this.error = undefined;
|
||||
this.currentProjectId = projectId;
|
||||
this.currentTab = tab;
|
||||
|
||||
try {
|
||||
const response = await this.externalContourService.list(workspaceSlug, projectId);
|
||||
runInAction(() => {
|
||||
this.requestIds = [];
|
||||
this.requests = {};
|
||||
this.upsertRequests(response.results || []);
|
||||
this.loader = undefined;
|
||||
});
|
||||
} catch (error: any) {
|
||||
runInAction(() => {
|
||||
this.loader = undefined;
|
||||
this.error = {
|
||||
message: error?.error || "Не удалось загрузить внешние контуры",
|
||||
status: "init-error",
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fetchRequestById = async (workspaceSlug: string, projectId: string, requestId: string) => {
|
||||
this.loader = "issue-loading";
|
||||
try {
|
||||
const request = await this.externalContourService.retrieve(workspaceSlug, projectId, requestId);
|
||||
runInAction(() => {
|
||||
this.upsertRequests([request]);
|
||||
this.loader = undefined;
|
||||
});
|
||||
return request;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = undefined;
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
createRequest = async (workspaceSlug: string, projectId: string, data: Partial<TIssue> & { target_project_id?: string | null }) => {
|
||||
this.loader = "mutation-loading";
|
||||
try {
|
||||
const request = await this.externalContourService.create(workspaceSlug, projectId, data);
|
||||
runInAction(() => {
|
||||
this.upsertRequests([request]);
|
||||
this.currentTab = EInboxIssueCurrentTab.OPEN;
|
||||
this.loader = undefined;
|
||||
});
|
||||
return request;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.loader = undefined;
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateRequestIssue = (requestId: string, issueData: Partial<TExternalContourRequest["issue"]>) => {
|
||||
if (!this.requests[requestId]) return;
|
||||
const nextStatus =
|
||||
issueData.state_detail?.group !== undefined
|
||||
? ["completed", "cancelled"].includes(issueData.state_detail.group)
|
||||
? "closed"
|
||||
: "open"
|
||||
: this.requests[requestId].status;
|
||||
this.requests[requestId] = {
|
||||
...this.requests[requestId],
|
||||
issue: {
|
||||
...this.requests[requestId].issue,
|
||||
...issueData,
|
||||
},
|
||||
status: nextStatus,
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import type { IEditorAssetStore } from "./editor/asset.store";
|
||||
import { EditorAssetStore } from "./editor/asset.store";
|
||||
import type { IProjectEstimateStore } from "./estimates/project-estimate.store";
|
||||
import { ProjectEstimateStore } from "./estimates/project-estimate.store";
|
||||
import type { IProjectExternalContoursStore } from "./external-contours/project-external-contours.store";
|
||||
import { ProjectExternalContoursStore } from "./external-contours/project-external-contours.store";
|
||||
import type { IFavoriteStore } from "./favorite.store";
|
||||
import { FavoriteStore } from "./favorite.store";
|
||||
import type { IGlobalViewStore } from "./global-view.store";
|
||||
@@ -93,6 +95,7 @@ export class CoreRootStore {
|
||||
instance: IInstanceStore;
|
||||
user: IUserStore;
|
||||
projectInbox: IProjectInboxStore;
|
||||
projectExternalContours: IProjectExternalContoursStore;
|
||||
projectEstimate: IProjectEstimateStore;
|
||||
multipleSelect: IMultipleSelectStore;
|
||||
workspaceNotification: IWorkspaceNotificationStore;
|
||||
@@ -123,6 +126,7 @@ export class CoreRootStore {
|
||||
this.dashboard = new DashboardStore(this);
|
||||
this.multipleSelect = new MultipleSelectStore();
|
||||
this.projectInbox = new ProjectInboxStore(this);
|
||||
this.projectExternalContours = new ProjectExternalContoursStore(this);
|
||||
this.projectPages = new ProjectPageStore(this as unknown as RootStore);
|
||||
this.projectEstimate = new ProjectEstimateStore(this);
|
||||
this.workspaceNotification = new WorkspaceNotificationStore(this);
|
||||
@@ -156,6 +160,7 @@ export class CoreRootStore {
|
||||
this.label = new LabelStore(this);
|
||||
this.dashboard = new DashboardStore(this);
|
||||
this.projectInbox = new ProjectInboxStore(this);
|
||||
this.projectExternalContours = new ProjectExternalContoursStore(this);
|
||||
this.projectPages = new ProjectPageStore(this as unknown as RootStore);
|
||||
this.multipleSelect = new MultipleSelectStore();
|
||||
this.projectEstimate = new ProjectEstimateStore(this);
|
||||
|
||||
Reference in New Issue
Block a user