chore: common services package (#6255)

* fix: initial services package setup

* fix: services packages updates

* fix: services changes

* fix: merge conflicts

* chore: file structuring

* fix: import fixes
This commit is contained in:
sriram veeraghanta
2024-12-23 01:51:30 +05:30
committed by GitHub
parent 1ee0661ac1
commit 043f4eaa5e
47 changed files with 2345 additions and 10 deletions

View File

@@ -0,0 +1,3 @@
export enum AI_EDITOR_TASKS {
ASK_ANYTHING = "ASK_ANYTHING",
}

View File

@@ -1,26 +1,25 @@
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "";
// PI Base Url
export const PI_BASE_URL = process.env.NEXT_PUBLIC_PI_BASE_URL || "";
export const API_BASE_PATH = process.env.NEXT_PUBLIC_API_BASE_PATH || "/";
export const API_URL = encodeURI(`${API_BASE_URL}${API_BASE_PATH}`);
// God Mode Admin App Base Url
export const ADMIN_BASE_URL = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
export const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "";
export const GOD_MODE_URL = encodeURI(`${ADMIN_BASE_URL}${ADMIN_BASE_PATH}/`);
export const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "/";
export const GOD_MODE_URL = encodeURI(`${ADMIN_BASE_URL}${ADMIN_BASE_PATH}`);
// Publish App Base Url
export const SPACE_BASE_URL = process.env.NEXT_PUBLIC_SPACE_BASE_URL || "";
export const SPACE_BASE_PATH = process.env.NEXT_PUBLIC_SPACE_BASE_PATH || "";
export const SITES_URL = encodeURI(`${SPACE_BASE_URL}${SPACE_BASE_PATH}/`);
export const SPACE_BASE_PATH = process.env.NEXT_PUBLIC_SPACE_BASE_PATH || "/";
export const SITES_URL = encodeURI(`${SPACE_BASE_URL}${SPACE_BASE_PATH}`);
// Live App Base Url
export const LIVE_BASE_URL = process.env.NEXT_PUBLIC_LIVE_BASE_URL || "";
export const LIVE_BASE_PATH = process.env.NEXT_PUBLIC_LIVE_BASE_PATH || "";
export const LIVE_URL = encodeURI(`${LIVE_BASE_URL}${LIVE_BASE_PATH}/`);
export const LIVE_BASE_PATH = process.env.NEXT_PUBLIC_LIVE_BASE_PATH || "/";
export const LIVE_URL = encodeURI(`${LIVE_BASE_URL}${LIVE_BASE_PATH}`);
// Web App Base Url
export const WEB_BASE_URL = process.env.NEXT_PUBLIC_WEB_BASE_URL || "";
export const WEB_BASE_PATH = process.env.NEXT_PUBLIC_WEB_BASE_PATH || "";
export const WEB_BASE_PATH = process.env.NEXT_PUBLIC_WEB_BASE_PATH || "/";
export const WEB_URL = encodeURI(`${WEB_BASE_URL}${WEB_BASE_PATH}`);
// plane website url
export const WEBSITE_URL =
process.env.NEXT_PUBLIC_WEBSITE_URL || "https://plane.so";
// support email
export const SUPPORT_EMAIL =
process.env.NEXT_PUBLIC_SUPPORT_EMAIL || "support@plane.so";

View File

@@ -1,3 +1,4 @@
export * from "./ai";
export * from "./auth";
export * from "./endpoints";
export * from "./file";

View File

@@ -44,6 +44,30 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-useless-empty-export": "error",
"@typescript-eslint/prefer-ts-expect-error": "warn",
"import/order": [
"warn",
{
groups: ["builtin", "external", "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
},
ignorePatterns: [".*.js", "node_modules/", "dist/"],
};

View File

@@ -0,0 +1,3 @@
build/*
dist/*
out/*

View File

@@ -0,0 +1,9 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
};

View File

@@ -0,0 +1,5 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5"
}

View File

@@ -0,0 +1,14 @@
{
"name": "@plane/services",
"version": "0.24.1",
"private": true,
"main": "./src/index.ts",
"scripts": {
"lint": "eslint src --ext .ts,.tsx",
"lint:errors": "eslint src --ext .ts,.tsx --quiet"
},
"dependencies": {
"@plane/constants": "*",
"axios": "^1.4.0"
}
}

View File

@@ -0,0 +1,67 @@
// plane web constants
import { AI_EDITOR_TASKS, API_BASE_URL } from "@plane/constants";
// services
import { APIService } from "@/api.service";
/**
* Payload type for AI editor tasks
* @typedef {Object} TTaskPayload
* @property {number} [casual_score] - Optional score for casual tone analysis
* @property {number} [formal_score] - Optional score for formal tone analysis
* @property {AI_EDITOR_TASKS} task - Type of AI editor task to perform
* @property {string} text_input - The input text to be processed
*/
export type TTaskPayload = {
casual_score?: number;
formal_score?: number;
task: AI_EDITOR_TASKS;
text_input: string;
};
/**
* Service class for handling AI-related API operations
* Extends the base APIService class to interact with AI endpoints
* @extends {APIService}
*/
export class AIService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Creates a GPT-based task for a specific workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {Object} data - The data payload for the GPT task
* @param {string} data.prompt - The prompt text for the GPT model
* @param {string} data.task - The type of task to be performed
* @returns {Promise<any>} The response data from the GPT task
* @throws {Error} Throws the response error if the request fails
*/
async prompt(workspaceSlug: string, data: { prompt: string; task: string }): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/ai-assistant/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Performs an editor-specific AI task for text processing
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {TTaskPayload} data - The task payload containing text and processing parameters
* @returns {Promise<{response: string}>} The processed text response
* @throws {Error} Throws the response data if the request fails
*/
async rephraseGrammar(
workspaceSlug: string,
data: TTaskPayload
): Promise<{
response: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/rephrase-grammar/`, data)
.then((res) => res?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,93 @@
// constants
import { API_BASE_URL } from "@plane/constants";
// types
import {
IAnalyticsParams,
IAnalyticsResponse,
IDefaultAnalyticsResponse,
IExportAnalyticsFormData,
ISaveAnalyticsFormData,
} from "@plane/types";
// services
import { APIService } from "../api.service";
export class AnalyticsService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves analytics data for a specific workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {IAnalyticsParams} params - Parameters for filtering analytics data
* @param {string|number} [params.project] - Optional project identifier that will be converted to string
* @returns {Promise<IAnalyticsResponse>} The analytics data for the workspace
* @throws {Error} Throws response data if the request fails
*/
async getAnalytics(workspaceSlug: string, params: IAnalyticsParams): Promise<IAnalyticsResponse> {
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;
});
}
/**
* Retrieves default analytics data for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {Partial<IAnalyticsParams>} [params] - Optional parameters for filtering default analytics
* @param {string|number} [params.project] - Optional project identifier that will be converted to string
* @returns {Promise<IDefaultAnalyticsResponse>} The default analytics data
* @throws {Error} Throws response data if the request fails
*/
async getDefaultAnalytics(
workspaceSlug: string,
params?: Partial<IAnalyticsParams>
): Promise<IDefaultAnalyticsResponse> {
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;
});
}
/**
* Saves analytics view configuration for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {ISaveAnalyticsFormData} data - The analytics configuration data to save
* @returns {Promise<any>} The response from saving the analytics view
* @throws {Error} Throws response data if the request fails
*/
async save(workspaceSlug: string, data: ISaveAnalyticsFormData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/analytic-view/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Exports analytics data for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {IExportAnalyticsFormData} data - Configuration for the analytics export
* @returns {Promise<any>} The exported analytics data
* @throws {Error} Throws response data if the request fails
*/
async export(workspaceSlug: string, data: IExportAnalyticsFormData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/export-analytics/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,110 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
/**
* Abstract base class for making HTTP requests using axios
* @abstract
*/
export abstract class APIService {
protected baseURL: string;
private axiosInstance: AxiosInstance;
/**
* Creates an instance of APIService
* @param {string} baseURL - The base URL for all HTTP requests
*/
constructor(baseURL: string) {
this.baseURL = baseURL;
this.axiosInstance = axios.create({
baseURL,
withCredentials: true,
});
this.setupInterceptors();
}
/**
* Sets up axios interceptors for handling responses
* Currently handles 401 unauthorized responses by redirecting to login
* @private
*/
private setupInterceptors() {
this.axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
const currentPath = window.location.pathname;
window.location.replace(`/${currentPath ? `?next_path=${currentPath}` : ``}`);
}
return Promise.reject(error);
}
);
}
/**
* Makes a GET request to the specified URL
* @param {string} url - The endpoint URL
* @param {object} [params={}] - URL parameters
* @param {AxiosRequestConfig} [config={}] - Additional axios configuration
* @returns {Promise} Axios response promise
*/
get(url: string, params = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.get(url, {
...params,
...config,
});
}
/**
* Makes a POST request to the specified URL
* @param {string} url - The endpoint URL
* @param {object} [data={}] - Request body data
* @param {AxiosRequestConfig} [config={}] - Additional axios configuration
* @returns {Promise} Axios response promise
*/
post(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.post(url, data, config);
}
/**
* Makes a PUT request to the specified URL
* @param {string} url - The endpoint URL
* @param {object} [data={}] - Request body data
* @param {AxiosRequestConfig} [config={}] - Additional axios configuration
* @returns {Promise} Axios response promise
*/
put(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.put(url, data, config);
}
/**
* Makes a PATCH request to the specified URL
* @param {string} url - The endpoint URL
* @param {object} [data={}] - Request body data
* @param {AxiosRequestConfig} [config={}] - Additional axios configuration
* @returns {Promise} Axios response promise
*/
patch(url: string, data = {}, config: AxiosRequestConfig = {}) {
return this.axiosInstance.patch(url, data, config);
}
/**
* Makes a DELETE request to the specified URL
* @param {string} url - The endpoint URL
* @param {any} [data] - Request body data
* @param {AxiosRequestConfig} [config={}] - Additional axios configuration
* @returns {Promise} Axios response promise
*/
delete(url: string, data?: any, config: AxiosRequestConfig = {}) {
return this.axiosInstance.delete(url, { data, ...config });
}
/**
* Makes a custom request with the provided configuration
* @param {object} [config={}] - Axios request configuration
* @returns {Promise} Axios response promise
*/
request(config = {}) {
return this.axiosInstance(config);
}
}

View File

@@ -0,0 +1,124 @@
import { API_BASE_URL } from "@plane/constants";
// types
import { ICsrfTokenData, IEmailCheckData, IEmailCheckResponse } from "@plane/types";
// services
import { APIService } from "../api.service";
/**
* Service class for handling authentication-related operations
* Provides methods for user authentication, password management, and session handling
* @extends {APIService}
*/
export default class AuthService extends APIService {
/**
* Creates an instance of AuthService
* Initializes with the base API URL
*/
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Requests a CSRF token for form submission security
* @returns {Promise<ICsrfTokenData>} Object containing the CSRF token
* @throws {Error} Throws the complete error object if the request fails
*/
async requestCSRFToken(): Promise<ICsrfTokenData> {
return this.get("/auth/get-csrf-token/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
/**
* Checks if an email exists in the system
* @param {IEmailCheckData} data - Email data to verify
* @returns {Promise<IEmailCheckResponse>} Response indicating email status
* @throws {Error} Throws response data if the request fails
*/
async emailCheck(data: IEmailCheckData): Promise<IEmailCheckResponse> {
return this.post("/auth/email-check/", data, { headers: {} })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Sends a password reset link to the specified email address
* @param {{ email: string }} data - Object containing the email address
* @returns {Promise<any>} Response from the password reset request
* @throws {Error} Throws response object if the request fails
*/
async sendResetPasswordLink(data: { email: string }): Promise<any> {
return this.post(`/auth/forgot-password/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Sets a new password using a reset token
* @param {string} token - CSRF token for form submission security
* @param {{ password: string }} data - Object containing the new password
* @returns {Promise<any>} Response from the password update request
* @throws {Error} Throws response data if the request fails
*/
async setPassword(token: string, data: { password: string }): Promise<any> {
return this.post(`/auth/set-password/`, data, {
headers: {
"X-CSRFTOKEN": token,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Generates a unique code for magic link authentication
* @param {{ email: string }} data - Object containing the email address
* @returns {Promise<any>} Response containing the generated unique code
* @throws {Error} Throws response data if the request fails
*/
async generateUniqueCode(data: { email: string }): Promise<any> {
return this.post("/auth/magic-generate/", data, { headers: {} })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Performs user sign out by submitting a form with CSRF token
* Creates and submits a form dynamically to handle the sign-out process
* @param {string} baseUrl - Base URL for the sign-out endpoint
* @returns {Promise<any>} Resolves when sign-out is complete
* @throws {Error} Throws error if CSRF token is not found
*/
async signOut(baseUrl: string): Promise<any> {
await this.requestCSRFToken().then((data) => {
const csrfToken = data?.csrf_token;
if (!csrfToken) throw Error("CSRF token not found");
const form = document.createElement("form");
const element1 = document.createElement("input");
form.method = "POST";
form.action = `${baseUrl}/auth/sign-out/`;
element1.value = csrfToken;
element1.name = "csrfmiddlewaretoken";
element1.type = "hidden";
form.appendChild(element1);
document.body.appendChild(form);
form.submit();
});
}
}

View File

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

View File

@@ -0,0 +1,78 @@
import { API_BASE_URL } from "@plane/constants";
import type { TCycleDistribution, TProgressSnapshot, TCycleEstimateDistribution } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing cycles within a workspace and project context.
* Extends APIService to handle HTTP requests to the cycle-related endpoints.
* @extends {APIService}
*/
export class CycleAnalyticsService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves analytics for active cycles in a workspace.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @param {string} [analytic_type="points"] - The type of analytics to retrieve
* @returns {Promise<TCycleDistribution | TCycleEstimateDistribution>} The cycle analytics data
* @throws {Error} If the request fails
*/
async workspaceActiveCyclesAnalytics(
workspaceSlug: string,
projectId: string,
cycleId: string,
analytic_type: string = "points"
): Promise<TCycleDistribution | TCycleEstimateDistribution> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/analytics?type=${analytic_type}`
)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
/**
* Retrieves progress data for active cycles.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @returns {Promise<TProgressSnapshot>} The cycle progress data
* @throws {Error} If the request fails
*/
async workspaceActiveCyclesProgress(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<TProgressSnapshot> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/progress/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
/**
* Retrieves advanced progress data for active cycles (Pro feature).
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @returns {Promise<TProgressSnapshot>} The detailed cycle progress data
* @throws {Error} If the request fails
*/
async workspaceActiveCyclesProgressPro(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<TProgressSnapshot> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-progress/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
}

View File

@@ -0,0 +1,83 @@
import { API_BASE_URL } from "@plane/constants";
import { ICycle } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing archived cycles in a project
* Provides methods for retrieving, archiving, and restoring project cycles
* @extends {APIService}
*/
export class CycleArchiveService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves all archived cycles for a specific project
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @returns {Promise<ICycle[]>} Array of archived cycles
* @throws {Error} Throws response data if the request fails
*/
async list(workspaceSlug: string, projectId: string): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-cycles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves details of a specific archived cycle
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} cycleId - The unique identifier for the cycle
* @returns {Promise<ICycle>} Details of the archived cycle
* @throws {Error} Throws response data if the request fails
*/
async retrieve(workspaceSlug: string, projectId: string, cycleId: string): Promise<ICycle> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-cycles/${cycleId}/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
/**
* Archives a specific cycle in a project
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} cycleId - The unique identifier for the cycle to archive
* @returns {Promise<{archived_at: string}>} Object containing the archive timestamp
* @throws {Error} Throws response data if the request fails
*/
async archive(
workspaceSlug: string,
projectId: string,
cycleId: string
): Promise<{
archived_at: string;
}> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Restores a previously archived cycle
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} cycleId - The unique identifier for the cycle to restore
* @returns {Promise<void>} Resolves when the cycle is successfully restored
* @throws {Error} Throws response data if the request fails
*/
async restore(workspaceSlug: string, projectId: string, cycleId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,70 @@
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/api.service";
export class CycleOperationsService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Adds a cycle to user favorites.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {{cycle: string}} data - The favorite cycle data
* @returns {Promise<any>} The response data
* @throws {Error} If the request fails
*/
async addToFavorites(
workspaceSlug: string,
projectId: string,
data: {
cycle: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Removes a cycle from user favorites.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @returns {Promise<any>} The removal response
* @throws {Error} If the request fails
*/
async removeFromFavorites(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/${cycleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Transfers issues between cycles.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The source cycle identifier
* @param {{new_cycle_id: string}} data - The target cycle data
* @returns {Promise<any>} The transfer response
* @throws {Error} If the request fails
*/
async transferIssues(
workspaceSlug: string,
projectId: string,
cycleId: string,
data: {
new_cycle_id: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/transfer-issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,184 @@
import { API_BASE_URL } from "@plane/constants";
import type { CycleDateCheckData, ICycle, TIssuesResponse, IWorkspaceActiveCyclesResponse } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing cycles within a workspace and project context.
* Extends APIService to handle HTTP requests to the cycle-related endpoints.
* @extends {APIService}
*/
export class CycleService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves paginated list of active cycles in a workspace.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} cursor - The pagination cursor
* @param {number} per_page - Number of items per page
* @returns {Promise<IWorkspaceActiveCyclesResponse>} Paginated active cycles data
* @throws {Error} If the request fails
*/
async workspaceActiveCycles(
workspaceSlug: string,
cursor: string,
per_page: number
): Promise<IWorkspaceActiveCyclesResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/active-cycles/`, {
params: {
per_page,
cursor,
},
})
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
/**
* Gets all cycles in a workspace.
* @param {string} workspaceSlug - The workspace identifier
* @returns {Promise<ICycle[]>} Array of cycle objects
* @throws {Error} If the request fails
*/
async getWorkspaceCycles(workspaceSlug: string): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/cycles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Creates a new cycle in a project.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {any} data - The cycle creation data
* @returns {Promise<ICycle>} The created cycle object
* @throws {Error} If the request fails
*/
async create(workspaceSlug: string, projectId: string, data: any): Promise<ICycle> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves cycles with optional filtering parameters.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {"current"} [cycleType] - Optional filter for cycle type
* @returns {Promise<ICycle[]>} Array of filtered cycle objects
* @throws {Error} If the request fails
*/
async getWithParams(workspaceSlug: string, projectId: string, cycleType?: "current"): Promise<ICycle[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, {
params: {
cycle_view: cycleType,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves detailed information for a specific cycle.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @returns {Promise<ICycle>} The cycle details
* @throws {Error} If the request fails
*/
async retrieve(workspaceSlug: string, projectId: string, cycleId: string): Promise<ICycle> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
/**
* Retrieves issues associated with a specific cycle.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @param {any} [queries] - Optional query parameters
* @param {object} [config={}] - Optional request configuration
* @returns {Promise<TIssuesResponse>} The cycle issues data
* @throws {Error} If the request fails
*/
async getCycleIssues(
workspaceSlug: string,
projectId: string,
cycleId: string,
queries?: any,
config = {}
): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`,
{
params: queries,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates a cycle with partial data.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @param {Partial<ICycle>} data - The partial cycle data to update
* @returns {Promise<any>} The update response
* @throws {Error} If the request fails
*/
async update(workspaceSlug: string, projectId: string, cycleId: string, data: Partial<ICycle>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Deletes a specific cycle.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {string} cycleId - The cycle identifier
* @returns {Promise<any>} The deletion response
* @throws {Error} If the request fails
*/
async destroy(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Validates cycle dates.
* @param {string} workspaceSlug - The workspace identifier
* @param {string} projectId - The project identifier
* @param {CycleDateCheckData} data - The date check data
* @returns {Promise<any>} The validation response
* @throws {Error} If the request fails
*/
async validateDates(workspaceSlug: string, projectId: string, data: CycleDateCheckData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/date-check/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,4 @@
export * from "./cycle-analytics.service";
export * from "./cycle-archive.service";
export * from "./cycle-operations.service";
export * from "./cycle.service";

View File

@@ -0,0 +1,79 @@
import { API_BASE_URL } from "@plane/constants";
import { THomeDashboardResponse, TWidget, TWidgetStatsResponse, TWidgetStatsRequestParams } from "@plane/types";
import { APIService } from "../api.service";
export default class DashboardService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves home dashboard widgets for a specific workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @returns {Promise<THomeDashboardResponse>} Promise resolving to dashboard widget data
* @throws {Error} If the API request fails
*/
async getHomeWidgets(workspaceSlug: string): Promise<THomeDashboardResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/dashboard/`, {
params: {
dashboard_type: "home",
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Fetches statistics for a specific dashboard widget
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} dashboardId - The unique identifier for the dashboard
* @param {TWidgetStatsRequestParams} params - Parameters for filtering widget statistics
* @returns {Promise<TWidgetStatsResponse>} Promise resolving to widget statistics data
* @throws {Error} If the API request fails
*/
async getWidgetStats(
workspaceSlug: string,
dashboardId: string,
params: TWidgetStatsRequestParams
): Promise<TWidgetStatsResponse> {
return this.get(`/api/workspaces/${workspaceSlug}/dashboard/${dashboardId}/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves detailed information about a specific dashboard
* @param {string} dashboardId - The unique identifier for the dashboard
* @returns {Promise<TWidgetStatsResponse>} Promise resolving to dashboard details
* @throws {Error} If the API request fails
*/
async retrieve(dashboardId: string): Promise<TWidgetStatsResponse> {
return this.get(`/api/dashboard/${dashboardId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates a specific widget within a dashboard
* @param {string} dashboardId - The unique identifier for the dashboard
* @param {string} widgetId - The unique identifier for the widget
* @param {Partial<TWidget>} data - Partial widget data to update
* @returns {Promise<TWidget>} Promise resolving to the updated widget data
* @throws {Error} If the API request fails
*/
async updateWidget(dashboardId: string, widgetId: string, data: Partial<TWidget>): Promise<TWidget> {
return this.patch(`/api/dashboard/${dashboardId}/widgets/${widgetId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,68 @@
import { API_BASE_URL } from "@plane/constants";
import { IApiToken } from "@plane/types";
import { APIService } from "@/api.service";
export class APITokenService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves all API tokens for a specific workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @returns {Promise<IApiToken[]>} Array of API tokens associated with the workspace
* @throws {Error} Throws response data if the request fails
*/
async list(workspaceSlug: string): Promise<IApiToken[]> {
return this.get(`/api/workspaces/${workspaceSlug}/api-tokens/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves a specific API token by its ID
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} tokenId - The unique identifier of the API token
* @returns {Promise<IApiToken>} The requested API token's details
* @throws {Error} Throws response data if the request fails
*/
async retrieve(workspaceSlug: string, tokenId: string): Promise<IApiToken> {
return this.get(`/api/workspaces/${workspaceSlug}/api-tokens/${tokenId}`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Creates a new API token for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {Partial<IApiToken>} data - The data for creating the new API token
* @returns {Promise<IApiToken>} The newly created API token
* @throws {Error} Throws response data if the request fails
*/
async create(workspaceSlug: string, data: Partial<IApiToken>): Promise<IApiToken> {
return this.post(`/api/workspaces/${workspaceSlug}/api-tokens/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Deletes a specific API token from the workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} tokenId - The unique identifier of the API token to delete
* @returns {Promise<IApiToken>} The deleted API token's details
* @throws {Error} Throws response data if the request fails
*/
async destroy(workspaceSlug: string, tokenId: string): Promise<IApiToken> {
return this.delete(`/api/workspaces/${workspaceSlug}/api-tokens/${tokenId}`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,2 @@
export * from "./api-token.service";
export * from "./webhook.service";

View File

@@ -0,0 +1,104 @@
import { API_BASE_URL } from "@plane/constants";
import { IWebhook } from "@plane/types";
import { APIService } from "../api.service";
/**
* Service class for managing webhooks
* Handles CRUD operations for webhooks and secret key management
* @extends {APIService}
*/
export default class WebhookService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves all webhooks for a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IWebhook[]>} Promise resolving to array of webhooks
* @throws {Error} If the API request fails
*/
async list(workspaceSlug: string): Promise<IWebhook[]> {
return this.get(`/api/workspaces/${workspaceSlug}/webhooks/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves details of a specific webhook
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} webhookId - The unique identifier for the webhook
* @returns {Promise<IWebhook>} Promise resolving to webhook details
* @throws {Error} If the API request fails
*/
async retrieve(workspaceSlug: string, webhookId: string): Promise<IWebhook> {
return this.get(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Creates a new webhook in the workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {Object} [data={}] - Webhook configuration data
* @returns {Promise<IWebhook>} Promise resolving to the created webhook
* @throws {Error} If the API request fails
*/
async create(workspaceSlug: string, data = {}): Promise<IWebhook> {
return this.post(`/api/workspaces/${workspaceSlug}/webhooks/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates an existing webhook
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} webhookId - The unique identifier for the webhook
* @param {Object} [data={}] - Updated webhook configuration data
* @returns {Promise<IWebhook>} Promise resolving to the updated webhook
* @throws {Error} If the API request fails
*/
async update(workspaceSlug: string, webhookId: string, data = {}): Promise<IWebhook> {
return this.patch(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Deletes a webhook from the workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} webhookId - The unique identifier for the webhook
* @returns {Promise<void>} Promise resolving when webhook is deleted
* @throws {Error} If the API request fails
*/
async destroy(workspaceSlug: string, webhookId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Regenerates the secret key for a webhook
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} webhookId - The unique identifier for the webhook
* @returns {Promise<IWebhook>} Promise resolving to the webhook with new secret key
* @throws {Error} If the API request fails
*/
async regenerateSecretKey(workspaceSlug: string, webhookId: string): Promise<IWebhook> {
return this.post(`/api/workspaces/${workspaceSlug}/webhooks/${webhookId}/regenerate/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,12 @@
export * from "./ai";
export * from "./analytics";
export * from "./developer";
export * from "./auth";
export * from "./cycle";
export * from "./dashboard";
export * from "./instance";
export * from "./intake";
export * from "./module";
export * from "./user";
export * from "./project";
export * from "./workspace";

View File

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

View File

@@ -0,0 +1,44 @@
import { API_BASE_URL } from "@plane/constants";
import type { IInstanceInfo, TPage } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing instance-related operations
* Handles retrieval of instance information and changelog
* @extends {APIService}
*/
export default class InstanceService extends APIService {
/**
* Creates an instance of InstanceService
* Initializes the service with the base API URL
*/
constructor() {
super(API_BASE_URL);
}
/**
* Retrieves information about the current instance
* @returns {Promise<IInstanceInfo>} Promise resolving to instance information
* @throws {Error} If the API request fails
*/
async info(): Promise<IInstanceInfo> {
return this.get("/api/instances/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
/**
* Fetches the changelog for the current instance
* @returns {Promise<TPage>} Promise resolving to the changelog page data
* @throws {Error} If the API request fails
*/
async changelog(): Promise<TPage> {
return this.get("/api/instances/changelog/")
.then((response) => response.data)
.catch((error) => {
throw error;
});
}
}

View File

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

View File

@@ -0,0 +1,8 @@
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/api.service";
export default class IntakeService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
}

View File

@@ -0,0 +1,18 @@
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "@/api.service";
export default class IntakeIssueService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
async list(workspaceSlug: string, projectId: string, params = {}) {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,8 @@
import { API_BASE_URL } from "@plane/constants";
import { APIService } from "./api.service";
export abstract class LiveService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
}

View File

@@ -0,0 +1,3 @@
export * from "./link.service";
export * from "./module.service";
export * from "./operations.service";

View File

@@ -0,0 +1,86 @@
// types
import type { ILinkDetails, ModuleLink } from "@plane/types";
// services
import { APIService } from "@/api.service";
/**
* Service class for handling module link related operations.
* Extends the base APIService class to interact with module link endpoints.
*/
export class ModuleLinkService extends APIService {
/**
* Creates an instance of ModuleLinkService.
* @param {string} baseURL - The base URL for the API endpoints
*/
constructor(baseURL: string) {
super(baseURL);
}
/**
* Creates a new module link.
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} moduleId - The unique identifier for the module
* @param {Partial<ModuleLink>} data - The module link data to be created
* @returns {Promise<ILinkDetails>} The created module link details
* @throws {Error} When the API request fails
*/
async create(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: Partial<ModuleLink>
): Promise<ILinkDetails> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Updates an existing module link.
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} moduleId - The unique identifier for the module
* @param {string} linkId - The unique identifier for the link to update
* @param {Partial<ModuleLink>} data - The module link data to be updated
* @returns {Promise<ILinkDetails>} The updated module link details
* @throws {Error} When the API request fails
*/
async update(
workspaceSlug: string,
projectId: string,
moduleId: string,
linkId: string,
data: Partial<ModuleLink>
): Promise<ILinkDetails> {
return this.patch(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
data
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Deletes a module link.
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} projectId - The unique identifier for the project
* @param {string} moduleId - The unique identifier for the module
* @param {string} linkId - The unique identifier for the link to delete
* @returns {Promise<any>} Response data from the server
* @throws {Error} When the API request fails
*/
async destroy(workspaceSlug: string, projectId: string, moduleId: string, linkId: string): Promise<any> {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,146 @@
// types
// import type { IModule, ILinkDetails, ModuleLink, TIssuesResponse } from "@plane/types";
// services
import { APIService } from "@/api.service";
export class ModuleOperationService extends APIService {
constructor(baseURL: string) {
super(baseURL);
}
/**
* Add issues to a module
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {string} moduleId - The ID of the module
* @param {object} data - The data to be sent in the request body
* @param {string[]} data.issues - The IDs of the issues to be added
* @returns {Promise<void>}
*/
async addIssuesToModule(
workspaceSlug: string,
projectId: string,
moduleId: string,
data: { issues: string[] }
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Add modules to an issue
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {string} issueId - The ID of the issue
* @param {object} data - The data to be sent in the request body
* @param {string[]} data.modules - The IDs of the modules to be added
* @param {string[]} [data.removed_modules] - The IDs of the modules to be removed
* @returns {Promise<void>}
*/
async addModulesToIssue(
workspaceSlug: string,
projectId: string,
issueId: string,
data: { modules: string[]; removed_modules?: string[] }
): Promise<void> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/modules/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Remove issues from a module
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {string} moduleId - The ID of the module
* @param {string[]} issueIds - The IDs of the issues to be removed
* @returns {Promise<void>}
*/
async removeIssuesFromModuleBulk(
workspaceSlug: string,
projectId: string,
moduleId: string,
issueIds: string[]
): Promise<void> {
const promiseDataUrls: any = [];
issueIds.forEach((issueId) => {
promiseDataUrls.push(
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
);
});
await Promise.all(promiseDataUrls)
.then((response) => response)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Remove modules from an issue
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {string} issueId - The ID of the issue
* @param {string[]} moduleIds - The IDs of the modules to be removed
* @returns {Promise<void>}
*/
async removeModulesFromIssueBulk(
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
): Promise<void> {
const promiseDataUrls: any = [];
moduleIds.forEach((moduleId) => {
promiseDataUrls.push(
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
);
});
await Promise.all(promiseDataUrls)
.then((response) => response)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Add a module to favorites
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {object} data - The data to be sent in the request body
* @param {string} data.module - The ID of the module to be added
* @returns {Promise<any>}
*/
async addModuleToFavorites(
workspaceSlug: string,
projectId: string,
data: {
module: string;
}
): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Remove a module from favorites
* @param {string} workspaceSlug - The slug of the workspace
* @param {string} projectId - The ID of the project
* @param {string} moduleId - The ID of the module to be removed
* @returns {Promise<any>}
*/
async removeModuleFromFavorites(workspaceSlug: string, projectId: string, moduleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,94 @@
import { API_BASE_URL } from "@plane/constants";
import type { IFavorite } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing user favorites
* Handles operations for adding, updating, removing, and retrieving user favorites within a workspace
* @extends {APIService}
*/
export class UserFavoriteService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Adds a new item to user favorites
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {Partial<IFavorite>} data - Favorite item data to be added
* @returns {Promise<IFavorite>} Promise resolving to the created favorite item
* @throws {Error} If the API request fails
*/
async add(workspaceSlug: string, data: Partial<IFavorite>): Promise<IFavorite> {
return this.post(`/api/workspaces/${workspaceSlug}/user-favorites/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Updates an existing favorite item
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} favoriteId - The unique identifier for the favorite item
* @param {Partial<IFavorite>} data - Updated favorite item data
* @returns {Promise<IFavorite>} Promise resolving to the updated favorite item
* @throws {Error} If the API request fails
*/
async update(workspaceSlug: string, favoriteId: string, data: Partial<IFavorite>): Promise<IFavorite> {
return this.patch(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Removes an item from user favorites
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} favoriteId - The unique identifier for the favorite item to remove
* @returns {Promise<void>} Promise resolving when the favorite item is removed
* @throws {Error} If the API request fails
*/
async remove(workspaceSlug: string, favoriteId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Retrieves all favorite items for a user in a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IFavorite[]>} Promise resolving to array of favorite items
* @throws {Error} If the API request fails
* @remarks This method includes the 'all' parameter to retrieve all favorites
*/
async list(workspaceSlug: string): Promise<IFavorite[]> {
return this.get(`/api/workspaces/${workspaceSlug}/user-favorites/`, {
params: {
all: true,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves grouped favorite items for a specific favorite in a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} favoriteId - The unique identifier for the favorite item to get grouped items for
* @returns {Promise<IFavorite[]>} Promise resolving to array of grouped favorite items
* @throws {Error} If the API request fails
*/
async groupedList(workspaceSlug: string, favoriteId: string): Promise<IFavorite[]> {
return this.get(`/api/workspaces/${workspaceSlug}/user-favorites/${favoriteId}/group/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

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

View File

@@ -0,0 +1,5 @@
export * from "./invitation.service";
export * from "./member.service";
export * from "./notification.service";
export * from "./view.service";
export * from "./workspace.service";

View File

@@ -0,0 +1,117 @@
import { API_BASE_URL } from "@plane/constants";
import { IWorkspaceMemberInvitation, IWorkspaceBulkInviteFormData, IWorkspaceMember } from "@plane/types";
import { APIService } from "@/api.service";
/**
* Service class for managing workspace invitations
* Handles operations related to inviting users to workspaces and managing invitations
* @extends {APIService}
*/
export class WorkspaceInvitationService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves all workspace invitations for the current user
* @returns {Promise<IWorkspaceMemberInvitation[]>} Promise resolving to array of workspace invitations
* @throws {Error} If the API request fails
*/
async userInvitations(): Promise<IWorkspaceMemberInvitation[]> {
return this.get("/api/users/me/workspaces/invitations/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves all invitations for a specific workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IWorkspaceMemberInvitation[]>} Promise resolving to array of workspace invitations
* @throws {Error} If the API request fails
*/
async workspaceInvitations(workspaceSlug: string): Promise<IWorkspaceMemberInvitation[]> {
return this.get(`/api/workspaces/${workspaceSlug}/invitations/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Sends bulk invitations to users for a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {IWorkspaceBulkInviteFormData} data - Bulk invitation data containing user information
* @returns {Promise<any>} Promise resolving to the invitation response
* @throws {Error} If the API request fails
*/
async invite(workspaceSlug: string, data: IWorkspaceBulkInviteFormData): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/invitations/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Update Invitation
* @param workspaceSlug
* @param invitationId
* @param data
* @returns
*/
async update(workspaceSlug: string, invitationId: string, data: Partial<IWorkspaceMember>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Delete Workspace invitation
* @param workspaceSlug
* @param invitationId
* @returns
*/
async destroy(workspaceSlug: string, invitationId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Accepts an invitation to join a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} invitationId - The unique identifier for the invitation
* @param {any} data - Additional data required for joining the workspace
* @returns {Promise<any>} Promise resolving to the join response
* @throws {Error} If the API request fails
*/
async join(workspaceSlug: string, invitationId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/join/`, data, {
headers: {},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Accepts multiple workspace invitations at once
* @param {any} data - Data containing information about invitations to accept
* @returns {Promise<any>} Promise resolving to the bulk join response
* @throws {Error} If the API request fails
*/
async joinMany(data: any): Promise<any> {
return this.post("/api/users/me/workspaces/invitations/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,92 @@
import { API_BASE_URL } from "@plane/constants";
import { IWorkspaceMemberMe, IWorkspaceMember, IUserProjectsRole } from "@plane/types";
import { APIService } from "../api.service";
/**
* Service class for managing workspace members
* Handles operations related to workspace membership, including member information,
* updates, deletions, and role management
* @extends {APIService}
*/
export class WorkspaceMemberService extends APIService {
/**
* Creates an instance of WorkspaceMemberService
* @param {string} baseUrl - The base URL for API requests
*/
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves current user's information for a specific workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IWorkspaceMemberMe>} Promise resolving to current user's workspace member information
* @throws {Error} If the API request fails
*/
async myInfo(workspaceSlug: string): Promise<IWorkspaceMemberMe> {
return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/me/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Retrieves all members of a specific workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IWorkspaceMember[]>} Promise resolving to array of workspace members
* @throws {Error} If the API request fails
*/
async list(workspaceSlug: string): Promise<IWorkspaceMember[]> {
return this.get(`/api/workspaces/${workspaceSlug}/members/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates a workspace member's information
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} memberId - The unique identifier for the member
* @param {Partial<IWorkspaceMember>} data - Updated member data
* @returns {Promise<IWorkspaceMember>} Promise resolving to the updated member information
* @throws {Error} If the API request fails
*/
async update(workspaceSlug: string, memberId: string, data: Partial<IWorkspaceMember>): Promise<IWorkspaceMember> {
return this.patch(`/api/workspaces/${workspaceSlug}/members/${memberId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Removes a member from a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {string} memberId - The unique identifier for the member to remove
* @returns {Promise<any>} Promise resolving to the deletion response
* @throws {Error} If the API request fails
*/
async destroy(workspaceSlug: string, memberId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/members/${memberId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves the current user's project roles within a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IUserProjectsRole>} Promise resolving to user's project roles
* @throws {Error} If the API request fails
*/
async getWorkspaceUserProjectsRole(workspaceSlug: string): Promise<IUserProjectsRole> {
return this.get(`/api/users/me/workspaces/${workspaceSlug}/project-roles/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,137 @@
import { API_BASE_URL } from "@plane/constants";
import {
TUnreadNotificationsCount,
TNotificationPaginatedInfo,
TNotification,
TNotificationPaginatedInfoQueryParams,
} from "@plane/types";
// services
import { APIService } from "../api.service";
export class WorkspaceNotificationService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves the count of unread notifications for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @returns {Promise<TUnreadNotificationsCount | undefined>} The count of unread notifications
*/
async getUnreadCount(workspaceSlug: string): Promise<TUnreadNotificationsCount | undefined> {
return this.get(`/api/workspaces/${workspaceSlug}/users/notifications/unread/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves paginated notifications for a workspace
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {TNotificationPaginatedInfoQueryParams} params - Query parameters for pagination and filtering
* @returns {Promise<TNotificationPaginatedInfo | undefined>} Paginated list of notifications
*/
async list(
workspaceSlug: string,
params: TNotificationPaginatedInfoQueryParams
): Promise<TNotificationPaginatedInfo | undefined> {
return this.get(`/api/workspaces/${workspaceSlug}/users/notifications`, { params })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates a specific notification by ID
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} notificationId - The unique identifier for the notification
* @param {Partial<TNotification>} data - The notification data to update
* @returns {Promise<TNotification | undefined>} The updated notification
*/
async update(
workspaceSlug: string,
notificationId: string,
data: Partial<TNotification>
): Promise<TNotification | undefined> {
return this.patch(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Marks a notification as read
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} notificationId - The unique identifier for the notification
* @returns {Promise<TNotification | undefined>} The updated notification
*/
async markAsRead(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Marks a notification as unread
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} notificationId - The unique identifier for the notification
* @returns {Promise<TNotification | undefined>} The updated notification
*/
async markAsUnread(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Archives a notification
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} notificationId - The unique identifier for the notification
* @returns {Promise<TNotification | undefined>} The updated notification
*/
async archive(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Unarchives a notification
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {string} notificationId - The unique identifier for the notification
* @returns {Promise<TNotification | undefined>} The updated notification
*/
async unarchive(workspaceSlug: string, notificationId: string): Promise<TNotification | undefined> {
return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Marks all notifications as read based on filter criteria
* @param {string} workspaceSlug - The unique identifier for the workspace
* @param {TNotificationPaginatedInfoQueryParams} data - Filter criteria for notifications to mark as read
* @returns {Promise<TNotification | undefined>} The result of the operation
*/
async markAllAsRead(
workspaceSlug: string,
data: TNotificationPaginatedInfoQueryParams
): Promise<TNotification | undefined> {
return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,67 @@
import { API_BASE_URL } from "@plane/constants";
import { IWorkspaceView, TIssuesResponse } from "@plane/types";
import { APIService } from "@/api.service";
export class WorkspaceViewService extends APIService {
/**
* Creates an instance of WorkspaceViewService
* @param {string} baseUrl - The base URL for API requests
*/
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
async create(workspaceSlug: string, data: Partial<IWorkspaceView>): Promise<IWorkspaceView> {
return this.post(`/api/workspaces/${workspaceSlug}/views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async update(workspaceSlug: string, viewId: string, data: Partial<IWorkspaceView>): Promise<IWorkspaceView> {
return this.patch(`/api/workspaces/${workspaceSlug}/views/${viewId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async destroy(workspaceSlug: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async list(workspaceSlug: string): Promise<IWorkspaceView[]> {
return this.get(`/api/workspaces/${workspaceSlug}/views/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieve(workspaceSlug: string, viewId: string): Promise<IWorkspaceView> {
return this.get(`/api/workspaces/${workspaceSlug}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getViewIssues(workspaceSlug: string, params: any, config = {}): Promise<TIssuesResponse> {
return this.get(
`/api/workspaces/${workspaceSlug}/issues/`,
{
params,
},
config
)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,141 @@
import { API_BASE_URL } from "@plane/constants";
import { IWorkspace, ILastActiveWorkspaceDetails, IWorkspaceSearchResults } from "@plane/types";
import { APIService } from "../api.service";
/**
* Service class for managing workspace operations
* Handles CRUD operations and various workspace-related functionalities
* @extends {APIService}
*/
export class WorkspaceService extends APIService {
/**
* Creates an instance of WorkspaceService
* @param {string} baseUrl - The base URL for API requests
*/
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves all workspaces for the current user
* @returns {Promise<IWorkspace[]>} Promise resolving to an array of workspaces
* @throws {Error} If the API request fails
*/
async list(): Promise<IWorkspace[]> {
return this.get("/api/users/me/workspaces/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves details of a specific workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<IWorkspace>} Promise resolving to workspace details
* @throws {Error} If the API request fails
*/
async retrieve(workspaceSlug: string): Promise<IWorkspace> {
return this.get(`/api/workspaces/${workspaceSlug}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Creates a new workspace
* @param {Partial<IWorkspace>} data - Workspace data for creation
* @returns {Promise<IWorkspace>} Promise resolving to the created workspace
* @throws {Error} If the API request fails
*/
async create(data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.post("/api/workspaces/", data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Updates an existing workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {Partial<IWorkspace>} data - Updated workspace data
* @returns {Promise<IWorkspace>} Promise resolving to the updated workspace
* @throws {Error} If the API request fails
*/
async update(workspaceSlug: string, data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.patch(`/api/workspaces/${workspaceSlug}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Deletes a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @returns {Promise<any>} Promise resolving to the deletion response
* @throws {Error} If the API request fails
*/
async destroy(workspaceSlug: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Retrieves information about the user's last visited workspace
* @returns {Promise<ILastActiveWorkspaceDetails>} Promise resolving to last active workspace details
* @throws {Error} If the API request fails
*/
async lastVisited(): Promise<ILastActiveWorkspaceDetails> {
return this.get("/api/users/last-visited-workspace/")
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Checks if a workspace slug is available
* @param {string} slug - The workspace slug to check
* @returns {Promise<any>} Promise resolving to slug availability status
* @throws {Error} If the API request fails
*/
async slugCheck(slug: string): Promise<any> {
return this.get(`/api/workspace-slug-check/?slug=${slug}`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
/**
* Searches within a workspace
* @param {string} workspaceSlug - The unique slug identifier for the workspace
* @param {Object} params - Search parameters
* @param {string} [params.project_id] - Optional project ID to scope the search
* @param {string} params.search - Search query string
* @param {boolean} params.workspace_search - Whether to search across the entire workspace
* @returns {Promise<IWorkspaceSearchResults>} Promise resolving to search results
* @throws {Error} If the API request fails
*/
async search(
workspaceSlug: string,
params: {
project_id?: string;
search: string;
workspace_search: boolean;
}
): Promise<IWorkspaceSearchResults> {
return this.get(`/api/workspaces/${workspaceSlug}/search/`, {
params,
})
.then((res) => res?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}

View File

@@ -0,0 +1,12 @@
{
"extends": "@plane/typescript-config/react-library.json",
"compilerOptions": {
"jsx": "react",
"lib": ["esnext", "dom"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["./src"],
"exclude": ["dist", "build", "node_modules"]
}