From 200be0ac7facd87d7ca032018ef51367dc4bde4e Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 7 Jan 2025 19:07:47 +0530 Subject: [PATCH] [WEB-3065] refactor: replace admin services with service packages (#6342) * [WEB-3065] refactor: replace admin services with service packages * chore: minor updates * chore: error handling --- admin/app/email/test-email-modal.tsx | 4 +- admin/app/workspace/create/form.tsx | 12 ++- .../admin-sidebar/sidebar-dropdown.tsx | 3 +- admin/core/components/instance/setup-form.tsx | 3 +- admin/core/components/login/sign-in-form.tsx | 3 +- admin/core/services/api.service.ts | 53 ----------- admin/core/services/auth.service.ts | 21 ----- admin/core/services/instance.service.ts | 72 --------------- admin/core/services/user.service.ts | 29 ------ admin/core/services/workspace.service.ts | 52 ----------- admin/core/store/instance.store.ts | 13 ++- admin/core/store/user.store.ts | 6 +- admin/core/store/workspace.store.ts | 14 +-- admin/package.json | 1 + packages/services/src/ai/ai.service.ts | 2 +- packages/services/src/auth/auth.service.ts | 2 +- .../src/cycle/cycle-analytics.service.ts | 2 +- .../src/cycle/cycle-archive.service.ts | 2 +- .../src/cycle/cycle-operations.service.ts | 2 +- packages/services/src/cycle/cycle.service.ts | 2 +- .../src/developer/api-token.service.ts | 2 +- .../services/src/instance/instance.service.ts | 89 +++++++++++++++++-- .../services/src/intake/intake.service.ts | 2 +- packages/services/src/intake/issue.service.ts | 2 +- packages/services/src/module/link.service.ts | 2 +- .../services/src/module/module.service.ts | 2 +- .../services/src/module/operations.service.ts | 2 +- packages/services/src/project/index.ts | 2 +- packages/services/src/project/view.service.ts | 14 +++ .../services/src/user/favorite.service.ts | 2 +- packages/services/src/user/index.ts | 1 + packages/services/src/user/user.service.ts | 33 +++++++ packages/services/src/workspace/index.ts | 1 + .../workspace/instance-workspace.service.ts | 65 ++++++++++++++ .../src/workspace/invitation.service.ts | 2 +- .../services/src/workspace/view.service.ts | 2 +- packages/services/tsconfig.json | 3 - 37 files changed, 240 insertions(+), 284 deletions(-) delete mode 100644 admin/core/services/api.service.ts delete mode 100644 admin/core/services/auth.service.ts delete mode 100644 admin/core/services/instance.service.ts delete mode 100644 admin/core/services/user.service.ts delete mode 100644 admin/core/services/workspace.service.ts create mode 100644 packages/services/src/user/user.service.ts create mode 100644 packages/services/src/workspace/instance-workspace.service.ts diff --git a/admin/app/email/test-email-modal.tsx b/admin/app/email/test-email-modal.tsx index 6d5cb8032..676f3b685 100644 --- a/admin/app/email/test-email-modal.tsx +++ b/admin/app/email/test-email-modal.tsx @@ -1,9 +1,9 @@ import React, { FC, useEffect, useState } from "react"; import { Dialog, Transition } from "@headlessui/react"; +// plane imports +import { InstanceService } from "@plane/services"; // ui import { Button, Input } from "@plane/ui"; -// services -import { InstanceService } from "@/services/instance.service"; type Props = { isOpen: boolean; diff --git a/admin/app/workspace/create/form.tsx b/admin/app/workspace/create/form.tsx index 2a7eda207..d086777fc 100644 --- a/admin/app/workspace/create/form.tsx +++ b/admin/app/workspace/create/form.tsx @@ -2,18 +2,16 @@ import { useState, useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Controller, useForm } from "react-hook-form"; -// constants +// plane imports import { WEB_BASE_URL, ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constants"; -// types +import { InstanceWorkspaceService } from "@plane/services"; import { IWorkspace } from "@plane/types"; // components import { Button, CustomSelect, getButtonStyling, Input, setToast, TOAST_TYPE } from "@plane/ui"; // hooks import { useWorkspace } from "@/hooks/store"; -// services -import { WorkspaceService } from "@/services/workspace.service"; -const workspaceService = new WorkspaceService(); +const instanceWorkspaceService = new InstanceWorkspaceService(); export const WorkspaceCreateForm = () => { // router @@ -40,8 +38,8 @@ export const WorkspaceCreateForm = () => { const workspaceBaseURL = encodeURI(WEB_BASE_URL || window.location.origin + "/"); const handleCreateWorkspace = async (formData: IWorkspace) => { - await workspaceService - .workspaceSlugCheck(formData.slug) + await instanceWorkspaceService + .slugCheck(formData.slug) .then(async (res) => { if (res.status === true && !RESTRICTED_URLS.includes(formData.slug)) { setSlugError(false); diff --git a/admin/core/components/admin-sidebar/sidebar-dropdown.tsx b/admin/core/components/admin-sidebar/sidebar-dropdown.tsx index f34372413..501d501d8 100644 --- a/admin/core/components/admin-sidebar/sidebar-dropdown.tsx +++ b/admin/core/components/admin-sidebar/sidebar-dropdown.tsx @@ -7,12 +7,11 @@ import { LogOut, UserCog2, Palette } from "lucide-react"; import { Menu, Transition } from "@headlessui/react"; // plane internal packages import { API_BASE_URL } from "@plane/constants"; +import {AuthService } from "@plane/services"; import { Avatar } from "@plane/ui"; import { getFileURL, cn } from "@plane/utils"; // hooks import { useTheme, useUser } from "@/hooks/store"; -// services -import { AuthService } from "@/services/auth.service"; // service initialization const authService = new AuthService(); diff --git a/admin/core/components/instance/setup-form.tsx b/admin/core/components/instance/setup-form.tsx index f033ce42e..ccbc557ba 100644 --- a/admin/core/components/instance/setup-form.tsx +++ b/admin/core/components/instance/setup-form.tsx @@ -6,12 +6,11 @@ import { useSearchParams } from "next/navigation"; import { Eye, EyeOff } from "lucide-react"; // plane internal packages import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants"; +import { AuthService } from "@plane/services"; import { Button, Checkbox, Input, Spinner } from "@plane/ui"; import { getPasswordStrength } from "@plane/utils"; // components import { Banner, PasswordStrengthMeter } from "@/components/common"; -// services -import { AuthService } from "@/services/auth.service"; // service initialization const authService = new AuthService(); diff --git a/admin/core/components/login/sign-in-form.tsx b/admin/core/components/login/sign-in-form.tsx index af1ba077e..986e5cebe 100644 --- a/admin/core/components/login/sign-in-form.tsx +++ b/admin/core/components/login/sign-in-form.tsx @@ -5,13 +5,12 @@ import { useSearchParams } from "next/navigation"; import { Eye, EyeOff } from "lucide-react"; // plane internal packages import { API_BASE_URL, EAdminAuthErrorCodes, TAuthErrorInfo } from "@plane/constants"; +import { AuthService } from "@plane/services"; import { Button, Input, Spinner } from "@plane/ui"; // components import { Banner } from "@/components/common"; // helpers import { authErrorHandler } from "@/lib/auth-helpers"; -// services -import { AuthService } from "@/services/auth.service"; // local components import { AuthBanner } from "../authentication"; diff --git a/admin/core/services/api.service.ts b/admin/core/services/api.service.ts deleted file mode 100644 index fa45c10b7..000000000 --- a/admin/core/services/api.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; -// store -// import { rootStore } from "@/lib/store-context"; - -export abstract class APIService { - protected baseURL: string; - private axiosInstance: AxiosInstance; - - constructor(baseURL: string) { - this.baseURL = baseURL; - this.axiosInstance = axios.create({ - baseURL, - withCredentials: true, - }); - - this.setupInterceptors(); - } - - private setupInterceptors() { - // this.axiosInstance.interceptors.response.use( - // (response) => response, - // (error) => { - // const store = rootStore; - // if (error.response && error.response.status === 401 && store.user.currentUser) store.user.reset(); - // return Promise.reject(error); - // } - // ); - } - - get(url: string, params = {}): Promise> { - return this.axiosInstance.get(url, { params }); - } - - post(url: string, data: RequestType, config = {}): Promise> { - return this.axiosInstance.post(url, data, config); - } - - put(url: string, data: RequestType, config = {}): Promise> { - return this.axiosInstance.put(url, data, config); - } - - patch(url: string, data: RequestType, config = {}): Promise> { - return this.axiosInstance.patch(url, data, config); - } - - delete(url: string, data?: RequestType, config = {}) { - return this.axiosInstance.delete(url, { data, ...config }); - } - - request(config: AxiosRequestConfig = {}): Promise> { - return this.axiosInstance(config); - } -} diff --git a/admin/core/services/auth.service.ts b/admin/core/services/auth.service.ts deleted file mode 100644 index a47fd8396..000000000 --- a/admin/core/services/auth.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { API_BASE_URL } from "@plane/constants"; -// services -import { APIService } from "@/services/api.service"; - -type TCsrfTokenResponse = { - csrf_token: string; -}; - -export class AuthService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async requestCSRFToken(): Promise { - return this.get("/auth/get-csrf-token/") - .then((response) => response.data) - .catch((error) => { - throw error; - }); - } -} diff --git a/admin/core/services/instance.service.ts b/admin/core/services/instance.service.ts deleted file mode 100644 index 510a780d7..000000000 --- a/admin/core/services/instance.service.ts +++ /dev/null @@ -1,72 +0,0 @@ -// plane internal packages -import { API_BASE_URL } from "@plane/constants"; -import type { - IFormattedInstanceConfiguration, - IInstance, - IInstanceAdmin, - IInstanceConfiguration, - IInstanceInfo, -} from "@plane/types"; -// helpers -import { APIService } from "@/services/api.service"; - -export class InstanceService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async getInstanceInfo(): Promise { - return this.get("/api/instances/") - .then((response) => response.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - 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, IInstance>("/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, IInstanceConfiguration[]>( - "/api/instances/configurations/", - data - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async sendTestEmail(receiverEmail: string): Promise { - return this.post<{ receiver_email: string }, undefined>("/api/instances/email-credentials-check/", { - receiver_email: receiverEmail, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/admin/core/services/user.service.ts b/admin/core/services/user.service.ts deleted file mode 100644 index 74ef2a81b..000000000 --- a/admin/core/services/user.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -// plane internal packages -import { API_BASE_URL } from "@plane/constants"; -import type { IUser } from "@plane/types"; -// services -import { APIService } from "@/services/api.service"; - -interface IUserSession extends IUser { - isAuthenticated: boolean; -} - -export class UserService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async authCheck(): Promise { - return this.get("/api/instances/admins/me/") - .then((response) => ({ ...response?.data, isAuthenticated: true })) - .catch(() => ({ isAuthenticated: false })); - } - - async currentUser(): Promise { - return this.get("/api/instances/admins/me/") - .then((response) => response?.data) - .catch((error) => { - throw error?.response; - }); - } -} diff --git a/admin/core/services/workspace.service.ts b/admin/core/services/workspace.service.ts deleted file mode 100644 index 787ad4269..000000000 --- a/admin/core/services/workspace.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -// plane internal packages -import { API_BASE_URL } from "@plane/constants"; -import type { IWorkspace, TWorkspacePaginationInfo } from "@plane/types"; -// services -import { APIService } from "@/services/api.service"; - -export class WorkspaceService extends APIService { - constructor() { - super(API_BASE_URL); - } - - /** - * @description Fetches all workspaces - * @returns Promise - */ - async getWorkspaces(nextPageCursor?: string): Promise { - return this.get("/api/instances/workspaces/", { - cursor: nextPageCursor, - }) - .then((response) => response.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - /** - * @description Checks if a slug is available - * @param slug - string - * @returns Promise - */ - async workspaceSlugCheck(slug: string): Promise { - const params = new URLSearchParams({ slug }); - return this.get(`/api/instances/workspace-slug-check/?${params.toString()}`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - /** - * @description Creates a new workspace - * @param data - IWorkspace - * @returns Promise - */ - async createWorkspace(data: IWorkspace): Promise { - return this.post("/api/instances/workspaces/", data) - .then((response) => response.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/admin/core/store/instance.store.ts b/admin/core/store/instance.store.ts index 0daadb1fc..9b25a2469 100644 --- a/admin/core/store/instance.store.ts +++ b/admin/core/store/instance.store.ts @@ -2,6 +2,7 @@ import set from "lodash/set"; import { observable, action, computed, makeObservable, runInAction } from "mobx"; // plane internal packages import { EInstanceStatus, TInstanceStatus } from "@plane/constants"; +import {InstanceService} from "@plane/services"; import { IInstance, IInstanceAdmin, @@ -10,8 +11,6 @@ import { IInstanceInfo, IInstanceConfig, } from "@plane/types"; -// services -import { InstanceService } from "@/services/instance.service"; // root store import { CoreRootStore } from "@/store/root.store"; @@ -96,7 +95,7 @@ export class InstanceStore implements IInstanceStore { try { if (this.instance === undefined) this.isLoading = true; this.error = undefined; - const instanceInfo = await this.instanceService.getInstanceInfo(); + const instanceInfo = await this.instanceService.info(); // handling the new user popup toggle if (this.instance === undefined && !instanceInfo?.instance?.workspaces_exist) this.store.theme.toggleNewUserPopup(); @@ -125,7 +124,7 @@ export class InstanceStore implements IInstanceStore { */ updateInstanceInfo = async (data: Partial) => { try { - const instanceResponse = await this.instanceService.updateInstanceInfo(data); + const instanceResponse = await this.instanceService.update(data); if (instanceResponse) { runInAction(() => { if (this.instance) set(this.instance, "instance", instanceResponse); @@ -144,7 +143,7 @@ export class InstanceStore implements IInstanceStore { */ fetchInstanceAdmins = async () => { try { - const instanceAdmins = await this.instanceService.getInstanceAdmins(); + const instanceAdmins = await this.instanceService.admins(); if (instanceAdmins) runInAction(() => (this.instanceAdmins = instanceAdmins)); return instanceAdmins; } catch (error) { @@ -159,7 +158,7 @@ export class InstanceStore implements IInstanceStore { */ fetchInstanceConfigurations = async () => { try { - const instanceConfigurations = await this.instanceService.getInstanceConfigurations(); + const instanceConfigurations = await this.instanceService.configurations(); if (instanceConfigurations) runInAction(() => (this.instanceConfigurations = instanceConfigurations)); return instanceConfigurations; } catch (error) { @@ -174,7 +173,7 @@ export class InstanceStore implements IInstanceStore { */ updateInstanceConfigurations = async (data: Partial) => { try { - const response = await this.instanceService.updateInstanceConfigurations(data); + const response = await this.instanceService.updateConfigurations(data); runInAction(() => { this.instanceConfigurations = this.instanceConfigurations?.map((config) => { const item = response.find((item) => item.key === config.key); diff --git a/admin/core/store/user.store.ts b/admin/core/store/user.store.ts index 7f56c0523..85c56495b 100644 --- a/admin/core/store/user.store.ts +++ b/admin/core/store/user.store.ts @@ -1,10 +1,8 @@ import { action, observable, runInAction, makeObservable } from "mobx"; // plane internal packages import { EUserStatus, TUserStatus } from "@plane/constants"; +import { AuthService, UserService } from "@plane/services"; import { IUser } from "@plane/types"; -// services -import { AuthService } from "@/services/auth.service"; -import { UserService } from "@/services/user.service"; // root store import { CoreRootStore } from "@/store/root.store"; @@ -58,7 +56,7 @@ export class UserStore implements IUserStore { fetchCurrentUser = async () => { try { if (this.currentUser === undefined) this.isLoading = true; - const currentUser = await this.userService.currentUser(); + const currentUser = await this.userService.adminDetails(); if (currentUser) { await this.store.instance.fetchInstanceAdmins(); runInAction(() => { diff --git a/admin/core/store/workspace.store.ts b/admin/core/store/workspace.store.ts index f892e14f0..64f7501d3 100644 --- a/admin/core/store/workspace.store.ts +++ b/admin/core/store/workspace.store.ts @@ -1,8 +1,8 @@ import set from "lodash/set"; import { action, observable, runInAction, makeObservable, computed } from "mobx"; +// plane imports +import { InstanceWorkspaceService } from "@plane/services"; import { IWorkspace, TLoader, TPaginationInfo } from "@plane/types"; -// services -import { WorkspaceService } from "@/services/workspace.service"; // root store import { CoreRootStore } from "@/store/root.store"; @@ -29,7 +29,7 @@ export class WorkspaceStore implements IWorkspaceStore { workspaces: Record = {}; paginationInfo: TPaginationInfo | undefined = undefined; // services - workspaceService; + instanceWorkspaceService; constructor(private store: CoreRootStore) { makeObservable(this, { @@ -48,7 +48,7 @@ export class WorkspaceStore implements IWorkspaceStore { // curd actions createWorkspace: action, }); - this.workspaceService = new WorkspaceService(); + this.instanceWorkspaceService = new InstanceWorkspaceService(); } // computed @@ -84,7 +84,7 @@ export class WorkspaceStore implements IWorkspaceStore { } else { this.loader = "init-loader"; } - const paginatedWorkspaceData = await this.workspaceService.getWorkspaces(); + const paginatedWorkspaceData = await this.instanceWorkspaceService.list(); runInAction(() => { const { results, ...paginationInfo } = paginatedWorkspaceData; results.forEach((workspace: IWorkspace) => { @@ -109,7 +109,7 @@ export class WorkspaceStore implements IWorkspaceStore { if (!this.paginationInfo || this.paginationInfo.next_page_results === false) return []; try { this.loader = "pagination"; - const paginatedWorkspaceData = await this.workspaceService.getWorkspaces(this.paginationInfo.next_cursor); + const paginatedWorkspaceData = await this.instanceWorkspaceService.list(this.paginationInfo.next_cursor); runInAction(() => { const { results, ...paginationInfo } = paginatedWorkspaceData; results.forEach((workspace: IWorkspace) => { @@ -135,7 +135,7 @@ export class WorkspaceStore implements IWorkspaceStore { createWorkspace = async (data: IWorkspace): Promise => { try { this.loader = "mutation"; - const workspace = await this.workspaceService.createWorkspace(data); + const workspace = await this.instanceWorkspaceService.create(data); runInAction(() => { set(this.workspaces, [workspace.id], workspace); }); diff --git a/admin/package.json b/admin/package.json index e2fe4cf33..f3cd40f4d 100644 --- a/admin/package.json +++ b/admin/package.json @@ -18,6 +18,7 @@ "@plane/types": "*", "@plane/ui": "*", "@plane/utils": "*", + "@plane/services": "*", "@sentry/nextjs": "^8.32.0", "@tailwindcss/typography": "^0.5.9", "@types/lodash": "^4.17.0", diff --git a/packages/services/src/ai/ai.service.ts b/packages/services/src/ai/ai.service.ts index 6a3b3c637..261cf9df5 100644 --- a/packages/services/src/ai/ai.service.ts +++ b/packages/services/src/ai/ai.service.ts @@ -1,7 +1,7 @@ // plane web constants import { AI_EDITOR_TASKS, API_BASE_URL } from "@plane/constants"; // services -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Payload type for AI editor tasks diff --git a/packages/services/src/auth/auth.service.ts b/packages/services/src/auth/auth.service.ts index 87e75e536..a45100940 100644 --- a/packages/services/src/auth/auth.service.ts +++ b/packages/services/src/auth/auth.service.ts @@ -9,7 +9,7 @@ import { APIService } from "../api.service"; * Provides methods for user authentication, password management, and session handling * @extends {APIService} */ -export default class AuthService extends APIService { +export class AuthService extends APIService { /** * Creates an instance of AuthService * Initializes with the base API URL diff --git a/packages/services/src/cycle/cycle-analytics.service.ts b/packages/services/src/cycle/cycle-analytics.service.ts index 4897926a9..c9e14441e 100644 --- a/packages/services/src/cycle/cycle-analytics.service.ts +++ b/packages/services/src/cycle/cycle-analytics.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import type { TCycleDistribution, TProgressSnapshot, TCycleEstimateDistribution } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for managing cycles within a workspace and project context. diff --git a/packages/services/src/cycle/cycle-archive.service.ts b/packages/services/src/cycle/cycle-archive.service.ts index 8c40f0a29..784fd32e7 100644 --- a/packages/services/src/cycle/cycle-archive.service.ts +++ b/packages/services/src/cycle/cycle-archive.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import { ICycle } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for managing archived cycles in a project diff --git a/packages/services/src/cycle/cycle-operations.service.ts b/packages/services/src/cycle/cycle-operations.service.ts index 3e6f32cd9..43c01396c 100644 --- a/packages/services/src/cycle/cycle-operations.service.ts +++ b/packages/services/src/cycle/cycle-operations.service.ts @@ -1,5 +1,5 @@ import { API_BASE_URL } from "@plane/constants"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export class CycleOperationsService extends APIService { constructor(BASE_URL?: string) { diff --git a/packages/services/src/cycle/cycle.service.ts b/packages/services/src/cycle/cycle.service.ts index c697c2da4..961e5588a 100644 --- a/packages/services/src/cycle/cycle.service.ts +++ b/packages/services/src/cycle/cycle.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import type { CycleDateCheckData, ICycle, TIssuesResponse, IWorkspaceActiveCyclesResponse } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for managing cycles within a workspace and project context. diff --git a/packages/services/src/developer/api-token.service.ts b/packages/services/src/developer/api-token.service.ts index 92ee523ea..74dc9135d 100644 --- a/packages/services/src/developer/api-token.service.ts +++ b/packages/services/src/developer/api-token.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import { IApiToken } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export class APITokenService extends APIService { constructor(BASE_URL?: string) { diff --git a/packages/services/src/instance/instance.service.ts b/packages/services/src/instance/instance.service.ts index 0ffe451fb..23cc0150d 100644 --- a/packages/services/src/instance/instance.service.ts +++ b/packages/services/src/instance/instance.service.ts @@ -1,13 +1,22 @@ +// plane imports import { API_BASE_URL } from "@plane/constants"; -import type { IInstanceInfo, TPage } from "@plane/types"; -import { APIService } from "@/api.service"; +import type { + IFormattedInstanceConfiguration, + IInstance, + IInstanceAdmin, + IInstanceConfiguration, + IInstanceInfo, + TPage, +} from "@plane/types"; +// api service +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 { +export class InstanceService extends APIService { /** * Creates an instance of InstanceService * Initializes the service with the base API URL @@ -25,7 +34,7 @@ export default class InstanceService extends APIService { return this.get("/api/instances/") .then((response) => response.data) .catch((error) => { - throw error; + throw error?.response?.data; }); } @@ -38,7 +47,77 @@ export default class InstanceService extends APIService { return this.get("/api/instances/changelog/") .then((response) => response.data) .catch((error) => { - throw error; + throw error?.response?.data; + }); + } + + /** + * Fetches the list of instance admins + * @returns {Promise} Promise resolving to an array of instance admins + * @throws {Error} If the API request fails + */ + async admins(): Promise { + return this.get("/api/instances/admins/") + .then((response) => response.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + /** + * Updates the instance information + * @param {Partial} data Data to update the instance with + * @returns {Promise} Promise resolving to the updated instance information + * @throws {Error} If the API request fails + */ + async update(data: Partial): Promise { + return this.patch("/api/instances/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + /** + * Fetches the list of instance configurations + * @returns {Promise} Promise resolving to an array of instance configurations + * @throws {Error} If the API request fails + */ + async configurations(): Promise { + return this.get("/api/instances/configurations/") + .then((response) => response.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + /** + * Updates the instance configurations + * @param {Partial} data Data to update the instance configurations with + * @returns {Promise} The updated instance configurations + * @throws {Error} If the API request fails + */ + async updateConfigurations(data: Partial): Promise { + return this.patch("/api/instances/configurations/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + /** + * Sends a test email to the specified receiver to test SMTP configuration + * @param {string} receiverEmail Email address to send the test email to + * @returns {Promise} Promise resolving to void + * @throws {Error} If the API request fails + */ + async sendTestEmail(receiverEmail: string): Promise { + return this.post("/api/instances/email-credentials-check/", { + receiver_email: receiverEmail, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; }); } } diff --git a/packages/services/src/intake/intake.service.ts b/packages/services/src/intake/intake.service.ts index 1f7f72295..1c4a93c18 100644 --- a/packages/services/src/intake/intake.service.ts +++ b/packages/services/src/intake/intake.service.ts @@ -1,5 +1,5 @@ import { API_BASE_URL } from "@plane/constants"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export default class IntakeService extends APIService { constructor(BASE_URL?: string) { diff --git a/packages/services/src/intake/issue.service.ts b/packages/services/src/intake/issue.service.ts index 37e1f81dc..b48328df4 100644 --- a/packages/services/src/intake/issue.service.ts +++ b/packages/services/src/intake/issue.service.ts @@ -1,5 +1,5 @@ import { API_BASE_URL } from "@plane/constants"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export default class IntakeIssueService extends APIService { constructor(BASE_URL?: string) { diff --git a/packages/services/src/module/link.service.ts b/packages/services/src/module/link.service.ts index 0caee9e19..8c8ec3f47 100644 --- a/packages/services/src/module/link.service.ts +++ b/packages/services/src/module/link.service.ts @@ -1,7 +1,7 @@ // types import type { ILinkDetails, ModuleLink } from "@plane/types"; // services -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for handling module link related operations. diff --git a/packages/services/src/module/module.service.ts b/packages/services/src/module/module.service.ts index 1d1732aa9..21321b36e 100644 --- a/packages/services/src/module/module.service.ts +++ b/packages/services/src/module/module.service.ts @@ -1,7 +1,7 @@ // types import type { IModule, ILinkDetails, ModuleLink, TIssuesResponse } from "@plane/types"; // services -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export class ModuleService extends APIService { constructor(baseURL: string) { diff --git a/packages/services/src/module/operations.service.ts b/packages/services/src/module/operations.service.ts index b8fddb37d..9185873da 100644 --- a/packages/services/src/module/operations.service.ts +++ b/packages/services/src/module/operations.service.ts @@ -1,7 +1,7 @@ // types // import type { IModule, ILinkDetails, ModuleLink, TIssuesResponse } from "@plane/types"; // services -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export class ModuleOperationService extends APIService { constructor(baseURL: string) { diff --git a/packages/services/src/project/index.ts b/packages/services/src/project/index.ts index 6ec55d7f7..a470a7328 100644 --- a/packages/services/src/project/index.ts +++ b/packages/services/src/project/index.ts @@ -1 +1 @@ -export * from "./view.service"; +export * from "./view.service"; \ No newline at end of file diff --git a/packages/services/src/project/view.service.ts b/packages/services/src/project/view.service.ts index e69de29bb..7eef71911 100644 --- a/packages/services/src/project/view.service.ts +++ b/packages/services/src/project/view.service.ts @@ -0,0 +1,14 @@ +// plane imports +import { API_BASE_URL } from "@plane/constants"; +// api services +import { APIService } from "../api.service"; + +export class ProjectViewService extends APIService { + /** + * Creates an instance of ProjectViewService + * @param {string} baseUrl - The base URL for API requests + */ + constructor(BASE_URL?: string) { + super(BASE_URL || API_BASE_URL); + } +} diff --git a/packages/services/src/user/favorite.service.ts b/packages/services/src/user/favorite.service.ts index 7e838a3c6..0c6e0497f 100644 --- a/packages/services/src/user/favorite.service.ts +++ b/packages/services/src/user/favorite.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import type { IFavorite } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for managing user favorites diff --git a/packages/services/src/user/index.ts b/packages/services/src/user/index.ts index 41df23a17..c738d93ee 100644 --- a/packages/services/src/user/index.ts +++ b/packages/services/src/user/index.ts @@ -1 +1,2 @@ export * from "./favorite.service"; +export * from "./user.service"; diff --git a/packages/services/src/user/user.service.ts b/packages/services/src/user/user.service.ts new file mode 100644 index 000000000..7f956683f --- /dev/null +++ b/packages/services/src/user/user.service.ts @@ -0,0 +1,33 @@ +// plane imports +import { API_BASE_URL } from "@plane/constants"; +import type { IUser } from "@plane/types"; +// api service +import { APIService } from "../api.service"; + +/** + * Service class for managing user operations + * Handles operations for retrieving the current user's details and perform CRUD operations + * @extends {APIService} + */ +export class UserService extends APIService { + /** + * Constructor for UserService + * @param BASE_URL - Base URL for API requests + */ + constructor(BASE_URL?: string) { + super(BASE_URL || API_BASE_URL); + } + + /** + * Retrieves the current instance admin details + * @returns {Promise} Promise resolving to the current instance admin details + * @throws {Error} If the API request fails + */ + async adminDetails(): Promise { + return this.get("/api/instances/admins/me/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/src/workspace/index.ts b/packages/services/src/workspace/index.ts index 4076a51f5..a48efdee2 100644 --- a/packages/services/src/workspace/index.ts +++ b/packages/services/src/workspace/index.ts @@ -3,3 +3,4 @@ export * from "./member.service"; export * from "./notification.service"; export * from "./view.service"; export * from "./workspace.service"; +export * from "./instance-workspace.service"; diff --git a/packages/services/src/workspace/instance-workspace.service.ts b/packages/services/src/workspace/instance-workspace.service.ts new file mode 100644 index 000000000..7ac3d4ce4 --- /dev/null +++ b/packages/services/src/workspace/instance-workspace.service.ts @@ -0,0 +1,65 @@ +import { API_BASE_URL } from "@plane/constants"; +import type { IWorkspace, TWorkspacePaginationInfo } from "@plane/types"; +import { APIService } from "../api.service"; + +/** + * Service class for managing instance workspaces + * Handles CRUD operations on instance workspaces + * @extends APIService + */ +export class InstanceWorkspaceService extends APIService { + /** + * Constructor for InstanceWorkspaceService + * @param BASE_URL - Base URL for API requests + */ + constructor(BASE_URL?: string) { + super(BASE_URL || API_BASE_URL); + } + + /** + * Retrieves a paginated list of workspaces for the current instance + * @param {string} nextPageCursor - Optional cursor to retrieve the next page of results + * @returns {Promise} Promise resolving to a paginated list of workspaces + * @throws {Error} If the API request fails + */ + async list(nextPageCursor?: string): Promise { + return this.get(`/api/instances/workspaces/`, { + params: { + cursor: nextPageCursor, + }, + }) + .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} Promise resolving to slug availability status + * @throws {Error} If the API request fails + */ + async slugCheck(slug: string): Promise { + const params = new URLSearchParams({ slug }); + return this.get(`/api/instances/workspace-slug-check/?${params.toString()}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + /** + * Creates a new workspace + * @param {Partial} data - Workspace data for creation + * @returns {Promise} Promise resolving to the created workspace + * @throws {Error} If the API request fails + */ + async create(data: Partial): Promise { + return this.post("/api/instances/workspaces/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/services/src/workspace/invitation.service.ts b/packages/services/src/workspace/invitation.service.ts index fa3446020..46088371f 100644 --- a/packages/services/src/workspace/invitation.service.ts +++ b/packages/services/src/workspace/invitation.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import { IWorkspaceMemberInvitation, IWorkspaceBulkInviteFormData, IWorkspaceMember } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; /** * Service class for managing workspace invitations diff --git a/packages/services/src/workspace/view.service.ts b/packages/services/src/workspace/view.service.ts index ca782d433..0ea21f742 100644 --- a/packages/services/src/workspace/view.service.ts +++ b/packages/services/src/workspace/view.service.ts @@ -1,6 +1,6 @@ import { API_BASE_URL } from "@plane/constants"; import { IWorkspaceView, TIssuesResponse } from "@plane/types"; -import { APIService } from "@/api.service"; +import { APIService } from "../api.service"; export class WorkspaceViewService extends APIService { /** diff --git a/packages/services/tsconfig.json b/packages/services/tsconfig.json index 0c2f64d1a..efce2a9fe 100644 --- a/packages/services/tsconfig.json +++ b/packages/services/tsconfig.json @@ -3,9 +3,6 @@ "compilerOptions": { "jsx": "react", "lib": ["esnext", "dom"], - "paths": { - "@/*": ["./src/*"] - } }, "include": ["./src"], "exclude": ["dist", "build", "node_modules"]