feat: init
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
chuan
2025-11-11 01:56:44 +08:00
commit bba4bb40c8
4638 changed files with 447437 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
// helpers
import { API_BASE_URL } from "@plane/constants";
// plane web constants
import type { AI_EDITOR_TASKS } from "@/plane-web/constants/ai";
// services
import { APIService } from "@/services/api.service";
// types
// FIXME:
// import { IGptResponse } from "@plane/types";
// helpers
export type TTaskPayload = {
casual_score?: number;
formal_score?: number;
task: AI_EDITOR_TASKS;
text_input: string;
};
export class AIService extends APIService {
constructor() {
super(API_BASE_URL);
}
async createGptTask(workspaceSlug: string, data: { prompt: string; task: string }): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/ai-assistant/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async performEditorTask(
workspaceSlug: string,
data: TTaskPayload
): Promise<{
response: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/rephrase-grammar/`, data)
.then((res) => res?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,106 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import type {
IAnalyticsResponse,
TAnalyticsTabsBase,
TAnalyticsGraphsBase,
TAnalyticsFilterParams,
} from "@plane/types";
// services
import { APIService } from "./api.service";
export class AnalyticsService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getAdvanceAnalytics<T extends IAnalyticsResponse>(
workspaceSlug: string,
tab: TAnalyticsTabsBase,
params?: TAnalyticsFilterParams,
isPeekView?: boolean
): Promise<T> {
return this.get(this.processUrl<TAnalyticsTabsBase>("advance-analytics", workspaceSlug, tab, params, isPeekView), {
params: {
tab,
...params,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getAdvanceAnalyticsStats<T>(
workspaceSlug: string,
tab: Exclude<TAnalyticsTabsBase, "overview">,
params?: TAnalyticsFilterParams,
isPeekView?: boolean
): Promise<T> {
const processedUrl = this.processUrl<Exclude<TAnalyticsTabsBase, "overview">>(
"advance-analytics-stats",
workspaceSlug,
tab,
params,
isPeekView
);
return this.get(processedUrl, {
params: {
type: tab,
...params,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getAdvanceAnalyticsCharts<T>(
workspaceSlug: string,
tab: TAnalyticsGraphsBase,
params?: TAnalyticsFilterParams,
isPeekView?: boolean
): Promise<T> {
const processedUrl = this.processUrl<TAnalyticsGraphsBase>(
"advance-analytics-charts",
workspaceSlug,
tab,
params,
isPeekView
);
return this.get(processedUrl, {
params: {
type: tab,
...params,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
processUrl<T extends string>(
endpoint: string,
workspaceSlug: string,
tab: TAnalyticsGraphsBase | TAnalyticsTabsBase,
params?: TAnalyticsFilterParams,
isPeekView?: boolean
) {
let processedUrl = `/api/workspaces/${workspaceSlug}`;
if (isPeekView && (tab === "work-items" || tab === "custom-work-items")) {
const projectIds = params?.project_ids;
if (typeof projectIds !== "string" || !projectIds.trim()) {
throw new Error("project_ids parameter is required for peek view of work items");
}
const projectId = projectIds.split(",")[0];
if (!projectId) {
throw new Error("Invalid project_ids format - no project ID found");
}
processedUrl += `/projects/${projectId}`;
}
return `${processedUrl}/${endpoint}`;
}
}

View File

@@ -0,0 +1,58 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { AxiosInstance, AxiosRequestConfig } from "axios";
import axios from "axios";
export abstract class APIService {
protected baseURL: string;
private axiosInstance: AxiosInstance;
constructor(baseURL: string) {
this.baseURL = baseURL;
this.axiosInstance = axios.create({
baseURL,
withCredentials: true,
});
this.setupInterceptors();
}
private setupInterceptors() {
this.axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
const currentPath = window.location.pathname;
window.location.replace(`/${currentPath ? `?next_path=${currentPath}` : ``}`);
}
return Promise.reject(error);
}
);
}
get(url: string, params = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.get(url, {
...params,
...config,
});
}
post(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.post(url, data, config);
}
put(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.put(url, data, config);
}
patch(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.patch(url, data, config);
}
delete(url: string, data?: any, config: AxiosRequestConfig = {}) {
return this.axiosInstance.delete(url, { data, ...config });
}
request(config = {}) {
return this.axiosInstance(config);
}
}

View File

@@ -0,0 +1,23 @@
// services
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/services/api.service";
// helper
// types
// FIXME:
// import { TAppConfig } from "@plane/types";
export class AppConfigService extends APIService {
constructor() {
super(API_BASE_URL);
}
async envConfig(): Promise<any> {
return this.get("/api/configs/", {
headers: { "Content-Type": "application/json" },
})
.then((response) => response.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,63 @@
// services
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/services/api.service";
// helpers
export class AppInstallationService extends APIService {
constructor() {
super(API_BASE_URL);
}
async addInstallationApp(workspaceSlug: string, provider: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/workspace-integrations/${provider}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async addSlackChannel(
workspaceSlug: string,
projectId: string,
integrationId: string | null | undefined,
data: any
): Promise<any> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getSlackChannelDetail(
workspaceSlug: string,
projectId: string,
integrationId: string | null | undefined
): Promise<any> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async removeSlackChannel(
workspaceSlug: string,
projectId: string,
integrationId: string | null | undefined,
slackSyncId: string | undefined
): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/${slackSyncId}`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}

View File

@@ -0,0 +1,78 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { ICsrfTokenData, IEmailCheckData, IEmailCheckResponse } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class AuthService extends APIService {
constructor() {
super(API_BASE_URL);
}
async requestCSRFToken(): Promise<ICsrfTokenData> {
return this.get("/auth/get-csrf-token/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
emailCheck = async (data: IEmailCheckData): Promise<IEmailCheckResponse> =>
this.post("/auth/email-check/", data, { headers: {} })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
async sendResetPasswordLink(data: { email: string }): Promise<any> {
return this.post(`/auth/forgot-password/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async setPassword(token: string, data: { password: string }): Promise<any> {
return this.post(`/auth/set-password/`, data, {
headers: {
"X-CSRFTOKEN": token,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async generateUniqueCode(data: { email: string }): Promise<any> {
return this.post("/auth/magic-generate/", data, { headers: {} })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async signOut(baseUrl: string): Promise<any> {
await this.requestCSRFToken().then((data) => {
const csrfToken = data?.csrf_token;
if (!csrfToken) throw Error("CSRF token not found");
const form = document.createElement("form");
const element1 = document.createElement("input");
form.method = "POST";
form.action = `${baseUrl}/auth/sign-out/`;
element1.value = csrfToken;
element1.name = "csrfmiddlewaretoken";
element1.type = "hidden";
form.appendChild(element1);
document.body.appendChild(form);
form.submit();
});
}
}

View File

@@ -0,0 +1,191 @@
// services
import { API_BASE_URL } from "@plane/constants";
import type {
CycleDateCheckData,
ICycle,
TIssuesResponse,
IWorkspaceActiveCyclesResponse,
TCycleDistribution,
TProgressSnapshot,
TCycleEstimateDistribution,
} from "@plane/types";
import { APIService } from "@/services/api.service";
export class CycleService extends APIService {
constructor() {
super(API_BASE_URL);
}
async workspaceActiveCyclesAnalytics(
workspaceSlug: string,
projectId: string,
cycleId: string,
analytic_type: string = "points"
): Promise<TCycleDistribution | TCycleEstimateDistribution> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/analytics?type=${analytic_type}`
)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async workspaceActiveCyclesProgress(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<TProgressSnapshot> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/progress/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async workspaceActiveCyclesProgressPro(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<TProgressSnapshot> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-progress/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async workspaceActiveCycles(
workspaceSlug: string,
cursor: string,
per_page: number
): Promise<IWorkspaceActiveCyclesResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/active-cycles/`, {
params: {
per_page,
cursor,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getWorkspaceCycles(workspaceSlug: string): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/cycles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createCycle(workspaceSlug: string, projectId: string, data: any): Promise<ICycle> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getCyclesWithParams(workspaceSlug: string, projectId: string, cycleType?: "current"): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, {
params: {
cycle_view: cycleType,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getCycleDetails(workspaceSlug: string, projectId: string, cycleId: string): Promise<ICycle> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getCycleIssues(
workspaceSlug: string,
projectId: string,
cycleId: string,
queries?: any,
config = {}
): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`,
{
params: queries,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchCycle(workspaceSlug: string, projectId: string, cycleId: string, data: Partial<ICycle>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async cycleDateCheck(workspaceSlug: string, projectId: string, data: CycleDateCheckData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/date-check/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addCycleToFavorites(
workspaceSlug: string,
projectId: string,
data: {
cycle: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async transferIssues(
workspaceSlug: string,
projectId: string,
cycleId: string,
data: {
new_cycle_id: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/transfer-issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeCycleFromFavorites(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/${cycleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,50 @@
// type
import { API_BASE_URL } from "@plane/constants";
import type { ICycle } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class CycleArchiveService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getArchivedCycles(workspaceSlug: string, projectId: string): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-cycles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getArchivedCycleDetails(workspaceSlug: string, projectId: string, cycleId: string): Promise<ICycle> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-cycles/${cycleId}/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async archiveCycle(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,53 @@
import { API_BASE_URL } from "@plane/constants";
import type { THomeDashboardResponse, TWidget, TWidgetStatsResponse, TWidgetStatsRequestParams } from "@plane/types";
import { APIService } from "@/services/api.service";
// helpers
// types
export class DashboardService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getHomeDashboardWidgets(workspaceSlug: string): Promise<THomeDashboardResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/dashboard/`, {
params: {
dashboard_type: "home",
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWidgetStats(
workspaceSlug: string,
dashboardId: string,
params: TWidgetStatsRequestParams
): Promise<TWidgetStatsResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/dashboard/${dashboardId}/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getDashboardDetails(dashboardId: string): Promise<TWidgetStatsResponse> {
return this.get(`/api/dashboard/${dashboardId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateDashboardWidget(dashboardId: string, widgetId: string, data: Partial<TWidget>): Promise<TWidget> {
return this.patch(`/api/dashboard/${dashboardId}/widgets/${widgetId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,56 @@
import { API_BASE_URL } from "@plane/constants";
import type { IFavorite } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
// types
export class FavoriteService extends APIService {
constructor() {
super(API_BASE_URL);
}
async addFavorite(workspaceSlug: string, data: Partial<IFavorite>): Promise<IFavorite> {
return this.post(`/api/workspaces/${workspaceSlug}/user-favorites/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateFavorite(workspaceSlug: string, favoriteId: string, data: Partial<IFavorite>): Promise<IFavorite> {
return this.patch(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteFavorite(workspaceSlug: string, favoriteId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getFavorites(workspaceSlug: string): Promise<IFavorite[]> {
return this.get(`/api/workspaces/${workspaceSlug}/user-favorites/`, {
params: {
all: true,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getGroupedFavorites(workspaceSlug: string, favoriteId: string): Promise<IFavorite[]> {
return this.get(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/group/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1 @@
export * from "./favorite.service";

View File

@@ -0,0 +1,40 @@
import type { AxiosRequestConfig } from "axios";
import axios from "axios";
// services
import { APIService } from "@/services/api.service";
export class FileUploadService extends APIService {
private cancelSource: any;
constructor() {
super("");
}
async uploadFile(
url: string,
data: FormData,
uploadProgressHandler?: AxiosRequestConfig["onUploadProgress"]
): Promise<void> {
this.cancelSource = axios.CancelToken.source();
return this.post(url, data, {
headers: {
"Content-Type": "multipart/form-data",
},
cancelToken: this.cancelSource.token,
withCredentials: false,
onUploadProgress: uploadProgressHandler,
})
.then((response) => response?.data)
.catch((error) => {
if (axios.isCancel(error)) {
console.log(error.message);
} else {
throw error?.response?.data;
}
});
}
cancelUpload() {
this.cancelSource.cancel("Upload canceled");
}
}

View File

@@ -0,0 +1,284 @@
import type { AxiosRequestConfig } from "axios";
// plane types
import { API_BASE_URL } from "@plane/constants";
import { getFileMetaDataForUpload, generateFileUploadPayload } from "@plane/services";
import type { TFileEntityInfo, TFileSignedURLResponse } from "@plane/types";
import { getAssetIdFromUrl } from "@plane/utils";
// helpers
// services
import { APIService } from "@/services/api.service";
import { FileUploadService } from "@/services/file-upload.service";
export interface UnSplashImage {
id: string;
created_at: Date;
updated_at: Date;
promoted_at: Date;
width: number;
height: number;
color: string;
blur_hash: string;
description: null;
alt_description: string;
urls: UnSplashImageUrls;
[key: string]: any;
}
export interface UnSplashImageUrls {
raw: string;
full: string;
regular: string;
small: string;
thumb: string;
small_s3: string;
}
export enum TFileAssetType {
COMMENT_DESCRIPTION = "COMMENT_DESCRIPTION",
ISSUE_ATTACHMENT = "ISSUE_ATTACHMENT",
ISSUE_DESCRIPTION = "ISSUE_DESCRIPTION",
PAGE_DESCRIPTION = "PAGE_DESCRIPTION",
PROJECT_COVER = "PROJECT_COVER",
USER_AVATAR = "USER_AVATAR",
USER_COVER = "USER_COVER",
WORKSPACE_LOGO = "WORKSPACE_LOGO",
}
export class FileService extends APIService {
private cancelSource: any;
private fileUploadService: FileUploadService;
constructor() {
super(API_BASE_URL);
this.cancelUpload = this.cancelUpload.bind(this);
// upload service
this.fileUploadService = new FileUploadService();
}
private async updateWorkspaceAssetUploadStatus(workspaceSlug: string, assetId: string): Promise<void> {
return this.patch(`/api/assets/v2/workspaces/${workspaceSlug}/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async uploadWorkspaceAsset(
workspaceSlug: string,
data: TFileEntityInfo,
file: File,
uploadProgressHandler?: AxiosRequestConfig["onUploadProgress"]
): Promise<TFileSignedURLResponse> {
const fileMetaData = await getFileMetaDataForUpload(file);
return this.post(`/api/assets/v2/workspaces/${workspaceSlug}/`, {
...data,
...fileMetaData,
})
.then(async (response) => {
const signedURLResponse: TFileSignedURLResponse = response?.data;
const fileUploadPayload = generateFileUploadPayload(signedURLResponse, file);
await this.fileUploadService.uploadFile(
signedURLResponse.upload_data.url,
fileUploadPayload,
uploadProgressHandler
);
await this.updateWorkspaceAssetUploadStatus(workspaceSlug.toString(), signedURLResponse.asset_id);
return signedURLResponse;
})
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWorkspaceAsset(workspaceSlug: string, assetId: string): Promise<void> {
return this.delete(`/api/assets/v2/workspaces/${workspaceSlug}/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
private async updateProjectAssetUploadStatus(
workspaceSlug: string,
projectId: string,
assetId: string
): Promise<void> {
return this.patch(`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateBulkWorkspaceAssetsUploadStatus(
workspaceSlug: string,
entityId: string,
data: {
asset_ids: string[];
}
): Promise<void> {
return this.post(`/api/assets/v2/workspaces/${workspaceSlug}/${entityId}/bulk/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateBulkProjectAssetsUploadStatus(
workspaceSlug: string,
projectId: string,
entityId: string,
data: {
asset_ids: string[];
}
): Promise<void> {
return this.post(`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${entityId}/bulk/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async uploadProjectAsset(
workspaceSlug: string,
projectId: string,
data: TFileEntityInfo,
file: File,
uploadProgressHandler?: AxiosRequestConfig["onUploadProgress"]
): Promise<TFileSignedURLResponse> {
const fileMetaData = await getFileMetaDataForUpload(file);
return this.post(`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/`, {
...data,
...fileMetaData,
})
.then(async (response) => {
const signedURLResponse: TFileSignedURLResponse = response?.data;
const fileUploadPayload = generateFileUploadPayload(signedURLResponse, file);
await this.fileUploadService.uploadFile(
signedURLResponse.upload_data.url,
fileUploadPayload,
uploadProgressHandler
);
await this.updateProjectAssetUploadStatus(workspaceSlug, projectId, signedURLResponse.asset_id);
return signedURLResponse;
})
.catch((error) => {
throw error?.response?.data;
});
}
private async updateUserAssetUploadStatus(assetId: string): Promise<void> {
return this.patch(`/api/assets/v2/user-assets/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async uploadUserAsset(data: TFileEntityInfo, file: File): Promise<TFileSignedURLResponse> {
const fileMetaData = await getFileMetaDataForUpload(file);
return this.post(`/api/assets/v2/user-assets/`, {
...data,
...fileMetaData,
})
.then(async (response) => {
const signedURLResponse: TFileSignedURLResponse = response?.data;
const fileUploadPayload = generateFileUploadPayload(signedURLResponse, file);
await this.fileUploadService.uploadFile(signedURLResponse.upload_data.url, fileUploadPayload);
await this.updateUserAssetUploadStatus(signedURLResponse.asset_id);
return signedURLResponse;
})
.catch((error) => {
throw error?.response?.data;
});
}
async deleteUserAsset(assetId: string): Promise<void> {
return this.delete(`/api/assets/v2/user-assets/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteNewAsset(assetPath: string): Promise<void> {
return this.delete(assetPath)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteOldWorkspaceAsset(workspaceId: string, src: string): Promise<any> {
const assetKey = getAssetIdFromUrl(src);
return this.delete(`/api/workspaces/file-assets/${workspaceId}/${assetKey}/`)
.then((response) => response?.status)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteOldUserAsset(src: string): Promise<any> {
const assetKey = getAssetIdFromUrl(src);
return this.delete(`/api/users/file-assets/${assetKey}/`)
.then((response) => response?.status)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreNewAsset(workspaceSlug: string, src: string): Promise<void> {
// remove the last slash and get the asset id
const assetId = getAssetIdFromUrl(src);
return this.post(`/api/assets/v2/workspaces/${workspaceSlug}/restore/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async checkIfAssetExists(
workspaceSlug: string,
assetId: string
): Promise<{
exists: boolean;
}> {
return this.get(`/api/assets/v2/workspaces/${workspaceSlug}/check/${assetId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreOldEditorAsset(workspaceId: string, src: string): Promise<void> {
const assetKey = getAssetIdFromUrl(src);
return this.post(`/api/workspaces/file-assets/${workspaceId}/${assetKey}/restore/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
cancelUpload() {
this.cancelSource.cancel("Upload canceled");
}
async getUnsplashImages(query?: string): Promise<UnSplashImage[]> {
return this.get(`/api/unsplash/`, {
params: {
query,
},
})
.then((res) => res?.data?.results ?? res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getProjectCoverImages(): Promise<string[]> {
return this.get(`/api/project-covers/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
}

View File

@@ -0,0 +1,80 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import type { TInboxIssue, TIssue, TInboxIssueWithPagination } from "@plane/types";
import { EInboxIssueSource } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class InboxIssueService extends APIService {
constructor() {
super(API_BASE_URL);
}
async list(workspaceSlug: string, projectId: string, params = {}): Promise<TInboxIssueWithPagination> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieve(workspaceSlug: string, projectId: string, inboxIssueId: string): Promise<TInboxIssue> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async create(workspaceSlug: string, projectId: string, data: Partial<TIssue>): Promise<TInboxIssue> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/`, {
source: EInboxIssueSource.IN_APP,
issue: data,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async update(
workspaceSlug: string,
projectId: string,
inboxIssueId: string,
data: Partial<TInboxIssue>
): Promise<TInboxIssue> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateIssue(
workspaceSlug: string,
projectId: string,
inboxIssueId: string,
data: Partial<TIssue>
): Promise<TInboxIssue> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`, {
issue: data,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async destroy(workspaceSlug: string, projectId: string, inboxIssueId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,2 @@
export * from "./inbox-issue.service";
export * from "./intake-work_item_version.service";

View File

@@ -0,0 +1,41 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import type { TDescriptionVersionsListResponse, TDescriptionVersionDetails } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class IntakeWorkItemVersionService extends APIService {
constructor() {
super(API_BASE_URL);
}
async listDescriptionVersions(
workspaceSlug: string,
projectId: string,
intakeWorkItemId: string
): Promise<TDescriptionVersionsListResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/intake-work-items/${intakeWorkItemId}/description-versions/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieveDescriptionVersion(
workspaceSlug: string,
projectId: string,
intakeWorkItemId: string,
versionId: string
): Promise<TDescriptionVersionDetails> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/intake-work-items/${intakeWorkItemId}/description-versions/${versionId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,28 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { IInstanceInfo, TPage } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class InstanceService extends APIService {
constructor() {
super(API_BASE_URL);
}
async requestCSRFToken(): Promise<{ csrf_token: string }> {
return this.get("/auth/get-csrf-token/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
async getInstanceInfo(): Promise<IInstanceInfo> {
return this.get("/api/instances/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
}

View File

@@ -0,0 +1,39 @@
import { API_BASE_URL } from "@plane/constants";
import type { IGithubRepoInfo, IGithubServiceImportFormData } from "@plane/types";
import { APIService } from "@/services/api.service";
// helpers
// types
const integrationServiceType: string = "github";
export class GithubIntegrationService extends APIService {
constructor() {
super(API_BASE_URL);
}
async listAllRepositories(workspaceSlug: string, integrationSlug: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/workspace-integrations/${integrationSlug}/github-repositories`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getGithubRepoInfo(workspaceSlug: string, params: { owner: string; repo: string }): Promise<IGithubRepoInfo> {
return this.get(`/api/workspaces/${workspaceSlug}/importers/${integrationServiceType}/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createGithubServiceImport(workspaceSlug: string, data: IGithubServiceImportFormData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,3 @@
export * from "./github.service";
export * from "./integration.service";
export * from "./jira.service";

View File

@@ -0,0 +1,67 @@
import { API_BASE_URL } from "@plane/constants";
import type { IAppIntegration, IImporterService, IWorkspaceIntegration, IExportServiceResponse } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
// helper
export class IntegrationService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getAppIntegrationsList(): Promise<IAppIntegration[]> {
return this.get(`/api/integrations/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWorkspaceIntegrationsList(workspaceSlug: string): Promise<IWorkspaceIntegration[]> {
return this.get(`/api/workspaces/${workspaceSlug}/workspace-integrations/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWorkspaceIntegration(workspaceSlug: string, integrationId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/workspace-integrations/${integrationId}/provider/`)
.then((res) => res?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getImporterServicesList(workspaceSlug: string): Promise<IImporterService[]> {
return this.get(`/api/workspaces/${workspaceSlug}/importers/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getExportsServicesList(
workspaceSlug: string,
cursor: string,
per_page: number
): Promise<IExportServiceResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/export-issues`, {
params: {
per_page,
cursor,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteImporterService(workspaceSlug: string, service: string, importerId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,28 @@
import { API_BASE_URL } from "@plane/constants";
import type { IJiraMetadata, IJiraResponse, IJiraImporterForm } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
export class JiraImporterService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getJiraProjectInfo(workspaceSlug: string, params: IJiraMetadata): Promise<IJiraResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/importers/jira`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createJiraImporter(workspaceSlug: string, data: IJiraImporterForm): Promise<IJiraResponse> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,10 @@
export * from "./issue_archive.service";
export * from "./issue.service";
export * from "./issue_reaction.service";
export * from "./issue_label.service";
export * from "./issue_attachment.service";
export * from "./issue_activity.service";
export * from "./issue_comment.service";
export * from "./issue_relation.service";
export * from "./work_item_version.service";
export * from "./workspace_draft.service";

View File

@@ -0,0 +1,497 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import { EIssueServiceType } from "@plane/types";
import type {
TIssueParams,
IIssueDisplayProperties,
TBulkOperationsPayload,
TIssue,
TIssueActivity,
TIssueLink,
TIssueServiceType,
TIssuesResponse,
TIssueSubIssues,
} from "@plane/types";
import { getIssuesShouldFallbackToServer } from "@plane/utils";
// services
import { APIService } from "@/services/api.service";
export class IssueService extends APIService {
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
this.serviceType = serviceType;
}
async createIssue(workspaceSlug: string, projectId: string, data: Partial<TIssue>): Promise<TIssue> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssuesFromServer(
workspaceSlug: string,
projectId: string,
queries?: any,
config = {}
): Promise<TIssuesResponse> {
const path =
(queries.expand as string)?.includes("issue_relation") && !queries.group_by
? `/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}-detail/`
: `/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/`;
return this.get(
path,
{
params: queries,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssuesForSync(
workspaceSlug: string,
projectId: string,
queries?: any,
config = {}
): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/v2/${this.serviceType}/`,
{ params: queries },
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssues(
workspaceSlug: string,
projectId: string,
queries?: Partial<Record<TIssueParams, string | boolean>>,
config = {}
): Promise<TIssuesResponse> {
if (getIssuesShouldFallbackToServer(queries) || this.serviceType !== EIssueServiceType.ISSUES) {
return await this.getIssuesFromServer(workspaceSlug, projectId, queries, config);
}
const { persistence } = await import("@/local-db/storage.sqlite");
const response = await persistence.getIssues(workspaceSlug, projectId, queries, config);
return response as TIssuesResponse;
}
async getDeletedIssues(workspaceSlug: string, projectId: string, queries?: any): Promise<TIssuesResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/deleted-issues/`, {
params: queries,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssuesWithParams(
workspaceSlug: string,
projectId: string,
queries?: any
): Promise<TIssue[] | { [key: string]: TIssue[] }> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/`, {
params: queries,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieve(workspaceSlug: string, projectId: string, issueId: string, queries?: any): Promise<TIssue> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/`, {
params: queries,
})
.then(async (response) => {
// skip issue update when the service type is epic
if (response.data && this.serviceType === EIssueServiceType.ISSUES) {
const { updateIssue } = await import("@/local-db/utils/load-issues");
updateIssue({ ...response.data, is_local_update: 1 });
}
// add is_epic flag when the service type is epic
if (response.data && this.serviceType === EIssueServiceType.EPICS) {
response.data.is_epic = true;
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
async retrieveIssues(workspaceSlug: string, projectId: string, issueIds: string[]): Promise<TIssue[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/list/`, {
params: { issues: issueIds.join(",") },
})
.then(async (response) => {
if (response?.data && Array.isArray(response?.data) && this.serviceType === EIssueServiceType.ISSUES) {
const { addIssuesBulk } = await import("@/local-db/utils/load-issues");
addIssuesBulk(response.data);
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
async getIssueActivities(workspaceSlug: string, projectId: string, issueId: string): Promise<TIssueActivity[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/history/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addIssueToCycle(
workspaceSlug: string,
projectId: string,
cycleId: string,
data: {
issues: string[];
}
) {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeIssueFromCycle(workspaceSlug: string, projectId: string, cycleId: string, bridgeId: string) {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/${bridgeId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createIssueRelation(
workspaceSlug: string,
projectId: string,
issueId: string,
data: {
related_list: Array<{
relation_type: "duplicate" | "relates_to" | "blocked_by";
related_issue: string;
}>;
relation?: "blocking" | null;
}
) {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/issue-relation/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteIssueRelation(workspaceSlug: string, projectId: string, issueId: string, relationId: string) {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/issue-relation/${relationId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getIssueDisplayProperties(workspaceSlug: string, projectId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateIssueDisplayProperties(
workspaceSlug: string,
projectId: string,
data: IIssueDisplayProperties
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-display-properties/`, {
properties: data,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchIssue(workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise<any> {
if (this.serviceType === EIssueServiceType.ISSUES) {
const { deleteIssueFromLocal } = await import("@/local-db/utils/load-issues");
deleteIssueFromLocal(issuesId);
}
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issuesId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateIssueDates(
workspaceSlug: string,
projectId: string,
updates: { id: string; start_date?: string; target_date?: string }[]
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-dates/`, { updates })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async subIssues(
workspaceSlug: string,
projectId: string,
issueId: string,
queries?: Partial<Record<TIssueParams, string | boolean>>
): Promise<TIssueSubIssues> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "issues" : "sub-issues"}/`,
{ params: queries }
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addSubIssues(
workspaceSlug: string,
projectId: string,
issueId: string,
data: { sub_issue_ids: string[] }
): Promise<TIssueSubIssues> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "issues" : "sub-issues"}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchIssueLinks(workspaceSlug: string, projectId: string, issueId: string): Promise<TIssueLink[]> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "links" : "issue-links"}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async createIssueLink(
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssueLink>
): Promise<TIssueLink> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "links" : "issue-links"}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateIssueLink(
workspaceSlug: string,
projectId: string,
issueId: string,
linkId: string,
data: Partial<TIssueLink>
): Promise<TIssueLink> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "links" : "issue-links"}/${linkId}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteIssueLink(workspaceSlug: string, projectId: string, issueId: string, linkId: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/${this.serviceType === EIssueServiceType.EPICS ? "links" : "issue-links"}/${linkId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async bulkOperations(workspaceSlug: string, projectId: string, data: TBulkOperationsPayload): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-operation-issues/`, data)
.then(async (response) => {
if (this.serviceType === EIssueServiceType.ISSUES) {
const { persistence } = await import("@/local-db/storage.sqlite");
persistence.syncIssues(projectId);
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
async bulkDeleteIssues(
workspaceSlug: string,
projectId: string,
data: {
issue_ids: string[];
}
): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, data)
.then(async (response) => {
if (this.serviceType === EIssueServiceType.ISSUES) {
const { persistence } = await import("@/local-db/storage.sqlite");
persistence.syncIssues(projectId);
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
async bulkArchiveIssues(
workspaceSlug: string,
projectId: string,
data: {
issue_ids: string[];
}
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-archive-issues/`, data)
.then(async (response) => {
if (this.serviceType === EIssueServiceType.ISSUES) {
const { persistence } = await import("@/local-db/storage.sqlite");
persistence.syncIssues(projectId);
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
// issue subscriptions
async getIssueNotificationSubscriptionStatus(
workspaceSlug: string,
projectId: string,
issueId: string
): Promise<{
subscribed: boolean;
}> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/subscribe/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async unsubscribeFromIssueNotifications(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/subscribe/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async subscribeToIssueNotifications(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/subscribe/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async bulkSubscribeIssues(
workspaceSlug: string,
projectId: string,
data: {
issue_ids: string[];
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-subscribe-issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssueMetaFromURL(
workspaceSlug: string,
projectId: string,
issueId: string
): Promise<{
project_identifier: string;
sequence_id: string;
}> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/meta/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieveWithIdentifier(
workspaceSlug: string,
project_identifier: string,
issue_sequence: string,
queries?: any
): Promise<TIssue> {
return this.get(`/api/workspaces/${workspaceSlug}/work-items/${project_identifier}-${issue_sequence}/`, {
params: queries,
})
.then(async (response) => {
// skip issue update when the service type is epic
if (response.data && this.serviceType === EIssueServiceType.ISSUES) {
const { updateIssue } = await import("@/local-db/utils/load-issues");
updateIssue({ ...response.data, is_local_update: 1 });
}
// add is_epic flag when the service type is epic
if (response.data && this.serviceType === EIssueServiceType.EPICS) {
response.data.is_epic = true;
}
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,37 @@
import { API_BASE_URL } from "@plane/constants";
import type { TIssueActivity, TIssueServiceType } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
// helper
export class IssueActivityService extends APIService {
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
this.serviceType = serviceType;
}
async getIssueActivities(
workspaceSlug: string,
projectId: string,
issueId: string,
params:
| {
created_at__gt: string;
}
| object = {}
): Promise<TIssueActivity[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/history/`, {
params: {
activity_type: `${this.serviceType === EIssueServiceType.EPICS ? "epic-property" : "issue-property"}`,
...params,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,66 @@
import { API_BASE_URL } from "@plane/constants";
import type { TIssue, TIssueServiceType } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
// constants
export class IssueArchiveService extends APIService {
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
this.serviceType = serviceType;
}
async getArchivedIssues(workspaceSlug: string, projectId: string, queries?: any, config = {}): Promise<any> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/`,
{
params: { ...queries },
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async archiveIssue(
workspaceSlug: string,
projectId: string,
issueId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieveArchivedIssue(
workspaceSlug: string,
projectId: string,
issueId: string,
queries?: any
): Promise<TIssue> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/archive/`, {
params: queries,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,89 @@
import type { AxiosRequestConfig } from "axios";
import { API_BASE_URL } from "@plane/constants";
// plane types
import { getFileMetaDataForUpload, generateFileUploadPayload } from "@plane/services";
import type { TIssueAttachment, TIssueAttachmentUploadResponse, TIssueServiceType } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
import { FileUploadService } from "@/services/file-upload.service";
export class IssueAttachmentService extends APIService {
private fileUploadService: FileUploadService;
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
// upload service
this.fileUploadService = new FileUploadService();
this.serviceType = serviceType;
}
private async updateIssueAttachmentUploadStatus(
workspaceSlug: string,
projectId: string,
issueId: string,
attachmentId: string
): Promise<void> {
return this.patch(
`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/attachments/${attachmentId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async uploadIssueAttachment(
workspaceSlug: string,
projectId: string,
issueId: string,
file: File,
uploadProgressHandler?: AxiosRequestConfig["onUploadProgress"]
): Promise<TIssueAttachment> {
const fileMetaData = await getFileMetaDataForUpload(file);
return this.post(
`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/attachments/`,
fileMetaData
)
.then(async (response) => {
const signedURLResponse: TIssueAttachmentUploadResponse = response?.data;
const fileUploadPayload = generateFileUploadPayload(signedURLResponse, file);
await this.fileUploadService.uploadFile(
signedURLResponse.upload_data.url,
fileUploadPayload,
uploadProgressHandler
);
await this.updateIssueAttachmentUploadStatus(workspaceSlug, projectId, issueId, signedURLResponse.asset_id);
return signedURLResponse.attachment;
})
.catch((error) => {
throw error?.response?.data;
});
}
async getIssueAttachments(workspaceSlug: string, projectId: string, issueId: string): Promise<TIssueAttachment[]> {
return this.get(
`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/attachments/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueAttachment(
workspaceSlug: string,
projectId: string,
issueId: string,
assetId: string
): Promise<TIssueAttachment> {
return this.delete(
`/api/assets/v2/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/attachments/${assetId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,89 @@
// plane types
import { API_BASE_URL } from "@plane/constants";
import type { TIssueComment, TIssueServiceType } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
import { FileUploadService } from "@/services/file-upload.service";
export class IssueCommentService extends APIService {
private fileUploadService: FileUploadService;
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
// upload service
this.fileUploadService = new FileUploadService();
this.serviceType = serviceType;
}
async getIssueComments(
workspaceSlug: string,
projectId: string,
issueId: string,
params:
| {
created_at__gt: string;
}
| object = {}
): Promise<TIssueComment[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/history/`, {
params: {
activity_type: `${this.serviceType === EIssueServiceType.EPICS ? "epic-comment" : "issue-comment"}`,
...params,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createIssueComment(
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssueComment>
): Promise<TIssueComment> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/comments/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchIssueComment(
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: Partial<TIssueComment>
): Promise<TIssueComment> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/comments/${commentId}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueComment(
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string
): Promise<void> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/comments/${commentId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,51 @@
import { API_BASE_URL } from "@plane/constants";
import type { IIssueLabel } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
// types
export class IssueLabelService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getWorkspaceIssueLabels(workspaceSlug: string): Promise<IIssueLabel[]> {
return this.get(`/api/workspaces/${workspaceSlug}/labels/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProjectLabels(workspaceSlug: string, projectId: string): Promise<IIssueLabel[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createIssueLabel(workspaceSlug: string, projectId: string, data: any): Promise<IIssueLabel> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchIssueLabel(workspaceSlug: string, projectId: string, labelId: string, data: any): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueLabel(workspaceSlug: string, projectId: string, labelId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,89 @@
import { API_BASE_URL } from "@plane/constants";
import { EIssueServiceType } from "@plane/types";
import type { TIssueCommentReaction, TIssueReaction, TIssueServiceType } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
// types
export class IssueReactionService extends APIService {
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.ISSUES) {
super(API_BASE_URL);
this.serviceType = serviceType;
}
async createIssueReaction(
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssueReaction>
): Promise<any> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/reactions/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async listIssueReactions(workspaceSlug: string, projectId: string, issueId: string): Promise<TIssueReaction[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/reactions/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueReaction(workspaceSlug: string, projectId: string, issueId: string, reaction: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issueId}/reactions/${reaction}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createIssueCommentReaction(
workspaceSlug: string,
projectId: string,
commentId: string,
data: Partial<TIssueCommentReaction>
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async listIssueCommentReactions(
workspaceSlug: string,
projectId: string,
commentId: string
): Promise<TIssueCommentReaction[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueCommentReaction(
workspaceSlug: string,
projectId: string,
commentId: string,
reaction: string
): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/${reaction}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,47 @@
import { API_BASE_URL } from "@plane/constants";
import type { TIssueRelation, TIssue } from "@plane/types";
// helpers
// Plane-web
import type { TIssueRelationTypes } from "@/plane-web/types";
// services
import { APIService } from "@/services/api.service";
export class IssueRelationService extends APIService {
constructor() {
super(API_BASE_URL);
}
async listIssueRelations(workspaceSlug: string, projectId: string, issueId: string): Promise<TIssueRelation> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-relation/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createIssueRelations(
workspaceSlug: string,
projectId: string,
issueId: string,
data: { relation_type: TIssueRelationTypes; issues: string[] }
): Promise<TIssue[]> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-relation/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteIssueRelation(
workspaceSlug: string,
projectId: string,
issueId: string,
data: { relation_type: TIssueRelationTypes; related_issue: string }
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/remove-relation/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,45 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import { EIssueServiceType } from "@plane/types";
import type { TDescriptionVersionsListResponse, TDescriptionVersionDetails, TIssueServiceType } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class WorkItemVersionService extends APIService {
private serviceType: TIssueServiceType;
constructor(serviceType: TIssueServiceType = EIssueServiceType.WORK_ITEMS) {
super(API_BASE_URL);
this.serviceType = serviceType;
}
async listDescriptionVersions(
workspaceSlug: string,
projectId: string,
workItemId: string
): Promise<TDescriptionVersionsListResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${workItemId}/description-versions/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieveDescriptionVersion(
workspaceSlug: string,
projectId: string,
workItemId: string,
versionId: string
): Promise<TDescriptionVersionDetails> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${workItemId}/description-versions/${versionId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,73 @@
import { API_BASE_URL } from "@plane/constants";
import type { TIssue, TWorkspaceDraftIssue, TWorkspaceDraftPaginationInfo } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class WorkspaceDraftService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getIssues(
workspaceSlug: string,
query: object = {}
): Promise<TWorkspaceDraftPaginationInfo<TWorkspaceDraftIssue> | undefined> {
return this.get(`/api/workspaces/${workspaceSlug}/draft-issues/`, { params: { ...query } })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssueById(workspaceSlug: string, issueId: string): Promise<TWorkspaceDraftIssue | undefined> {
return this.get(`/api/workspaces/${workspaceSlug}/draft-issues/${issueId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async createIssue(
workspaceSlug: string,
payload: Partial<TWorkspaceDraftIssue | TIssue>
): Promise<TWorkspaceDraftIssue | undefined> {
return this.post(`/api/workspaces/${workspaceSlug}/draft-issues/`, payload)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateIssue(
workspaceSlug: string,
issueId: string,
payload: Partial<TWorkspaceDraftIssue | TIssue>
): Promise<TWorkspaceDraftIssue | undefined> {
return this.patch(`/api/workspaces/${workspaceSlug}/draft-issues/${issueId}/`, payload)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteIssue(workspaceSlug: string, issueId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/draft-issues/${issueId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async moveIssue(workspaceSlug: string, issueId: string, payload: Partial<TWorkspaceDraftIssue>): Promise<TIssue> {
return this.post(`/api/workspaces/${workspaceSlug}/draft-to-issue/${issueId}/`, payload)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}
const workspaceDraftService = new WorkspaceDraftService();
export default workspaceDraftService;

View File

@@ -0,0 +1,123 @@
// services
import { API_BASE_URL } from "@plane/constants";
import type { IIssueFiltersResponse } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
export class IssueFiltersService extends APIService {
constructor() {
super(API_BASE_URL);
}
// // workspace issue filters
// async fetchWorkspaceFilters(workspaceSlug: string): Promise<IIssueFiltersResponse> {
// return this.get(`/api/workspaces/${workspaceSlug}/user-properties/`)
// .then((response) => response?.data)
// .catch((error) => {
// throw error?.response?.data;
// });
// }
// async patchWorkspaceFilters(
// workspaceSlug: string,
// data: Partial<IIssueFiltersResponse>
// ): Promise<IIssueFiltersResponse> {
// return this.patch(`/api/workspaces/${workspaceSlug}/user-properties/`, data)
// .then((response) => response?.data)
// .catch((error) => {
// throw error?.response?.data;
// });
// }
// project issue filters
async fetchProjectIssueFilters(workspaceSlug: string, projectId: string): Promise<IIssueFiltersResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchProjectIssueFilters(
workspaceSlug: string,
projectId: string,
data: Partial<IIssueFiltersResponse>
): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-properties/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
// epic issue filters
async fetchProjectEpicFilters(workspaceSlug: string, projectId: string): Promise<IIssueFiltersResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/epics-user-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchProjectEpicFilters(
workspaceSlug: string,
projectId: string,
data: Partial<IIssueFiltersResponse>
): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/epics-user-properties/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
// cycle issue filters
async fetchCycleIssueFilters(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<IIssueFiltersResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/user-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchCycleIssueFilters(
workspaceSlug: string,
projectId: string,
cycleId: string,
data: Partial<IIssueFiltersResponse>
): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/user-properties/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
// module issue filters
async fetchModuleIssueFilters(
workspaceSlug: string,
projectId: string,
moduleId: string
): Promise<IIssueFiltersResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/user-properties/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchModuleIssueFilters(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: Partial<IIssueFiltersResponse>
): Promise<any> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/user-properties/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,218 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { IModule, ILinkDetails, ModuleLink, TIssuesResponse } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
export class ModuleService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getWorkspaceModules(workspaceSlug: string): Promise<IModule[]> {
return this.get(`/api/workspaces/${workspaceSlug}/modules/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getModules(workspaceSlug: string, projectId: string): Promise<IModule[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createModule(workspaceSlug: string, projectId: string, data: any): Promise<IModule> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateModule(workspaceSlug: string, projectId: string, moduleId: string, data: any): Promise<any> {
return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getModuleDetails(workspaceSlug: string, projectId: string, moduleId: string): Promise<IModule> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchModule(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: Partial<IModule>
): Promise<IModule> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteModule(workspaceSlug: string, projectId: string, moduleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getModuleIssues(
workspaceSlug: string,
projectId: string,
moduleId: string,
queries?: any,
config = {}
): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`,
{
params: queries,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addIssuesToModule(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: { issues: string[] }
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addModulesToIssue(
workspaceSlug: string,
projectId: string,
issueId: string,
data: { modules: string[]; removed_modules?: string[] }
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/modules/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeIssuesFromModuleBulk(
workspaceSlug: string,
projectId: string,
moduleId: string,
issueIds: string[]
): Promise<void> {
const promiseDataUrls: any = [];
issueIds.forEach((issueId) => {
promiseDataUrls.push(
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
);
});
await Promise.all(promiseDataUrls)
.then((response) => response)
.catch((error) => {
throw error?.response?.data;
});
}
async removeModulesFromIssueBulk(
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
): Promise<void> {
const promiseDataUrls: any = [];
moduleIds.forEach((moduleId) => {
promiseDataUrls.push(
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
);
});
await Promise.all(promiseDataUrls)
.then((response) => response)
.catch((error) => {
throw error?.response?.data;
});
}
async createModuleLink(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: Partial<ModuleLink>
): Promise<ILinkDetails> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateModuleLink(
workspaceSlug: string,
projectId: string,
moduleId: string,
linkId: string,
data: Partial<ModuleLink>
): Promise<ILinkDetails> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteModuleLink(workspaceSlug: string, projectId: string, moduleId: string, linkId: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addModuleToFavorites(
workspaceSlug: string,
projectId: string,
data: {
module: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeModuleFromFavorites(workspaceSlug: string, projectId: string, moduleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,50 @@
// type
import { API_BASE_URL } from "@plane/constants";
import type { IModule } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class ModuleArchiveService extends APIService {
constructor() {
super(API_BASE_URL);
}
async getArchivedModules(workspaceSlug: string, projectId: string): Promise<IModule[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-modules/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getArchivedModuleDetails(workspaceSlug: string, projectId: string, moduleId: string): Promise<IModule> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async archiveModule(
workspaceSlug: string,
projectId: string,
moduleId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreModule(workspaceSlug: string, projectId: string, moduleId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,2 @@
export * from "./project-page-version.service";
export * from "./project-page.service";

View File

@@ -0,0 +1,43 @@
// plane types
import { API_BASE_URL } from "@plane/constants";
import type { TPageVersion } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class ProjectPageVersionService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetchAllVersions(workspaceSlug: string, projectId: string, pageId: string): Promise<TPageVersion[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/versions/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchVersionById(
workspaceSlug: string,
projectId: string,
pageId: string,
versionId: string
): Promise<TPageVersion> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/versions/${versionId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreVersion(workspaceSlug: string, projectId: string, pageId: string, versionId: string): Promise<void> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/versions/${versionId}/restore/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,188 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { TDocumentPayload, TPage } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
import { FileUploadService } from "@/services/file-upload.service";
export class ProjectPageService extends APIService {
private fileUploadService: FileUploadService;
constructor() {
super(API_BASE_URL);
// upload service
this.fileUploadService = new FileUploadService();
}
async fetchAll(workspaceSlug: string, projectId: string): Promise<TPage[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchById(workspaceSlug: string, projectId: string, pageId: string, trackVisit: boolean): Promise<TPage> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, {
params: {
track_visit: trackVisit,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async create(workspaceSlug: string, projectId: string, data: Partial<TPage>): Promise<TPage> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async update(workspaceSlug: string, projectId: string, pageId: string, data: Partial<TPage>): Promise<TPage> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateAccess(
workspaceSlug: string,
projectId: string,
pageId: string,
data: Pick<TPage, "access">
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/access/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async remove(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchFavorites(workspaceSlug: string, projectId: string): Promise<TPage[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/favorite-pages/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addToFavorites(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/favorite-pages/${pageId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeFromFavorites(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/favorite-pages/${pageId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchArchived(workspaceSlug: string, projectId: string): Promise<TPage[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-pages/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async archive(
workspaceSlug: string,
projectId: string,
pageId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restore(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async lock(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/lock/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async unlock(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/lock/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchDescriptionBinary(workspaceSlug: string, projectId: string, pageId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/description/`, {
headers: {
"Content-Type": "application/octet-stream",
},
responseType: "arraybuffer",
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateDescription(
workspaceSlug: string,
projectId: string,
pageId: string,
data: TDocumentPayload
): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/description/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error;
});
}
async duplicate(workspaceSlug: string, projectId: string, pageId: string): Promise<TPage> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/duplicate/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async move(workspaceSlug: string, projectId: string, pageId: string, newProjectId: string): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/move/`, {
new_project_id: newProjectId,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,6 @@
export * from "./project.service";
export * from "./project-export.service";
export * from "./project-member.service";
export * from "./project-state.service";
export * from "./project-publish.service";
export * from "./project-archive.service";

View File

@@ -0,0 +1,31 @@
// helpers
import { API_BASE_URL } from "@plane/constants";
// services
import { APIService } from "@/services/api.service";
export class ProjectArchiveService extends APIService {
constructor() {
super(API_BASE_URL);
}
async archiveProject(
workspaceSlug: string,
projectId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async restoreProject(workspaceSlug: string, projectId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,23 @@
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/services/api.service";
// helpers
export class ProjectExportService extends APIService {
constructor() {
super(API_BASE_URL);
}
async csvExport(
workspaceSlug: string,
data: {
provider: string;
project: string[];
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/export-issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,72 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { IProjectBulkAddFormData, TProjectMembership } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
export class ProjectMemberService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetchProjectMembers(workspaceSlug: string, projectId: string): Promise<TProjectMembership[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async bulkAddMembersToProject(
workspaceSlug: string,
projectId: string,
data: IProjectBulkAddFormData
): Promise<TProjectMembership[]> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async projectMemberMe(workspaceSlug: string, projectId: string): Promise<TProjectMembership> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/me/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getProjectMember(workspaceSlug: string, projectId: string, memberId: string): Promise<TProjectMembership> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateProjectMember(
workspaceSlug: string,
projectId: string,
memberId: string,
data: Partial<TProjectMembership>
): Promise<TProjectMembership> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteProjectMember(workspaceSlug: string, projectId: string, memberId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
const projectMemberService = new ProjectMemberService();
export default projectMemberService;

View File

@@ -0,0 +1,58 @@
// types
import { API_BASE_URL } from "@plane/constants";
import type { TProjectPublishSettings } from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class ProjectPublishService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetchPublishSettings(workspaceSlug: string, projectID: string): Promise<TProjectPublishSettings> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async publishProject(
workspaceSlug: string,
projectID: string,
data: Partial<TProjectPublishSettings>
): Promise<TProjectPublishSettings> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updatePublishSettings(
workspaceSlug: string,
projectID: string,
project_publish_id: string,
data: Partial<TProjectPublishSettings>
): Promise<TProjectPublishSettings> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/${project_publish_id}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async unpublishProject(workspaceSlug: string, projectID: string, project_publish_id: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/${project_publish_id}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}

View File

@@ -0,0 +1,76 @@
// services
import { API_BASE_URL } from "@plane/constants";
import type { IState } from "@plane/types";
import { APIService } from "@/services/api.service";
// helpers
// types
export class ProjectStateService extends APIService {
constructor() {
super(API_BASE_URL);
}
async createState(workspaceSlug: string, projectId: string, data: any): Promise<IState> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async markDefault(workspaceSlug: string, projectId: string, stateId: string): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/mark-default/`, {})
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getStates(workspaceSlug: string, projectId: string): Promise<IState[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getState(workspaceSlug: string, projectId: string, stateId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateState(workspaceSlug: string, projectId: string, stateId: string, data: IState): Promise<any> {
return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async patchState(workspaceSlug: string, projectId: string, stateId: string, data: Partial<IState>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteState(workspaceSlug: string, projectId: string, stateId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getWorkspaceStates(workspaceSlug: string): Promise<IState[]> {
return this.get(`/api/workspaces/${workspaceSlug}/states/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,186 @@
import { API_BASE_URL } from "@plane/constants";
import type {
GithubRepositoriesResponse,
ISearchIssueResponse,
TProjectAnalyticsCount,
TProjectAnalyticsCountParams,
TProjectIssuesSearchParams,
} from "@plane/types";
// helpers
// plane web types
import type { TProject, TPartialProject } from "@/plane-web/types";
// services
import { APIService } from "@/services/api.service";
export class ProjectService extends APIService {
constructor() {
super(API_BASE_URL);
}
async createProject(workspaceSlug: string, data: Partial<TProject>): Promise<TProject> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async checkProjectIdentifierAvailability(workspaceSlug: string, data: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/project-identifiers`, {
params: {
name: data,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProjectsLite(workspaceSlug: string): Promise<TPartialProject[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProjects(workspaceSlug: string): Promise<TProject[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/details/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProject(workspaceSlug: string, projectId: string): Promise<TProject> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProjectAnalyticsCount(
workspaceSlug: string,
params?: TProjectAnalyticsCountParams
): Promise<TProjectAnalyticsCount[]> {
return this.get(`/api/workspaces/${workspaceSlug}/project-stats/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateProject(workspaceSlug: string, projectId: string, data: Partial<TProject>): Promise<TProject> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteProject(workspaceSlug: string, projectId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async setProjectView(
workspaceSlug: string,
projectId: string,
data: {
sort_order?: number;
}
): Promise<any> {
await this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getGithubRepositories(url: string): Promise<GithubRepositoriesResponse> {
return this.request({
method: "get",
url,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async syncGithubRepository(
workspaceSlug: string,
projectId: string,
workspaceIntegrationId: string,
data: {
name: string;
owner: string;
repository_id: string;
url: string;
}
): Promise<any> {
return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${workspaceIntegrationId}/github-repository-sync/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProjectGithubRepository(workspaceSlug: string, projectId: string, integrationId: string): Promise<any> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/github-repository-sync/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserProjectFavorites(workspaceSlug: string): Promise<any[]> {
return this.get(`/api/workspaces/${workspaceSlug}/user-favorite-projects/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addProjectToFavorites(workspaceSlug: string, project: string): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/user-favorite-projects/`, { project })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeProjectFromFavorites(workspaceSlug: string, projectId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/user-favorite-projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async projectIssuesSearch(
workspaceSlug: string,
projectId: string,
params: TProjectIssuesSearchParams
): Promise<ISearchIssueResponse[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/search-issues/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,62 @@
// helpers
import { STICKIES_PER_PAGE, API_BASE_URL } from "@plane/constants";
import type { TSticky } from "@plane/types";
// services
import { APIService } from "@/services/api.service";
export class StickyService extends APIService {
constructor() {
super(API_BASE_URL);
}
async createSticky(workspaceSlug: string, payload: Partial<TSticky>) {
return this.post(`/api/workspaces/${workspaceSlug}/stickies/`, payload)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getStickies(
workspaceSlug: string,
cursor: string,
query?: string,
per_page?: number
): Promise<{ results: TSticky[]; total_pages: number }> {
return this.get(`/api/workspaces/${workspaceSlug}/stickies/`, {
params: {
cursor,
per_page: per_page || STICKIES_PER_PAGE,
query,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async getSticky(workspaceSlug: string, id: string) {
return this.get(`/api/workspaces/${workspaceSlug}/stickies/${id}`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async updateSticky(workspaceSlug: string, id: string, data: Partial<TSticky>) {
return await this.patch(`/api/workspaces/${workspaceSlug}/stickies/${id}/`, data)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async deleteSticky(workspaceSlug: string, id: string) {
return await this.delete(`/api/workspaces/${workspaceSlug}/stickies/${id}`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
}

View File

@@ -0,0 +1,23 @@
import { API_BASE_URL } from "@plane/constants";
import type { TTimezones } from "@plane/types";
// helpers
// api services
import { APIService } from "@/services/api.service";
export class TimezoneService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetch(): Promise<TTimezones> {
return this.get(`/api/timezones/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
const timezoneService = new TimezoneService();
export default timezoneService;

View File

@@ -0,0 +1,265 @@
// services
import { API_BASE_URL } from "@plane/constants";
import type {
TIssue,
IUser,
IUserActivityResponse,
IInstanceAdminStatus,
IUserProfileData,
IUserProfileProjectSegregation,
IUserSettings,
IUserEmailNotificationSettings,
TIssuesResponse,
TUserProfile,
} from "@plane/types";
import { APIService } from "@/services/api.service";
// types
// helpers
export class UserService extends APIService {
constructor() {
super(API_BASE_URL);
}
currentUserConfig() {
return {
url: `${this.baseURL}/api/users/me/`,
};
}
async userIssues(
workspaceSlug: string,
params: any
): Promise<
| {
[key: string]: TIssue[];
}
| TIssue[]
> {
return this.get(`/api/workspaces/${workspaceSlug}/my-issues/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async currentUser(): Promise<IUser> {
// Using validateStatus: null to bypass interceptors for unauthorized errors.
return this.get("/api/users/me/", { validateStatus: null })
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getCurrentUserProfile(): Promise<TUserProfile> {
return this.get("/api/users/me/profile/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateCurrentUserProfile(data: any): Promise<any> {
return this.patch("/api/users/me/profile/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async getCurrentUserAccounts(): Promise<any> {
return this.get("/api/users/me/accounts/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async currentUserInstanceAdminStatus(): Promise<IInstanceAdminStatus> {
return this.get("/api/users/me/instance-admin/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async currentUserSettings(bustCache: boolean = false): Promise<IUserSettings> {
const url = bustCache ? `/api/users/me/settings/?t=${Date.now()}` : "/api/users/me/settings/";
return this.get(url)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async currentUserEmailNotificationSettings(): Promise<IUserEmailNotificationSettings> {
return this.get("/api/users/me/notification-preferences/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateUser(data: Partial<IUser>): Promise<any> {
return this.patch("/api/users/me/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateUserOnBoard(): Promise<any> {
return this.patch("/api/users/me/onboard/", {
is_onboarded: true,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateUserTourCompleted(): Promise<any> {
return this.patch("/api/users/me/tour-completed/", {
is_tour_completed: true,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateCurrentUserEmailNotificationSettings(data: Partial<IUserEmailNotificationSettings>): Promise<any> {
return this.patch("/api/users/me/notification-preferences/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserActivity(params: { per_page: number; cursor?: string }): Promise<IUserActivityResponse> {
return this.get("/api/users/me/activities/", { params })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async changePassword(token: string, data: { old_password?: string; new_password: string }): Promise<any> {
return this.post(`/auth/change-password/`, data, {
headers: {
"X-CSRFTOKEN": token,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserProfileData(workspaceSlug: string, userId: string): Promise<IUserProfileData> {
return this.get(`/api/workspaces/${workspaceSlug}/user-stats/${userId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserProfileProjectsSegregation(
workspaceSlug: string,
userId: string
): Promise<IUserProfileProjectSegregation> {
return this.get(`/api/workspaces/${workspaceSlug}/user-profile/${userId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserProfileActivity(
workspaceSlug: string,
userId: string,
params: {
per_page: number;
cursor?: string;
}
): Promise<IUserActivityResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/user-activity/${userId}/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async downloadProfileActivity(
workspaceSlug: string,
userId: string,
data: {
date: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/user-activity/${userId}/export/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getUserProfileIssues(
workspaceSlug: string,
userId: string,
params: any,
config = {}
): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/user-issues/${userId}/`,
{
params,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deactivateAccount() {
return this.delete(`/api/users/me/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async leaveWorkspace(workspaceSlug: string) {
return this.post(`/api/workspaces/${workspaceSlug}/members/leave/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async joinProject(workspaceSlug: string, project_ids: string[]): Promise<any> {
return this.post(`/api/users/me/workspaces/${workspaceSlug}/projects/invitations/`, { project_ids })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async leaveProject(workspaceSlug: string, projectId: string) {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/leave/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
const userService = new UserService();
export default userService;

View File

@@ -0,0 +1,81 @@
import { API_BASE_URL } from "@plane/constants";
import type { IProjectView } from "@plane/types";
import { APIService } from "@/services/api.service";
// types
// helpers
export class ViewService extends APIService {
constructor() {
super(API_BASE_URL);
}
async createView(workspaceSlug: string, projectId: string, data: Partial<IProjectView>): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async patchView(workspaceSlug: string, projectId: string, viewId: string, data: Partial<IProjectView>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteView(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViews(workspaceSlug: string, projectId: string): Promise<IProjectView[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViewDetails(workspaceSlug: string, projectId: string, viewId: string): Promise<IProjectView> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViewIssues(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/issues/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addViewToFavorites(
workspaceSlug: string,
projectId: string,
data: {
view: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeViewFromFavorites(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,60 @@
// api services
import { API_BASE_URL } from "@plane/constants";
import type { IWebhook } from "@plane/types";
import { APIService } from "@/services/api.service";
// helpers
// types
export class WebhookService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetchWebhooksList(workspaceSlug: string): Promise<IWebhook[]> {
return this.get(`/api/workspaces/${workspaceSlug}/webhooks/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchWebhookDetails(workspaceSlug: string, webhookId: string): Promise<IWebhook> {
return this.get(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createWebhook(workspaceSlug: string, data = {}): Promise<IWebhook> {
return this.post(`/api/workspaces/${workspaceSlug}/webhooks/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateWebhook(workspaceSlug: string, webhookId: string, data = {}): Promise<IWebhook> {
return this.patch(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWebhook(workspaceSlug: string, webhookId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async regenerateSecretKey(workspaceSlug: string, webhookId: string): Promise<IWebhook> {
return this.post(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/regenerate/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,118 @@
/* eslint-disable no-useless-catch */
import { API_BASE_URL } from "@plane/constants";
import type {
TNotificationPaginatedInfo,
TNotificationPaginatedInfoQueryParams,
TNotification,
TUnreadNotificationsCount,
} from "@plane/types";
// helpers
// services
import { APIService } from "@/services/api.service";
export class WorkspaceNotificationService extends APIService {
constructor() {
super(API_BASE_URL);
}
async fetchUnreadNotificationsCount(workspaceSlug: string): Promise<TUnreadNotificationsCount | undefined> {
try {
const { data } = await this.get(`/api/workspaces/${workspaceSlug}/users/notifications/unread/`);
return data || undefined;
} catch (error) {
throw error;
}
}
async fetchNotifications(
workspaceSlug: string,
params: TNotificationPaginatedInfoQueryParams
): Promise<TNotificationPaginatedInfo | undefined> {
try {
const { data } = await this.get(`/api/workspaces/${workspaceSlug}/users/notifications`, {
params,
});
return data || undefined;
} catch (error) {
throw error;
}
}
async updateNotificationById(
workspaceSlug: string,
notificationId: string,
payload: Partial<TNotification>
): Promise<TNotification | undefined> {
try {
const { data } = await this.patch(
`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`,
payload
);
return data || undefined;
} catch (error) {
throw error;
}
}
async markNotificationAsRead(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
try {
const { data } = await this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`);
return data || undefined;
} catch (error) {
throw error;
}
}
async markNotificationAsUnread(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
try {
const { data } = await this.delete(
`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`
);
return data || undefined;
} catch (error) {
throw error;
}
}
async markNotificationAsArchived(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
try {
const { data } = await this.post(
`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`
);
return data || undefined;
} catch (error) {
throw error;
}
}
async markNotificationAsUnArchived(
workspaceSlug: string,
notificationId: string
): Promise<TNotification | undefined> {
try {
const { data } = await this.delete(
`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`
);
return data || undefined;
} catch (error) {
throw error;
}
}
async markAllNotificationsAsRead(
workspaceSlug: string,
payload: TNotificationPaginatedInfoQueryParams
): Promise<TNotification | undefined> {
try {
const { data } = await this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, payload);
return data || undefined;
} catch (error) {
throw error;
}
}
}
const workspaceNotificationService = new WorkspaceNotificationService();
export default workspaceNotificationService;

View File

@@ -0,0 +1,389 @@
import { API_BASE_URL } from "@plane/constants";
import type {
IWorkspace,
IWorkspaceMemberMe,
IWorkspaceMember,
IWorkspaceMemberInvitation,
ILastActiveWorkspaceDetails,
IWorkspaceSearchResults,
IProductUpdateResponse,
IWorkspaceBulkInviteFormData,
IWorkspaceViewProps,
IUserProjectsRole,
IWorkspaceView,
TIssuesResponse,
TLink,
TSearchResponse,
TSearchEntityRequestPayload,
TWidgetEntityData,
TActivityEntityData,
IWorkspaceSidebarNavigationItem,
IWorkspaceSidebarNavigation,
} from "@plane/types";
// services
import { APIService } from "@/services/api.service";
export class WorkspaceService extends APIService {
constructor() {
super(API_BASE_URL);
}
async userWorkspaces(): Promise<IWorkspace[]> {
return this.get("/api/users/me/workspaces/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWorkspace(workspaceSlug: string): Promise<IWorkspace> {
return this.get(`/api/workspaces/${workspaceSlug}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async createWorkspace(data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.post("/api/workspaces/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateWorkspace(workspaceSlug: string, data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.patch(`/api/workspaces/${workspaceSlug}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWorkspace(workspaceSlug: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async inviteWorkspace(workspaceSlug: string, data: IWorkspaceBulkInviteFormData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/invitations/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async joinWorkspace(workspaceSlug: string, invitationId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/join/`, data, {
headers: {},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async joinWorkspaces(data: any): Promise<any> {
return this.post("/api/users/me/workspaces/invitations/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getLastActiveWorkspaceAndProjects(): Promise<ILastActiveWorkspaceDetails> {
return this.get("/api/users/last-visited-workspace/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async userWorkspaceInvitations(): Promise<IWorkspaceMemberInvitation[]> {
return this.get("/api/users/me/workspaces/invitations/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async workspaceMemberMe(workspaceSlug: string): Promise<IWorkspaceMemberMe> {
return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/me/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateWorkspaceView(workspaceSlug: string, data: { view_props: IWorkspaceViewProps }): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/workspace-views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async fetchWorkspaceMembers(workspaceSlug: string): Promise<IWorkspaceMember[]> {
return this.get(`/api/workspaces/${workspaceSlug}/members/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateWorkspaceMember(
workspaceSlug: string,
memberId: string,
data: Partial<IWorkspaceMember>
): Promise<IWorkspaceMember> {
return this.patch(`/api/workspaces/${workspaceSlug}/members/${memberId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWorkspaceMember(workspaceSlug: string, memberId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/members/${memberId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async workspaceInvitations(workspaceSlug: string): Promise<IWorkspaceMemberInvitation[]> {
return this.get(`/api/workspaces/${workspaceSlug}/invitations/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWorkspaceInvitation(workspaceSlug: string, invitationId: string): Promise<IWorkspaceMemberInvitation> {
return this.get(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/join/`, { headers: {} })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateWorkspaceInvitation(
workspaceSlug: string,
invitationId: string,
data: Partial<IWorkspaceMember>
): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteWorkspaceInvitations(workspaceSlug: string, invitationId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async workspaceSlugCheck(slug: string): Promise<any> {
return this.get(`/api/workspace-slug-check/?slug=${slug}`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async searchWorkspace(
workspaceSlug: string,
params: {
project_id?: string;
search: string;
workspace_search: boolean;
}
): Promise<IWorkspaceSearchResults> {
return this.get(`/api/workspaces/${workspaceSlug}/search/`, {
params,
})
.then((res) => res?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getProductUpdates(): Promise<IProductUpdateResponse[]> {
return this.get("/api/release-notes/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async createView(workspaceSlug: string, data: Partial<IWorkspaceView>): Promise<IWorkspaceView> {
return this.post(`/api/workspaces/${workspaceSlug}/views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async updateView(workspaceSlug: string, viewId: string, data: Partial<IWorkspaceView>): Promise<IWorkspaceView> {
return this.patch(`/api/workspaces/${workspaceSlug}/views/${viewId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async deleteView(workspaceSlug: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getAllViews(workspaceSlug: string): Promise<IWorkspaceView[]> {
return this.get(`/api/workspaces/${workspaceSlug}/views/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViewDetails(workspaceSlug: string, viewId: string): Promise<IWorkspaceView> {
return this.get(`/api/workspaces/${workspaceSlug}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViewIssues(workspaceSlug: string, params: any, config = {}): Promise<TIssuesResponse> {
const path = params.expand?.includes("issue_relation")
? `/api/workspaces/${workspaceSlug}/issues-detail/`
: `/api/workspaces/${workspaceSlug}/issues/`;
return this.get(
path,
{
params,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWorkspaceUserProjectsRole(workspaceSlug: string): Promise<IUserProjectsRole> {
return this.get(`/api/users/me/workspaces/${workspaceSlug}/project-roles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
// quicklinks
async fetchWorkspaceLinks(workspaceSlug: string): Promise<TLink[]> {
return this.get(`/api/workspaces/${workspaceSlug}/quick-links/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async createWorkspaceLink(workspaceSlug: string, data: Partial<TLink>): Promise<TLink> {
return this.post(`/api/workspaces/${workspaceSlug}/quick-links/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateWorkspaceLink(workspaceSlug: string, linkId: string, data: Partial<TLink>): Promise<TLink> {
return this.patch(`/api/workspaces/${workspaceSlug}/quick-links/${linkId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async deleteWorkspaceLink(workspaceSlug: string, linkId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/quick-links/${linkId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async searchEntity(workspaceSlug: string, params: TSearchEntityRequestPayload): Promise<TSearchResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/entity-search/`, {
params: {
...params,
query_type: params.query_type.join(","),
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
// recents
async fetchWorkspaceRecents(workspaceSlug: string, entity_name?: string): Promise<TActivityEntityData[]> {
return this.get(`/api/workspaces/${workspaceSlug}/recent-visits/`, {
params: {
entity_name,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
// widgets
async fetchWorkspaceWidgets(workspaceSlug: string): Promise<TWidgetEntityData[]> {
return this.get(`/api/workspaces/${workspaceSlug}/home-preferences/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateWorkspaceWidget(
workspaceSlug: string,
widgetKey: string,
data: Partial<TWidgetEntityData>
): Promise<TWidgetEntityData> {
return this.patch(`/api/workspaces/${workspaceSlug}/home-preferences/${widgetKey}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async fetchSidebarNavigationPreferences(workspaceSlug: string): Promise<IWorkspaceSidebarNavigation> {
return this.get(`/api/workspaces/${workspaceSlug}/sidebar-preferences/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async updateSidebarPreference(
workspaceSlug: string,
key: string,
data: Partial<IWorkspaceSidebarNavigationItem>
): Promise<IWorkspaceSidebarNavigationItem> {
return this.patch(`/api/workspaces/${workspaceSlug}/sidebar-preferences/${key}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}