From e3036797146515789b5743acd5375f7c217a571a Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 6 Feb 2024 00:12:52 +0530 Subject: [PATCH] fix: service layer fixes --- packages/services/ai/ai.service.ts | 24 ++ .../services/analytics/analytics.service.ts | 63 +++ packages/services/api.service.ts | 94 +++++ packages/services/client.ts | 15 + packages/services/cycle/cycle.service.ts | 124 ++++++ .../services/inbox/inbox-issue.service.ts | 112 +++++ .../services/inbox/inbox-legacy.service.ts | 122 ++++++ packages/services/inbox/inbox.service.ts | 35 ++ packages/services/inbox/index.ts | 2 + .../services/instance/api_token.service.ts | 49 +++ packages/services/instance/config.service.ts | 24 ++ packages/services/instance/file.service.ts | 187 +++++++++ .../services/instance/instance.service.ts | 53 +++ packages/services/instance/webhook.service.ts | 60 +++ .../services/integrations/github.service.ts | 39 ++ packages/services/integrations/index.ts | 3 + .../integrations/integration.service.ts | 67 +++ .../services/integrations/jira.service.ts | 28 ++ packages/services/issue/index.ts | 9 + packages/services/issue/issue.service.ts | 238 +++++++++++ .../services/issue/issue_activity.service.ts | 33 ++ .../services/issue/issue_archive.service.ts | 43 ++ .../issue/issue_attachment.service.ts | 56 +++ .../services/issue/issue_comment.service.ts | 73 ++++ .../services/issue/issue_draft.service.tsx | 52 +++ .../services/issue/issue_filter.service.ts | 103 +++++ .../services/issue/issue_label.service.ts | 51 +++ .../services/issue/issue_reaction.service.ts | 82 ++++ .../services/issue/issue_relation.service.ts | 45 ++ packages/services/module/module.service.ts | 213 ++++++++++ packages/services/page/page.service.ts | 203 +++++++++ packages/services/project/index.ts | 6 + .../project/project-estimate.service.ts | 72 ++++ .../project/project-export.service.ts | 23 + .../project/project-member.service.ts | 68 +++ .../project/project-publish.service.ts | 61 +++ .../services/project/project-state.service.ts | 76 ++++ packages/services/project/project.service.ts | 168 ++++++++ packages/services/user/auth.service.ts | 148 +++++++ .../services/user/notification.service.ts | 144 +++++++ packages/services/user/user.service.ts | 212 ++++++++++ packages/services/view/view.service.ts | 81 ++++ .../workspace/app_installation.service.ts | 63 +++ .../services/workspace/dashboard.service.ts | 53 +++ .../services/workspace/workspace.service.ts | 397 ++++++++++++++++++ packages/types/src/ai.d.ts | 4 +- 46 files changed, 3876 insertions(+), 2 deletions(-) create mode 100644 packages/services/ai/ai.service.ts create mode 100644 packages/services/analytics/analytics.service.ts create mode 100644 packages/services/api.service.ts create mode 100644 packages/services/client.ts create mode 100644 packages/services/cycle/cycle.service.ts create mode 100644 packages/services/inbox/inbox-issue.service.ts create mode 100644 packages/services/inbox/inbox-legacy.service.ts create mode 100644 packages/services/inbox/inbox.service.ts create mode 100644 packages/services/inbox/index.ts create mode 100644 packages/services/instance/api_token.service.ts create mode 100644 packages/services/instance/config.service.ts create mode 100644 packages/services/instance/file.service.ts create mode 100644 packages/services/instance/instance.service.ts create mode 100644 packages/services/instance/webhook.service.ts create mode 100644 packages/services/integrations/github.service.ts create mode 100644 packages/services/integrations/index.ts create mode 100644 packages/services/integrations/integration.service.ts create mode 100644 packages/services/integrations/jira.service.ts create mode 100644 packages/services/issue/index.ts create mode 100644 packages/services/issue/issue.service.ts create mode 100644 packages/services/issue/issue_activity.service.ts create mode 100644 packages/services/issue/issue_archive.service.ts create mode 100644 packages/services/issue/issue_attachment.service.ts create mode 100644 packages/services/issue/issue_comment.service.ts create mode 100644 packages/services/issue/issue_draft.service.tsx create mode 100644 packages/services/issue/issue_filter.service.ts create mode 100644 packages/services/issue/issue_label.service.ts create mode 100644 packages/services/issue/issue_reaction.service.ts create mode 100644 packages/services/issue/issue_relation.service.ts create mode 100644 packages/services/module/module.service.ts create mode 100644 packages/services/page/page.service.ts create mode 100644 packages/services/project/index.ts create mode 100644 packages/services/project/project-estimate.service.ts create mode 100644 packages/services/project/project-export.service.ts create mode 100644 packages/services/project/project-member.service.ts create mode 100644 packages/services/project/project-publish.service.ts create mode 100644 packages/services/project/project-state.service.ts create mode 100644 packages/services/project/project.service.ts create mode 100644 packages/services/user/auth.service.ts create mode 100644 packages/services/user/notification.service.ts create mode 100644 packages/services/user/user.service.ts create mode 100644 packages/services/view/view.service.ts create mode 100644 packages/services/workspace/app_installation.service.ts create mode 100644 packages/services/workspace/dashboard.service.ts create mode 100644 packages/services/workspace/workspace.service.ts diff --git a/packages/services/ai/ai.service.ts b/packages/services/ai/ai.service.ts new file mode 100644 index 000000000..9c3489689 --- /dev/null +++ b/packages/services/ai/ai.service.ts @@ -0,0 +1,24 @@ +import { APIService } from "../api.service"; +// types +import { GptApiResponse } from "@plane/types"; + +export class AIService extends APIService { + constructor(BASE_URL: string) { + super(BASE_URL); + } + + async createGptTask( + workspaceSlug: string, + projectId: string, + data: { prompt: string; task: string } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } +} diff --git a/packages/services/analytics/analytics.service.ts b/packages/services/analytics/analytics.service.ts new file mode 100644 index 000000000..5e3aac44b --- /dev/null +++ b/packages/services/analytics/analytics.service.ts @@ -0,0 +1,63 @@ +// services +import { APIService } from "services/api.service"; +// types +import { + IAnalyticsParams, + IAnalyticsResponse, + IDefaultAnalyticsResponse, + IExportAnalyticsFormData, + ISaveAnalyticsFormData, +} from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class AnalyticsService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getAnalytics(workspaceSlug: string, params: IAnalyticsParams): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/analytics/`, { + params: { + ...params, + project: params?.project ? params.project.toString() : null, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getDefaultAnalytics( + workspaceSlug: string, + params?: Partial + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/default-analytics/`, { + params: { + ...params, + project: params?.project ? params.project.toString() : null, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async saveAnalytics(workspaceSlug: string, data: ISaveAnalyticsFormData): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/analytic-view/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async exportAnalytics(workspaceSlug: string, data: IExportAnalyticsFormData): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/export-analytics/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/api.service.ts b/packages/services/api.service.ts new file mode 100644 index 000000000..23be79929 --- /dev/null +++ b/packages/services/api.service.ts @@ -0,0 +1,94 @@ +import axios from "axios"; +import Cookies from "js-cookie"; + +export abstract class APIService { + protected baseURL: string; + protected headers: any = {}; + + constructor(baseURL: string) { + this.baseURL = baseURL; + } + + setRefreshToken(token: string) { + Cookies.set("refreshToken", token, { expires: 30 }); + } + + getRefreshToken() { + return Cookies.get("refreshToken"); + } + + purgeRefreshToken() { + Cookies.remove("refreshToken", { path: "/" }); + } + + setAccessToken(token: string) { + Cookies.set("accessToken", token, { expires: 30 }); + } + + getAccessToken() { + return Cookies.get("accessToken"); + } + + purgeAccessToken() { + Cookies.remove("accessToken", { path: "/" }); + } + + getHeaders() { + return { + Authorization: `Bearer ${this.getAccessToken()}`, + }; + } + + get(url: string, config = {}): Promise { + return axios({ + method: "get", + url: this.baseURL + url, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + post(url: string, data = {}, config = {}): Promise { + return axios({ + method: "post", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + put(url: string, data = {}, config = {}): Promise { + return axios({ + method: "put", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + patch(url: string, data = {}, config = {}): Promise { + return axios({ + method: "patch", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + delete(url: string, data?: any, config = {}): Promise { + return axios({ + method: "delete", + url: this.baseURL + url, + data: data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + request(config = {}) { + return axios(config); + } +} diff --git a/packages/services/client.ts b/packages/services/client.ts new file mode 100644 index 000000000..fd237bd35 --- /dev/null +++ b/packages/services/client.ts @@ -0,0 +1,15 @@ +import { AIService } from "./ai/ai.service"; +import { WorkspaceService } from "./workspace/workspace.service"; + +export class Client { + ai; + workspace; + + constructor(BASE_URL: string | undefined) { + this.user = new UserService(BASE_URL || ""); + this.instance = new InstanceService(BASE_URL || ""); + + this.ai = new AIService(BASE_URL || ""); + this.workspace = new WorkspaceService(BASE_URL || ""); + } +} diff --git a/packages/services/cycle/cycle.service.ts b/packages/services/cycle/cycle.service.ts new file mode 100644 index 000000000..6b6d17231 --- /dev/null +++ b/packages/services/cycle/cycle.service.ts @@ -0,0 +1,124 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { CycleDateCheckData, ICycle, TIssue, TIssueMap } from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class CycleService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createCycle(workspaceSlug: string, projectId: string, data: any): Promise { + 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 { + 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 { + 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): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getCycleIssuesWithParams( + workspaceSlug: string, + projectId: string, + cycleId: string, + queries?: any + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchCycle(workspaceSlug: string, projectId: string, cycleId: string, data: Partial): Promise { + 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 { + 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 { + 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 { + 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 { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/${cycleId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/inbox/inbox-issue.service.ts b/packages/services/inbox/inbox-issue.service.ts new file mode 100644 index 000000000..6b2099059 --- /dev/null +++ b/packages/services/inbox/inbox-issue.service.ts @@ -0,0 +1,112 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import type { TInboxIssueFilterOptions, TInboxIssueExtendedDetail, TIssue, TInboxDetailedStatus } from "@plane/types"; + +export class InboxIssueService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async fetchInboxIssues( + workspaceSlug: string, + projectId: string, + inboxId: string, + params?: TInboxIssueFilterOptions | {} + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/?expand=issue_inbox`, + { + params, + } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async fetchInboxIssueById( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + data: { + source: string; + issue: Partial; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/?expand=issue_inbox`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: { issue: Partial } + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateInboxIssueStatus( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: TInboxDetailedStatus + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/inbox/inbox-legacy.service.ts b/packages/services/inbox/inbox-legacy.service.ts new file mode 100644 index 000000000..a36d356ce --- /dev/null +++ b/packages/services/inbox/inbox-legacy.service.ts @@ -0,0 +1,122 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import type { IInboxIssue, IInbox, TInboxStatus, IInboxQueryParams } from "@plane/types"; + +export class InboxService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getInboxes(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxById(workspaceSlug: string, projectId: string, inboxId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchInbox(workspaceSlug: string, projectId: string, inboxId: string, data: Partial): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxIssues( + workspaceSlug: string, + projectId: string, + inboxId: string, + params?: IInboxQueryParams + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxIssueById( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markInboxStatus( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: TInboxStatus + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: { issue: Partial } + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createInboxIssue(workspaceSlug: string, projectId: string, inboxId: string, data: any): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/inbox/inbox.service.ts b/packages/services/inbox/inbox.service.ts new file mode 100644 index 000000000..8ee6ee514 --- /dev/null +++ b/packages/services/inbox/inbox.service.ts @@ -0,0 +1,35 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import type { TInbox } from "@plane/types"; + +export class InboxService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async fetchInboxes(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async fetchInboxById(workspaceSlug: string, projectId: string, inboxId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateInbox(workspaceSlug: string, projectId: string, inboxId: string, data: Partial): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/inbox/index.ts b/packages/services/inbox/index.ts new file mode 100644 index 000000000..fe3f30fce --- /dev/null +++ b/packages/services/inbox/index.ts @@ -0,0 +1,2 @@ +export * from "./inbox.service"; +export * from "./inbox-issue.service"; diff --git a/packages/services/instance/api_token.service.ts b/packages/services/instance/api_token.service.ts new file mode 100644 index 000000000..16705d148 --- /dev/null +++ b/packages/services/instance/api_token.service.ts @@ -0,0 +1,49 @@ +import { APIService } from "../api.service"; +import { IApiToken } from "@plane/types"; + +export class APITokenService extends APIService { + constructor(BASE_URL) { + super(BASE_URL); + } + + async getApiTokens(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/api-tokens/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieveApiToken( + workspaceSlug: string, + tokenId: String + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/api-tokens/${tokenId}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createApiToken( + workspaceSlug: string, + data: Partial + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/api-tokens/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteApiToken( + workspaceSlug: string, + tokenId: String + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/api-tokens/${tokenId}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/instance/config.service.ts b/packages/services/instance/config.service.ts new file mode 100644 index 000000000..4b45e0cc4 --- /dev/null +++ b/packages/services/instance/config.service.ts @@ -0,0 +1,24 @@ +// services +import { APIService } from "services/api.service"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { IAppConfig } from "@plane/types"; + +export class AppConfigService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async envConfig(): Promise { + return this.get("/api/configs/", { + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/instance/file.service.ts b/packages/services/instance/file.service.ts new file mode 100644 index 000000000..d5e80dd53 --- /dev/null +++ b/packages/services/instance/file.service.ts @@ -0,0 +1,187 @@ +// services +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +import axios from "axios"; + +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 class FileService extends APIService { + private cancelSource: any; + + constructor() { + super(API_BASE_URL); + this.uploadFile = this.uploadFile.bind(this); + this.deleteImage = this.deleteImage.bind(this); + this.restoreImage = this.restoreImage.bind(this); + this.cancelUpload = this.cancelUpload.bind(this); + } + + async uploadFile(workspaceSlug: string, file: FormData): Promise { + this.cancelSource = axios.CancelToken.source(); + return this.post(`/api/workspaces/${workspaceSlug}/file-assets/`, file, { + headers: { + ...this.getHeaders(), + "Content-Type": "multipart/form-data", + }, + cancelToken: this.cancelSource.token, + }) + .then((response) => response?.data) + .catch((error) => { + if (axios.isCancel(error)) { + console.log(error.message); + } else { + console.log(error); + throw error?.response?.data; + } + }); + } + + cancelUpload() { + this.cancelSource.cancel("Upload cancelled"); + } + + getUploadFileFunction(workspaceSlug: string): (file: File) => Promise { + return async (file: File) => { + try { + const formData = new FormData(); + formData.append("asset", file); + formData.append("attributes", JSON.stringify({})); + + const data = await this.uploadFile(workspaceSlug, formData); + return data.asset; + } catch (e) { + console.error(e); + } + }; + } + + getDeleteImageFunction(workspaceId: string) { + return async (src: string) => { + try { + const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`; + const data = await this.deleteImage(assetUrlWithWorkspaceId); + return data; + } catch (e) { + console.error(e); + } + }; + } + + getRestoreImageFunction(workspaceId: string) { + return async (src: string) => { + try { + const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`; + const data = await this.restoreImage(assetUrlWithWorkspaceId); + return data; + } catch (e) { + console.error(e); + } + }; + } + + extractAssetIdFromUrl(src: string, workspaceId: string): string { + const indexWhereAssetIdStarts = src.indexOf(workspaceId) + workspaceId.length + 1; + if (indexWhereAssetIdStarts === -1) { + throw new Error("Workspace ID not found in source string"); + } + const assetUrl = src.substring(indexWhereAssetIdStarts); + return assetUrl; + } + + async deleteImage(assetUrlWithWorkspaceId: string): Promise { + return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`) + .then((response) => response?.status) + .catch((error) => { + throw error?.response?.data; + }); + } + + async restoreImage(assetUrlWithWorkspaceId: string): Promise { + return this.post(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/restore/`, { + headers: this.getHeaders(), + "Content-Type": "application/json", + }) + .then((response) => response?.status) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteFile(workspaceId: string, assetUrl: string): Promise { + const lastIndex = assetUrl.lastIndexOf("/"); + const assetId = assetUrl.substring(lastIndex + 1); + + return this.delete(`/api/workspaces/file-assets/${workspaceId}/${assetId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async uploadUserFile(file: FormData): Promise { + return this.post(`/api/users/file-assets/`, file, { + headers: { + ...this.getHeaders(), + "Content-Type": "multipart/form-data", + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteUserFile(assetUrl: string): Promise { + const lastIndex = assetUrl.lastIndexOf("/"); + const assetId = assetUrl.substring(lastIndex + 1); + + return this.delete(`/api/users/file-assets/${assetId}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUnsplashImages(query?: string): Promise { + return this.get(`/api/unsplash/`, { + params: { + query, + }, + }) + .then((res) => res?.data?.results ?? res?.data) + .catch((err) => { + throw err?.response?.data; + }); + } + + async getProjectCoverImages(): Promise { + return this.get(`/api/project-covers/`) + .then((res) => res?.data) + .catch((err) => { + throw err?.response?.data; + }); + } +} diff --git a/packages/services/instance/instance.service.ts b/packages/services/instance/instance.service.ts new file mode 100644 index 000000000..1bc5ecdbc --- /dev/null +++ b/packages/services/instance/instance.service.ts @@ -0,0 +1,53 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import type { IFormattedInstanceConfiguration, IInstance, IInstanceAdmin, IInstanceConfiguration } from "@plane/types"; + +export class InstanceService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getInstanceInfo(): Promise { + return this.get("/api/instances/", { headers: {} }) + .then((response) => response.data) + .catch((error) => { + throw error; + }); + } + + async getInstanceAdmins(): Promise { + return this.get("/api/instances/admins/") + .then((response) => response.data) + .catch((error) => { + throw error; + }); + } + + async updateInstanceInfo(data: Partial): Promise { + return this.patch("/api/instances/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInstanceConfigurations() { + return this.get("/api/instances/configurations/") + .then((response) => response.data) + .catch((error) => { + throw error; + }); + } + + async updateInstanceConfigurations( + data: Partial + ): Promise { + return this.patch("/api/instances/configurations/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/instance/webhook.service.ts b/packages/services/instance/webhook.service.ts new file mode 100644 index 000000000..abfe7c46d --- /dev/null +++ b/packages/services/instance/webhook.service.ts @@ -0,0 +1,60 @@ +// api services +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { IWebhook } from "@plane/types"; + +export class WebhookService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async fetchWebhooksList(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/webhooks/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async fetchWebhookDetails(workspaceSlug: string, webhookId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createWebhook(workspaceSlug: string, data: {}): Promise { + 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 { + 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 { + 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 { + return this.post(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/regenerate/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/integrations/github.service.ts b/packages/services/integrations/github.service.ts new file mode 100644 index 000000000..6a0519565 --- /dev/null +++ b/packages/services/integrations/github.service.ts @@ -0,0 +1,39 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { IGithubRepoInfo, IGithubServiceImportFormData } from "@plane/types"; + +const integrationServiceType: string = "github"; + +export class GithubIntegrationService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async listAllRepositories(workspaceSlug: string, integrationSlug: string): Promise { + 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 { + 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 { + return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/integrations/index.ts b/packages/services/integrations/index.ts new file mode 100644 index 000000000..cf9a070ee --- /dev/null +++ b/packages/services/integrations/index.ts @@ -0,0 +1,3 @@ +export * from "./github.service"; +export * from "./integration.service"; +export * from "./jira.service"; diff --git a/packages/services/integrations/integration.service.ts b/packages/services/integrations/integration.service.ts new file mode 100644 index 000000000..460dc17d9 --- /dev/null +++ b/packages/services/integrations/integration.service.ts @@ -0,0 +1,67 @@ +import { APIService } from "services/api.service"; +// types +import { IAppIntegration, IImporterService, IWorkspaceIntegration, IExportServiceResponse } from "@plane/types"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; + +export class IntegrationService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getAppIntegrationsList(): Promise { + return this.get(`/api/integrations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceIntegrationsList(workspaceSlug: string): Promise { + 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 { + 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 { + 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 { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/integrations/jira.service.ts b/packages/services/integrations/jira.service.ts new file mode 100644 index 000000000..5641bb28b --- /dev/null +++ b/packages/services/integrations/jira.service.ts @@ -0,0 +1,28 @@ +import { APIService } from "services/api.service"; +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { IJiraMetadata, IJiraResponse, IJiraImporterForm } from "@plane/types"; + +export class JiraImporterService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getJiraProjectInfo(workspaceSlug: string, params: IJiraMetadata): Promise { + 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 { + return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/index.ts b/packages/services/issue/index.ts new file mode 100644 index 000000000..4d8a4623b --- /dev/null +++ b/packages/services/issue/index.ts @@ -0,0 +1,9 @@ +export * from "./issue_archive.service"; +export * from "./issue.service"; +export * from "./issue_draft.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"; diff --git a/packages/services/issue/issue.service.ts b/packages/services/issue/issue.service.ts new file mode 100644 index 000000000..0b65b0482 --- /dev/null +++ b/packages/services/issue/issue.service.ts @@ -0,0 +1,238 @@ +// services +import { APIService } from "services/api.service"; +// type +import type { + TIssue, + IIssueDisplayProperties, + ILinkDetails, + TIssueLink, + TIssueSubIssues, + TIssueActivity, +} from "@plane/types"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; + +export class IssueService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createIssue(workspaceSlug: string, projectId: string, data: any): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssues(workspaceSlug: string, projectId: string, queries?: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssuesWithParams( + workspaceSlug: string, + projectId: string, + queries?: any + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieve(workspaceSlug: string, projectId: string, issueId: string, queries?: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueActivities(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${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}/issues/${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}/issues/${issueId}/issue-relation/${relationId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getIssueDisplayProperties(workspaceSlug: string, projectId: string): Promise { + 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 { + 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): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async bulkDeleteIssues(workspaceSlug: string, projectId: string, data: any): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async subIssues(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addSubIssues( + workspaceSlug: string, + projectId: string, + issueId: string, + data: { sub_issue_ids: string[] } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async fetchIssueLinks(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async createIssueLink( + workspaceSlug: string, + projectId: string, + issueId: string, + data: Partial + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateIssueLink( + workspaceSlug: string, + projectId: string, + issueId: string, + linkId: string, + data: Partial + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async deleteIssueLink(workspaceSlug: string, projectId: string, issueId: string, linkId: string): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_activity.service.ts b/packages/services/issue/issue_activity.service.ts new file mode 100644 index 000000000..87c7a8f54 --- /dev/null +++ b/packages/services/issue/issue_activity.service.ts @@ -0,0 +1,33 @@ +import { APIService } from "services/api.service"; +// types +import { TIssueActivity } from "@plane/types"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; + +export class IssueActivityService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getIssueActivities( + workspaceSlug: string, + projectId: string, + issueId: string, + params: + | { + created_at__gt: string; + } + | {} = {} + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/history/`, { + params: { + activity_type: "issue-property", + ...params, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_archive.service.ts b/packages/services/issue/issue_archive.service.ts new file mode 100644 index 000000000..3337f23ce --- /dev/null +++ b/packages/services/issue/issue_archive.service.ts @@ -0,0 +1,43 @@ +import { APIService } from "services/api.service"; +// type +import { API_BASE_URL } from "helpers/common.helper"; + +export class IssueArchiveService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getArchivedIssues(workspaceSlug: string, projectId: string, queries?: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/`, { + params: { ...queries }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async unarchiveIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/unarchive/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieveArchivedIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteArchivedIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issuesId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_attachment.service.ts b/packages/services/issue/issue_attachment.service.ts new file mode 100644 index 000000000..16253218a --- /dev/null +++ b/packages/services/issue/issue_attachment.service.ts @@ -0,0 +1,56 @@ +import { APIService } from "services/api.service"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { TIssueAttachment } from "@plane/types"; + +export class IssueAttachmentService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async uploadIssueAttachment( + workspaceSlug: string, + projectId: string, + issueId: string, + file: FormData + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/`, + file, + { + headers: { + ...this.getHeaders(), + "Content-Type": "multipart/form-data", + }, + } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueAttachment(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueAttachment( + workspaceSlug: string, + projectId: string, + issueId: string, + assetId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/${assetId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_comment.service.ts b/packages/services/issue/issue_comment.service.ts new file mode 100644 index 000000000..8001d644a --- /dev/null +++ b/packages/services/issue/issue_comment.service.ts @@ -0,0 +1,73 @@ +import { APIService } from "services/api.service"; +// types +import { TIssueComment } from "@plane/types"; +// helper +import { API_BASE_URL } from "helpers/common.helper"; + +export class IssueCommentService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getIssueComments( + workspaceSlug: string, + projectId: string, + issueId: string, + params: + | { + created_at__gt: string; + } + | {} = {} + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/history/`, { + params: { + activity_type: "issue-comment", + ...params, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueComment( + workspaceSlug: string, + projectId: string, + issueId: string, + data: Partial + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${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 + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${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 { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/${commentId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_draft.service.tsx b/packages/services/issue/issue_draft.service.tsx new file mode 100644 index 000000000..b4eb995b0 --- /dev/null +++ b/packages/services/issue/issue_draft.service.tsx @@ -0,0 +1,52 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +import { TIssue } from "@plane/types"; + +export class IssueDraftService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getDraftIssues(workspaceSlug: string, projectId: string, query?: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, { + params: { ...query }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createDraftIssue(workspaceSlug: string, projectId: string, data: any): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateDraftIssue(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async deleteDraftIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getDraftIssueById(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } +} diff --git a/packages/services/issue/issue_filter.service.ts b/packages/services/issue/issue_filter.service.ts new file mode 100644 index 000000000..5103a4bc8 --- /dev/null +++ b/packages/services/issue/issue_filter.service.ts @@ -0,0 +1,103 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { IIssueFiltersResponse } from "@plane/types"; +import { API_BASE_URL } from "helpers/common.helper"; + +export class IssueFiltersService extends APIService { + constructor() { + super(API_BASE_URL); + } + + // // workspace issue filters + // async fetchWorkspaceFilters(workspaceSlug: string): Promise { + // return this.get(`/api/workspaces/${workspaceSlug}/user-properties/`) + // .then((response) => response?.data) + // .catch((error) => { + // throw error?.response?.data; + // }); + // } + // async patchWorkspaceFilters( + // workspaceSlug: string, + // data: Partial + // ): Promise { + // 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 { + 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 + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/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 { + 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 + ): Promise { + 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 { + 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 + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/user-properties/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_label.service.ts b/packages/services/issue/issue_label.service.ts new file mode 100644 index 000000000..9d03caa52 --- /dev/null +++ b/packages/services/issue/issue_label.service.ts @@ -0,0 +1,51 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import { IIssueLabel } from "@plane/types"; + +export class IssueLabelService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getWorkspaceIssueLabels(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/labels/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProjectLabels(workspaceSlug: string, projectId: string): Promise { + 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 { + 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 { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_reaction.service.ts b/packages/services/issue/issue_reaction.service.ts new file mode 100644 index 000000000..9f91e48be --- /dev/null +++ b/packages/services/issue/issue_reaction.service.ts @@ -0,0 +1,82 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import type { TIssueCommentReaction, TIssueReaction } from "@plane/types"; + +export class IssueReactionService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createIssueReaction( + workspaceSlug: string, + projectId: string, + issueId: string, + data: Partial + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async listIssueReactions(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueReaction(workspaceSlug: string, projectId: string, issueId: string, reaction: string): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/${reaction}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueCommentReaction( + workspaceSlug: string, + projectId: string, + commentId: string, + data: Partial + ): Promise { + 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 { + 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 { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/${reaction}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/issue/issue_relation.service.ts b/packages/services/issue/issue_relation.service.ts new file mode 100644 index 000000000..ba9a64068 --- /dev/null +++ b/packages/services/issue/issue_relation.service.ts @@ -0,0 +1,45 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import type { TIssueRelation, TIssue, TIssueRelationTypes } from "@plane/types"; + +export class IssueRelationService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async listIssueRelations(workspaceSlug: string, projectId: string, issueId: string): Promise { + 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 { + 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 { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/remove-relation/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/module/module.service.ts b/packages/services/module/module.service.ts new file mode 100644 index 000000000..ebddfb055 --- /dev/null +++ b/packages/services/module/module.service.ts @@ -0,0 +1,213 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { IModule, TIssue, ILinkDetails, ModuleLink } from "@plane/types"; +import { API_BASE_URL } from "helpers/common.helper"; + +export class ModuleService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getModules(workspaceSlug: string, projectId: string): Promise { + 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 { + 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 { + 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 { + 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 + ): Promise { + 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 { + 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): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addIssuesToModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: { issues: string[] } + ): Promise { + 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[] } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/modules/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeIssueFromModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + issueId: string + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeIssuesFromModuleBulk( + workspaceSlug: string, + projectId: string, + moduleId: string, + issueIds: string[] + ): Promise { + const promiseDataUrls: any = []; + issueIds.forEach((issueId) => { + promiseDataUrls.push( + this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`) + ); + }); + return await Promise.all(promiseDataUrls) + .then((response) => response) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeModulesFromIssueBulk( + workspaceSlug: string, + projectId: string, + issueId: string, + moduleIds: string[] + ): Promise { + const promiseDataUrls: any = []; + moduleIds.forEach((moduleId) => { + promiseDataUrls.push( + this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`) + ); + }); + return await Promise.all(promiseDataUrls) + .then((response) => response) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createModuleLink( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: Partial + ): Promise { + 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 + ): Promise { + 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 { + 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 { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/${moduleId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/page/page.service.ts b/packages/services/page/page.service.ts new file mode 100644 index 000000000..3f0090b57 --- /dev/null +++ b/packages/services/page/page.service.ts @@ -0,0 +1,203 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import { IPage, IPageBlock, TIssue } from "@plane/types"; + +export class PageService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createPage(workspaceSlug: string, projectId: string, data: Partial): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchPage(workspaceSlug: string, projectId: string, pageId: string, data: Partial): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, data) + .then((response) => response?.data) + .catch((error) => { + console.error("error", error?.response?.data); + throw error?.response?.data; + }); + } + + async deletePage(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addPageToFavorites(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-pages/`, { page: pageId }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removePageFromFavorites(workspaceSlug: string, projectId: string, pageId: string) { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-pages/${pageId}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProjectPages(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPagesWithParams( + workspaceSlug: string, + projectId: string, + pageType: "all" | "favorite" | "private" | "shared" + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, { + params: { + page_view: pageType, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPageDetails(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + data: Partial + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + pageBlockId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + pageBlockId: string, + data: Partial + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deletePageBlock(workspaceSlug: string, projectId: string, pageId: string, pageBlockId: string): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async listPageBlocks(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async convertPageBlockToIssue( + workspaceSlug: string, + projectId: string, + pageId: string, + blockId: string + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${blockId}/issues/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + // =============== Archiving & Unarchiving Pages ================= + async archivePage(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/archive/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async restorePage(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/unarchive/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getArchivedPages(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-pages/`) + .then((response) => response?.data) + .catch((error) => { + throw error; + }); + } + // ==================== Pages Locking Services ========================== + async lockPage(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/lock/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async unlockPage(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/unlock/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/project/index.ts b/packages/services/project/index.ts new file mode 100644 index 000000000..18cf1200a --- /dev/null +++ b/packages/services/project/index.ts @@ -0,0 +1,6 @@ +export * from "./project.service"; +export * from "./project-estimate.service"; +export * from "./project-export.service"; +export * from "./project-member.service"; +export * from "./project-state.service"; +export * from "./project-publish.service"; diff --git a/packages/services/project/project-estimate.service.ts b/packages/services/project/project-estimate.service.ts new file mode 100644 index 000000000..6d276c7b9 --- /dev/null +++ b/packages/services/project/project-estimate.service.ts @@ -0,0 +1,72 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { IEstimate, IEstimateFormData, IEstimatePoint } from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class ProjectEstimateService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createEstimate( + workspaceSlug: string, + projectId: string, + data: IEstimateFormData + ): Promise<{ + estimate: IEstimate; + estimate_points: IEstimatePoint[]; + }> { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async patchEstimate( + workspaceSlug: string, + projectId: string, + estimateId: string, + data: IEstimateFormData + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getEstimateDetails(workspaceSlug: string, projectId: string, estimateId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getEstimatesList(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteEstimate(workspaceSlug: string, projectId: string, estimateId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceEstimatesList(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/estimates/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/project/project-export.service.ts b/packages/services/project/project-export.service.ts new file mode 100644 index 000000000..b5503a829 --- /dev/null +++ b/packages/services/project/project-export.service.ts @@ -0,0 +1,23 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class ProjectExportService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async csvExport( + workspaceSlug: string, + data: { + provider: string; + project: string[]; + } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/export-issues/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/project/project-member.service.ts b/packages/services/project/project-member.service.ts new file mode 100644 index 000000000..05345984e --- /dev/null +++ b/packages/services/project/project-member.service.ts @@ -0,0 +1,68 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import type { IProjectBulkAddFormData, IProjectMember, IProjectMembership } from "@plane/types"; + +export class ProjectMemberService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async fetchProjectMembers(workspaceSlug: string, projectId: string): Promise { + 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 { + 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 { + 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 { + 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 + ): Promise { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/project/project-publish.service.ts b/packages/services/project/project-publish.service.ts new file mode 100644 index 000000000..1327453d2 --- /dev/null +++ b/packages/services/project/project-publish.service.ts @@ -0,0 +1,61 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import { IProjectPublishSettings } from "store/project/project-publish.store"; + +export class ProjectPublishService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getProjectSettingsAsync(workspace_slug: string, project_slug: string): Promise { + return this.get(`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async createProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + data: IProjectPublishSettings + ): Promise { + return this.post(`/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + project_publish_id: string, + data: IProjectPublishSettings + ): Promise { + return this.patch( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async deleteProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + project_publish_id: string + ): Promise { + return this.delete( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } +} diff --git a/packages/services/project/project-state.service.ts b/packages/services/project/project-state.service.ts new file mode 100644 index 000000000..9f846987e --- /dev/null +++ b/packages/services/project/project-state.service.ts @@ -0,0 +1,76 @@ +// services +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import type { IState } from "@plane/types"; + +export class ProjectStateService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createState(workspaceSlug: string, projectId: string, data: any): Promise { + 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 { + 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 { + 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 { + 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 { + 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): Promise { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getWorkspaceStates(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/states/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/project/project.service.ts b/packages/services/project/project.service.ts new file mode 100644 index 000000000..4956b952e --- /dev/null +++ b/packages/services/project/project.service.ts @@ -0,0 +1,168 @@ +import { API_BASE_URL } from "helpers/common.helper"; +// services +import { APIService } from "services/api.service"; +// types +import type { + GithubRepositoriesResponse, + IProject, + ISearchIssueResponse, + ProjectPreferences, + IProjectViewProps, + TProjectIssuesSearchParams, +} from "@plane/types"; + +export class ProjectService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createProject(workspaceSlug: string, data: Partial): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async checkProjectIdentifierAvailability(workspaceSlug: string, data: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/project-identifiers`, { + params: { + name: data, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProjects(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProject(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateProject(workspaceSlug: string, projectId: string, data: Partial): Promise { + 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 { + 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: { + view_props?: IProjectViewProps; + default_props?: IProjectViewProps; + preferences?: ProjectPreferences; + sort_order?: number; + } + ): Promise { + 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 { + return this.request({ + method: "get", + url, + headers: this.getAccessToken() ? this.getHeaders() : {}, + }) + .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 { + 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 { + 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 { + 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 { + 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 { + 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 { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/search-issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/user/auth.service.ts b/packages/services/user/auth.service.ts new file mode 100644 index 000000000..f47a52824 --- /dev/null +++ b/packages/services/user/auth.service.ts @@ -0,0 +1,148 @@ +// services +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { + IEmailCheckData, + IEmailCheckResponse, + ILoginTokenResponse, + IMagicSignInData, + IPasswordSignInData, +} from "@plane/types"; + +export class AuthService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async emailCheck(data: IEmailCheckData): Promise { + return this.post("/api/email-check/", data, { headers: {} }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async passwordSignIn(data: IPasswordSignInData): Promise { + return this.post("/api/sign-in/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async sendResetPasswordLink(data: { email: string }): Promise { + return this.post(`/api/forgot-password/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async setPassword(data: { password: string }): Promise { + return this.post(`/api/users/me/set-password/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async resetPassword( + uidb64: string, + token: string, + data: { + new_password: string; + } + ): Promise { + return this.post(`/api/reset-password/${uidb64}/${token}/`, data, { headers: {} }) + .then((response) => { + if (response?.status === 200) { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + } + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async emailSignUp(data: { email: string; password: string }): Promise { + return this.post("/api/sign-up/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async socialAuth(data: any): Promise { + return this.post("/api/social-auth/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async generateUniqueCode(data: { email: string }): Promise { + return this.post("/api/magic-generate/", data, { headers: {} }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async magicSignIn(data: IMagicSignInData): Promise { + return await this.post("/api/magic-sign-in/", data, { headers: {} }) + .then((response) => { + if (response?.status === 200) { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + } + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async instanceAdminSignIn(data: IPasswordSignInData): Promise { + return await this.post("/api/instances/admins/sign-in/", data, { headers: {} }) + .then((response) => { + if (response?.status === 200) { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + } + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async signOut(): Promise { + return this.post("/api/sign-out/", { refresh_token: this.getRefreshToken() }) + .then((response) => { + this.purgeAccessToken(); + this.purgeRefreshToken(); + return response?.data; + }) + .catch((error) => { + this.purgeAccessToken(); + this.purgeRefreshToken(); + throw error?.response?.data; + }); + } +} diff --git a/packages/services/user/notification.service.ts b/packages/services/user/notification.service.ts new file mode 100644 index 000000000..db9c6d6d1 --- /dev/null +++ b/packages/services/user/notification.service.ts @@ -0,0 +1,144 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { + IUserNotification, + INotificationParams, + NotificationCount, + PaginatedUserNotification, + IMarkAllAsReadPayload, +} from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class NotificationService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getUserNotifications(workspaceSlug: string, params: INotificationParams): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserNotificationDetailById(workspaceSlug: string, notificationId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsRead(workspaceSlug: string, notificationId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsUnread(workspaceSlug: string, notificationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsArchived(workspaceSlug: string, notificationId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsUnarchived(workspaceSlug: string, notificationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchUserNotification( + workspaceSlug: string, + notificationId: string, + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteUserNotification(workspaceSlug: string, notificationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async subscribeToIssueNotifications(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueNotificationSubscriptionStatus( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise<{ + subscribed: boolean; + }> { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async unsubscribeFromIssueNotifications(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUnreadNotificationsCount(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications/unread/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getNotifications(url: string): Promise { + return this.get(url) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markAllNotificationsAsRead(workspaceSlug: string, payload: IMarkAllAsReadPayload): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, { + ...payload, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/user/user.service.ts b/packages/services/user/user.service.ts new file mode 100644 index 000000000..13ffa9c51 --- /dev/null +++ b/packages/services/user/user.service.ts @@ -0,0 +1,212 @@ +// services +import { APIService } from "services/api.service"; +// types +import type { + TIssue, + IUser, + IUserActivityResponse, + IInstanceAdminStatus, + IUserProfileData, + IUserProfileProjectSegregation, + IUserSettings, + IUserWorkspaceDashboard, + IUserEmailNotificationSettings, +} from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class UserService extends APIService { + constructor() { + super(API_BASE_URL); + } + + currentUserConfig() { + return { + url: `${this.baseURL}/api/users/me/`, + headers: this.getHeaders(), + }; + } + + 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 { + return this.get("/api/users/me/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async currentUserInstanceAdminStatus(): Promise { + return this.get("/api/users/me/instance-admin/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async currentUserSettings(): Promise { + return this.get("/api/users/me/settings/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async currentUserEmailNotificationSettings(): Promise { + return this.get("/api/users/me/notification-preferences/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateUser(data: Partial): Promise { + return this.patch("/api/users/me/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateUserOnBoard(): Promise { + return this.patch("/api/users/me/onboard/", { + is_onboarded: true, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateUserTourCompleted(): Promise { + 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): Promise { + return this.patch("/api/users/me/notification-preferences/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserActivity(): Promise { + return this.get(`/api/users/me/activities/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async userWorkspaceDashboard(workspaceSlug: string, month: number): Promise { + return this.get(`/api/users/me/workspaces/${workspaceSlug}/dashboard/`, { + params: { + month: month, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async changePassword(data: { old_password: string; new_password: string; confirm_password: string }): Promise { + return this.post(`/api/users/me/change-password/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileData(workspaceSlug: string, userId: string): Promise { + 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 { + 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): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/user-activity/${userId}/?per_page=15`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileIssues(workspaceSlug: string, userId: string, params: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/user-issues/${userId}/`, { + params, + }) + .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 { + 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; + }); + } +} diff --git a/packages/services/view/view.service.ts b/packages/services/view/view.service.ts new file mode 100644 index 000000000..95ae7dd06 --- /dev/null +++ b/packages/services/view/view.service.ts @@ -0,0 +1,81 @@ +import { APIService } from "services/api.service"; +// types +import { IProjectView } from "@plane/types"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class ViewService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async createView(workspaceSlug: string, projectId: string, data: Partial): Promise { + 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): Promise { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/${viewId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/workspace/app_installation.service.ts b/packages/services/workspace/app_installation.service.ts new file mode 100644 index 000000000..179721036 --- /dev/null +++ b/packages/services/workspace/app_installation.service.ts @@ -0,0 +1,63 @@ +// services +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; + +export class AppInstallationService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async addInstallationApp(workspaceSlug: string, provider: string, data: any): Promise { + 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 { + 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 { + 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 { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/${slackSyncId}` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } +} diff --git a/packages/services/workspace/dashboard.service.ts b/packages/services/workspace/dashboard.service.ts new file mode 100644 index 000000000..e001f92a1 --- /dev/null +++ b/packages/services/workspace/dashboard.service.ts @@ -0,0 +1,53 @@ +import { APIService } from "services/api.service"; +// helpers +import { API_BASE_URL } from "helpers/common.helper"; +// types +import { THomeDashboardResponse, TWidget, TWidgetStatsResponse, TWidgetStatsRequestParams } from "@plane/types"; + +export class DashboardService extends APIService { + constructor() { + super(API_BASE_URL); + } + + async getHomeDashboardWidgets(workspaceSlug: string): Promise { + 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 { + return this.get(`/api/workspaces/${workspaceSlug}/dashboard/${dashboardId}/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getDashboardDetails(dashboardId: string): Promise { + return this.get(`/api/dashboard/${dashboardId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateDashboardWidget(dashboardId: string, widgetId: string, data: Partial): Promise { + return this.patch(`/api/dashboard/${dashboardId}/widgets/${widgetId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/workspace/workspace.service.ts b/packages/services/workspace/workspace.service.ts new file mode 100644 index 000000000..e960ef59d --- /dev/null +++ b/packages/services/workspace/workspace.service.ts @@ -0,0 +1,397 @@ +// services +import { APIService } from "../api.service"; +// types +import { + IWorkspace, + IWorkspaceMemberMe, + IWorkspaceMember, + IWorkspaceMemberInvitation, + ILastActiveWorkspaceDetails, + IWorkspaceSearchResults, + IProductUpdateResponse, + IWorkspaceBulkInviteFormData, + IWorkspaceViewProps, + IUserProjectsRole, + TIssue, + IWorkspaceView, +} from "@plane/types"; + +export interface IWorkspaceService { + list(): Promise; + retrieve(workspaceSlug: string): Promise; + create(data: Partial): Promise; + update(workspaceSlug: string, data: Partial): Promise; + delete(workspaceSlug: string): Promise; + invite( + workspaceSlug: string, + data: IWorkspaceBulkInviteFormData + ): Promise; + join(workspaceSlug: string, invitationId: string, data: any): Promise; + joinMany(data: any): Promise; + getLastActiveWorkspaceAndProjects(): Promise; + userWorkspaceInvitations(): Promise; + workspaceMemberMe(workspaceSlug: string): Promise; + updateWorkspaceView( + workspaceSlug: string, + data: { view_props: IWorkspaceViewProps } + ): Promise; + fetchWorkspaceMembers(workspaceSlug: string): Promise; + updateWorkspaceMember( + workspaceSlug: string, + memberId: string, + data: Partial + ): Promise; + deleteWorkspaceMember(workspaceSlug: string, memberId: string): Promise; + workspaceInvitations( + workspaceSlug: string + ): Promise; + getWorkspaceInvitation( + workspaceSlug: string, + invitationId: string + ): Promise; + updateWorkspaceInvitation( + workspaceSlug: string, + invitationId: string, + data: Partial + ): Promise; + deleteWorkspaceInvitations( + workspaceSlug: string, + invitationId: string + ): Promise; + workspaceSlugCheck(slug: string): Promise; + searchWorkspace( + workspaceSlug: string, + params: { project_id?: string; search: string; workspace_search: boolean } + ): Promise; + getProductUpdates(): Promise; + createView( + workspaceSlug: string, + data: Partial + ): Promise; + updateView( + workspaceSlug: string, + viewId: string, + data: Partial + ): Promise; + deleteView(workspaceSlug: string, viewId: string): Promise; + getAllViews(workspaceSlug: string): Promise; + getViewDetails( + workspaceSlug: string, + viewId: string + ): Promise; + getViewIssues(workspaceSlug: string, params: any): Promise; + getWorkspaceUserProjectsRole( + workspaceSlug: string + ): Promise; +} + +export class WorkspaceService extends APIService implements IWorkspaceService { + constructor(BASE_URL: string) { + super(BASE_URL); + } + + async list(): Promise { + return this.get("/api/users/me/workspaces/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieve(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async create(data: Partial): Promise { + return this.post("/api/workspaces/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async update( + workspaceSlug: string, + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async delete(workspaceSlug: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async invite( + workspaceSlug: string, + data: IWorkspaceBulkInviteFormData + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/invitations/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async join( + workspaceSlug: string, + invitationId: string, + data: any + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/invitations/${invitationId}/join/`, + data, + { + headers: {}, + } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async joinMany(data: any): Promise { + return this.post("/api/users/me/workspaces/invitations/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getLastActiveWorkspaceAndProjects(): Promise { + return this.get("/api/users/last-visited-workspace/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async userWorkspaceInvitations(): Promise { + return this.get("/api/users/me/workspaces/invitations/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceMemberMe(workspaceSlug: string): Promise { + 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 { + return this.post(`/api/workspaces/${workspaceSlug}/workspace-views/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async fetchWorkspaceMembers( + workspaceSlug: string + ): Promise { + 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 + ): Promise { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/members/${memberId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceInvitations( + workspaceSlug: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/invitations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceInvitation( + workspaceSlug: string, + invitationId: string + ): Promise { + 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 + ): Promise { + 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 { + return this.delete( + `/api/workspaces/${workspaceSlug}/invitations/${invitationId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceSlugCheck(slug: string): Promise { + 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 { + return this.get(`/api/workspaces/${workspaceSlug}/search/`, { + params, + }) + .then((res) => res?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + async getProductUpdates(): Promise { + return this.get("/api/release-notes/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createView( + workspaceSlug: string, + data: Partial + ): Promise { + 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 + ): Promise { + 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 { + return this.delete(`/api/workspaces/${workspaceSlug}/views/${viewId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getAllViews(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/views/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getViewDetails( + workspaceSlug: string, + viewId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/views/${viewId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getViewIssues(workspaceSlug: string, params: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceUserProjectsRole( + workspaceSlug: string + ): Promise { + return this.get(`/api/users/me/workspaces/${workspaceSlug}/project-roles/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/types/src/ai.d.ts b/packages/types/src/ai.d.ts index ce8bcbadb..cf2a85e9e 100644 --- a/packages/types/src/ai.d.ts +++ b/packages/types/src/ai.d.ts @@ -1,9 +1,9 @@ import { IProjectLite, IWorkspaceLite } from "@plane/types"; -export interface IGptResponse { +export type GptApiResponse = { response: string; response_html: string; count: number; project_detail: IProjectLite; workspace_detail: IWorkspaceLite; -} +};