Compare commits

...
Author SHA1 Message Date
sriram veeraghanta 14601d0f36 fix: base url standardization 2025-08-30 22:50:49 +05:30
sriram veeraghanta 866eb5ac17 chore: service structure that scales 2025-08-28 02:27:11 +05:30
sriram veeraghantaandGitHub 0e6fbaee3a [WEB-4790] fix: moved typescript parser to the base eslint config (#7658)
* fix: moved typescript parser to the base eslint config

* fix: eslint warning

* fix: type config setting

* fix: convert live eslint to cjs
2025-08-27 21:03:20 +05:30
Anmol Singh BhatiaandGitHub cfe710d492 [WEB-4779] chore: app sidebar wrapper component for consistency and reusability (#7655)
* chore: app sidebar ui enhancements and code refactor

* chore: code refactor

* chore: code refactor
2025-08-27 20:46:43 +05:30
58 changed files with 516 additions and 254 deletions
+12
View File
@@ -0,0 +1,12 @@
.next/*
out/*
public/*
dist/*
node_modules/*
.turbo/*
.env*
.env
.env.local
.env.development
.env.production
.env.test
-1
View File
@@ -1,5 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
};
@@ -9,7 +9,7 @@ import { useInstance } from "@/hooks/store";
// components
import { InstanceEmailForm } from "./email-config-form";
const InstanceEmailPage = observer(() => {
const InstanceEmailPage: React.FC = observer(() => {
// store
const { fetchInstanceConfigurations, formattedConfig, disableEmail } = useInstance();
@@ -29,7 +29,7 @@ const InstanceEmailPage = observer(() => {
message: "Email feature has been disabled",
type: TOAST_TYPE.SUCCESS,
});
} catch (error) {
} catch (_error) {
setToast({
title: "Error disabling email",
message: "Failed to disable email feature. Please try again.",
@@ -25,9 +25,8 @@ export const EmailCodesConfiguration: React.FC<Props> = observer((props) => {
<ToggleSwitch
value={Boolean(parseInt(enableMagicLogin))}
onChange={() => {
Boolean(parseInt(enableMagicLogin)) === true
? updateConfig("ENABLE_MAGIC_LINK_LOGIN", "0")
: updateConfig("ENABLE_MAGIC_LINK_LOGIN", "1");
const newEnableMagicLogin = Boolean(parseInt(enableMagicLogin)) === true ? "0" : "1";
updateConfig("ENABLE_MAGIC_LINK_LOGIN", newEnableMagicLogin);
}}
size="sm"
disabled={disabled}
@@ -35,9 +35,8 @@ export const GithubConfiguration: React.FC<Props> = observer((props) => {
<ToggleSwitch
value={Boolean(parseInt(enableGithubConfig))}
onChange={() => {
Boolean(parseInt(enableGithubConfig)) === true
? updateConfig("IS_GITHUB_ENABLED", "0")
: updateConfig("IS_GITHUB_ENABLED", "1");
const newEnableGithubConfig = Boolean(parseInt(enableGithubConfig)) === true ? "0" : "1";
updateConfig("IS_GITHUB_ENABLED", newEnableGithubConfig);
}}
size="sm"
disabled={disabled}
@@ -35,9 +35,8 @@ export const GitlabConfiguration: React.FC<Props> = observer((props) => {
<ToggleSwitch
value={Boolean(parseInt(enableGitlabConfig))}
onChange={() => {
Boolean(parseInt(enableGitlabConfig)) === true
? updateConfig("IS_GITLAB_ENABLED", "0")
: updateConfig("IS_GITLAB_ENABLED", "1");
const newEnableGitlabConfig = Boolean(parseInt(enableGitlabConfig)) === true ? "0" : "1";
updateConfig("IS_GITLAB_ENABLED", newEnableGitlabConfig);
}}
size="sm"
disabled={disabled}
@@ -35,9 +35,8 @@ export const GoogleConfiguration: React.FC<Props> = observer((props) => {
<ToggleSwitch
value={Boolean(parseInt(enableGoogleConfig))}
onChange={() => {
Boolean(parseInt(enableGoogleConfig)) === true
? updateConfig("IS_GOOGLE_ENABLED", "0")
: updateConfig("IS_GOOGLE_ENABLED", "1");
const newEnableGoogleConfig = Boolean(parseInt(enableGoogleConfig)) === true ? "0" : "1";
updateConfig("IS_GOOGLE_ENABLED", newEnableGoogleConfig);
}}
size="sm"
disabled={disabled}
@@ -25,9 +25,8 @@ export const PasswordLoginConfiguration: React.FC<Props> = observer((props) => {
<ToggleSwitch
value={Boolean(parseInt(enableEmailPassword))}
onChange={() => {
Boolean(parseInt(enableEmailPassword)) === true
? updateConfig("ENABLE_EMAIL_PASSWORD", "0")
: updateConfig("ENABLE_EMAIL_PASSWORD", "1");
const newEnableEmailPassword = Boolean(parseInt(enableEmailPassword)) === true ? "0" : "1";
updateConfig("ENABLE_EMAIL_PASSWORD", newEnableEmailPassword);
}}
size="sm"
disabled={disabled}
+1 -1
View File
@@ -209,7 +209,7 @@ export class InstanceStore implements IInstanceStore {
});
});
await this.instanceService.disableEmail();
} catch (error) {
} catch (_error) {
console.error("Error disabling the email");
this.instanceConfigurations = instanceConfigurations;
}
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/server.js"],
};
-5
View File
@@ -1,5 +0,0 @@
{
"root": true,
"extends": ["@plane/eslint-config/server.js"],
"parser": "@typescript-eslint/parser"
}
+4 -7
View File
@@ -1,20 +1,17 @@
// Third-party libraries
import { Redis } from "ioredis";
// Hocuspocus extensions and core
import { Database } from "@hocuspocus/extension-database";
import { Extension } from "@hocuspocus/server";
import { Logger } from "@hocuspocus/extension-logger";
import { Redis as HocusPocusRedis } from "@hocuspocus/extension-redis";
import { Extension } from "@hocuspocus/server";
import { Redis } from "ioredis";
// core helpers and utilities
import { manualLogger } from "@/core/helpers/logger.js";
import { getRedisUrl } from "@/core/lib/utils/redis-url.js";
// core libraries
import { fetchPageDescriptionBinary, updatePageDescription } from "@/core/lib/page.js";
import { getRedisUrl } from "@/core/lib/utils/redis-url.js";
import { type HocusPocusServerContext, type TDocumentTypes } from "@/core/types/common.js";
// plane live libraries
import { fetchDocument } from "@/plane-live/lib/fetch-document.js";
import { updateDocument } from "@/plane-live/lib/update-document.js";
// types
import { type HocusPocusServerContext, type TDocumentTypes } from "@/core/types/common.js";
export const getExtensions: () => Promise<Extension[]> = async () => {
const extensions: Extension[] = [
+5 -5
View File
@@ -1,12 +1,12 @@
import { Server } from "@hocuspocus/server";
import { v4 as uuidv4 } from "uuid";
// lib
import { handleAuthentication } from "@/core/lib/authentication.js";
// extensions
import { getExtensions } from "@/core/extensions/index.js";
import { DocumentCollaborativeEvents, TDocumentEventsServer } from "@plane/editor/lib";
// editor types
import { TUserDetails } from "@plane/editor";
import { DocumentCollaborativeEvents, TDocumentEventsServer } from "@plane/editor/lib";
// extensions
import { getExtensions } from "@/core/extensions/index.js";
// lib
import { handleAuthentication } from "@/core/lib/authentication.js";
// types
import { type HocusPocusServerContext } from "@/core/types/common.js";
+2 -2
View File
@@ -1,7 +1,7 @@
// services
import { UserService } from "@/core/services/user.service.js";
// core helpers
import { manualLogger } from "@/core/helpers/logger.js";
// services
import { UserService } from "@/core/services/user.service.js";
const userService = new UserService();
+2 -2
View File
@@ -1,13 +1,13 @@
import compression from "compression";
import cors from "cors";
import expressWs from "express-ws";
import express, { Request, Response } from "express";
import expressWs from "express-ws";
import helmet from "helmet";
// hocuspocus server
import { getHocusPocusServer } from "@/core/hocuspocus-server.js";
// helpers
import { convertHTMLDocumentToAllFormats } from "@/core/helpers/convert-document.js";
import { logger, manualLogger } from "@/core/helpers/logger.js";
import { getHocusPocusServer } from "@/core/hocuspocus-server.js";
// types
import { TConvertDocumentRequestBody } from "@/core/types/common.js";
+12
View File
@@ -0,0 +1,12 @@
.next/*
out/*
public/*
dist/*
node_modules/*
.turbo/*
.env*
.env
.env.local
.env.development
.env.production
.env.test
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
};
+10 -1
View File
@@ -1,4 +1,13 @@
.next/*
out/*
public/*
core/local-db/worker/wa-sqlite/src/*
core/local-db/worker/wa-sqlite/src/*
dist/*
node_modules/*
.turbo/*
.env*
.env
.env.local
.env.development
.env.production
.env.test
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
};
@@ -1,36 +1,24 @@
import { FC, useEffect, useRef } from "react";
import { FC } from "react";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react";
// plane helpers
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useOutsideClickDetector } from "@plane/hooks";
// components
import { AppSidebarToggleButton } from "@/components/sidebar/sidebar-toggle-button";
import { SidebarDropdown } from "@/components/workspace/sidebar/dropdown";
import { SidebarWrapper } from "@/components/sidebar/sidebar-wrapper";
import { SidebarFavoritesMenu } from "@/components/workspace/sidebar/favorites/favorites-menu";
import { HelpMenu } from "@/components/workspace/sidebar/help-menu";
import { SidebarProjectsList } from "@/components/workspace/sidebar/projects-list";
import { SidebarQuickActions } from "@/components/workspace/sidebar/quick-actions";
import { SidebarMenuItems } from "@/components/workspace/sidebar/sidebar-menu-items";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { useFavorite } from "@/hooks/store/use-favorite";
import { useUserPermissions } from "@/hooks/store/user";
import { useAppRail } from "@/hooks/use-app-rail";
import useSize from "@/hooks/use-window-size";
// plane web components
import { WorkspaceEditionBadge } from "@/plane-web/components/workspace/edition-badge";
import { SidebarTeamsList } from "@/plane-web/components/workspace/sidebar/teams-sidebar-list";
export const AppSidebar: FC = observer(() => {
// store hooks
const { allowPermissions } = useUserPermissions();
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
const { shouldRenderAppRail, isEnabled: isAppRailEnabled } = useAppRail();
const { groupedFavorites } = useFavorite();
const windowSize = useSize();
// refs
const ref = useRef<HTMLDivElement>(null);
// derived values
const canPerformWorkspaceMemberActions = allowPermissions(
@@ -38,55 +26,17 @@ export const AppSidebar: FC = observer(() => {
EUserPermissionsLevel.WORKSPACE
);
useOutsideClickDetector(ref, () => {
if (sidebarCollapsed === false) {
if (window.innerWidth < 768) {
toggleSidebar();
}
}
});
useEffect(() => {
if (windowSize[0] < 768 && !sidebarCollapsed) toggleSidebar();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [windowSize]);
const isFavoriteEmpty = isEmpty(groupedFavorites);
return (
<>
<div className="flex flex-col gap-3 px-3">
{/* Workspace switcher and settings */}
{!shouldRenderAppRail && <SidebarDropdown />}
{isAppRailEnabled && (
<div className="flex items-center justify-between gap-2">
<span className="text-md text-custom-text-200 font-medium pt-1">Projects</span>
<div className="flex items-center gap-2">
<AppSidebarToggleButton />
</div>
</div>
)}
{/* Quick actions */}
<SidebarQuickActions />
</div>
<div className="flex flex-col gap-3 overflow-x-hidden scrollbar-sm h-full w-full overflow-y-auto vertical-scrollbar px-3 pt-3 pb-0.5">
<SidebarMenuItems />
{/* Favorites Menu */}
{canPerformWorkspaceMemberActions && !isFavoriteEmpty && <SidebarFavoritesMenu />}
{/* Teams List */}
<SidebarTeamsList />
{/* Projects List */}
<SidebarProjectsList />
</div>
{/* Help Section */}
<div className="flex items-center justify-between p-3 border-t border-custom-border-200 bg-custom-sidebar-background-100 h-12">
<WorkspaceEditionBadge />
<div className="flex items-center gap-2">
{!shouldRenderAppRail && <HelpMenu />}
{!isAppRailEnabled && <AppSidebarToggleButton />}
</div>
</div>
</>
<SidebarWrapper title="Projects" quickActions={<SidebarQuickActions />}>
<SidebarMenuItems />
{/* Favorites Menu */}
{canPerformWorkspaceMemberActions && !isFavoriteEmpty && <SidebarFavoritesMenu />}
{/* Teams List */}
<SidebarTeamsList />
{/* Projects List */}
<SidebarProjectsList />
</SidebarWrapper>
);
});
@@ -0,0 +1,72 @@
import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/hooks";
// components
import { AppSidebarToggleButton } from "@/components/sidebar/sidebar-toggle-button";
import { SidebarDropdown } from "@/components/workspace/sidebar/dropdown";
import { HelpMenu } from "@/components/workspace/sidebar/help-menu";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { useAppRail } from "@/hooks/use-app-rail";
import useSize from "@/hooks/use-window-size";
// plane web components
import { WorkspaceEditionBadge } from "@/plane-web/components/workspace/edition-badge";
type TSidebarWrapperProps = {
title: string;
children: React.ReactNode;
quickActions?: React.ReactNode;
};
export const SidebarWrapper: FC<TSidebarWrapperProps> = observer((props) => {
const { children, title, quickActions } = props;
// store hooks
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
const { shouldRenderAppRail, isEnabled: isAppRailEnabled } = useAppRail();
const windowSize = useSize();
// refs
const ref = useRef<HTMLDivElement>(null);
useOutsideClickDetector(ref, () => {
if (sidebarCollapsed === false && window.innerWidth < 768) {
toggleSidebar();
}
});
useEffect(() => {
if (windowSize[0] < 768 && !sidebarCollapsed) toggleSidebar();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [windowSize]);
return (
<div ref={ref} className="flex flex-col h-full w-full">
<div className="flex flex-col gap-3 px-3">
{/* Workspace switcher and settings */}
{!shouldRenderAppRail && <SidebarDropdown />}
{isAppRailEnabled && (
<div className="flex items-center justify-between gap-2">
<span className="text-md text-custom-text-200 font-medium pt-1">{title}</span>
<div className="flex items-center gap-2">
<AppSidebarToggleButton />
</div>
</div>
)}
{/* Quick actions */}
{quickActions}
</div>
<div className="flex flex-col gap-3 overflow-x-hidden scrollbar-sm h-full w-full overflow-y-auto vertical-scrollbar px-3 pt-3 pb-0.5">
{children}
</div>
{/* Help Section */}
<div className="flex items-center justify-between p-3 border-t border-custom-border-200 bg-custom-sidebar-background-100 h-12">
<WorkspaceEditionBadge />
<div className="flex items-center gap-2">
{!shouldRenderAppRail && <HelpMenu />}
{!isAppRailEnabled && <AppSidebarToggleButton />}
</div>
</div>
</div>
);
});
+4
View File
@@ -0,0 +1,4 @@
node_modules
build/*
dist/*
out/*
@@ -1,5 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+4
View File
@@ -0,0 +1,4 @@
node_modules
build/*
dist/*
out/*
-1
View File
@@ -1,5 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+5 -4
View File
@@ -5,6 +5,7 @@ const project = resolve(process.cwd(), "tsconfig.json");
/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: ["prettier", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["react", "react-hooks", "@typescript-eslint", "import"],
globals: {
React: true,
@@ -43,10 +44,10 @@ module.exports = {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-useless-empty-export": "error",
+6 -5
View File
@@ -3,6 +3,8 @@ const project = resolve(process.cwd(), "tsconfig.json");
module.exports = {
extends: ["next", "prettier", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["react", "@typescript-eslint", "import"],
globals: {
React: "readonly",
JSX: "readonly",
@@ -11,7 +13,6 @@ module.exports = {
node: true,
browser: true,
},
plugins: ["react", "@typescript-eslint", "import"],
settings: {
"import/resolver": {
typescript: {
@@ -42,10 +43,10 @@ module.exports = {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-useless-empty-export": "error",
+29 -5
View File
@@ -3,6 +3,7 @@ const project = resolve(process.cwd(), "tsconfig.json");
module.exports = {
extends: ["prettier", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
env: {
node: true,
es6: true,
@@ -25,10 +26,33 @@ module.exports = {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
}
"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,
},
},
],
},
};
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+2 -2
View File
@@ -5,7 +5,7 @@ export const getValueFromLocalStorage = (key: string, defaultValue: any) => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
} catch (_error) {
window.localStorage.removeItem(key);
return defaultValue;
}
@@ -16,7 +16,7 @@ export const setValueIntoLocalStorage = (key: string, value: any) => {
try {
window.localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
} catch (_error) {
return false;
}
};
-5
View File
@@ -1,9 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
};
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
-2
View File
@@ -1,8 +1,6 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js", "plugin:storybook/recommended"],
parser: "@typescript-eslint/parser",
rules: {
"import/order": [
"warn",
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
@@ -0,0 +1,30 @@
import { TProjectPublishSettings } from "@plane/types";
import { APIService } from "../api.service";
/**
* Service class for managing project publish operations within plane core application.
* Extends APIService to handle HTTP requests to the project publish-related endpoints.
* @extends {APIService}
* @remarks This service is only available for plane core
*/
export abstract class CoreProjectPublishService extends APIService {
constructor(BASE_URL: string) {
super(BASE_URL);
}
async retrieve(workspaceSlug: string, projectID: string): Promise<TProjectPublishSettings> {
return this.get(`/api/public/workspaces/${workspaceSlug}/projects/${projectID}/anchor/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async retrieveSettings(anchor: string): Promise<TProjectPublishSettings> {
return this.get(`/api/public/anchor/${anchor}/settings/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}
@@ -0,0 +1,7 @@
import { CoreProjectPublishService } from "./core.service";
export abstract class ExtendedProjectPublishService extends CoreProjectPublishService {
constructor(baseUrl: string) {
super(baseUrl);
}
}
@@ -0,0 +1,8 @@
import { API_BASE_URL } from "@plane/constants";
import { ExtendedProjectPublishService } from "./extended.service";
export class ProjectPublishService extends ExtendedProjectPublishService {
constructor() {
super(API_BASE_URL);
}
}
@@ -0,0 +1,72 @@
import { IProjectView } from "@plane/types";
import { APIService } from "../api.service";
export class CoreProjectViewService extends APIService {
constructor(baseUrl: string) {
super(baseUrl);
}
async create(workspaceSlug: string, projectId: string, data: Partial<IProjectView>): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async update(workspaceSlug: string, projectId: string, viewId: string, data: Partial<IProjectView>): Promise<any> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async destroy(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async list(workspaceSlug: string, projectId: string): Promise<IProjectView[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieve(workspaceSlug: string, projectId: string, viewId: string): Promise<IProjectView> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getWorksItems(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/issues/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async addToFavorites(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/`, { view: viewId })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async removeFromFavorites(workspaceSlug: string, projectId: string, viewId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/${viewId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
@@ -0,0 +1,7 @@
import { CoreProjectViewService } from "./core.service";
export class ExtendedProjectViewService extends CoreProjectViewService {
constructor(baseUrl: string) {
super(baseUrl);
}
}
@@ -0,0 +1,8 @@
import { API_BASE_URL } from "@plane/constants";
import { ExtendedProjectViewService } from "./extended.service";
export class ProjectViewService extends ExtendedProjectViewService {
constructor(baseUrl?: string) {
super(baseUrl || API_BASE_URL);
}
}
@@ -0,0 +1,86 @@
import { TProject, TProjectAnalyticsCountParams, TProjectAnalyticsCount } from "@plane/types";
import { APIService } from "../api.service";
export class CoreProjectService extends APIService {
constructor(BASE_URL: string) {
super(BASE_URL);
}
async create(workspaceSlug: string, data: Partial<TProject>): Promise<TProject> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
async checkIdentifierAvailability(workspaceSlug: string, identifier: string): Promise<any> {
return this.get(`/api/workspaces/${workspaceSlug}/project-identifiers/`, {
params: {
name: identifier,
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
list(workspaceSlug: string): Promise<TProject[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
retrieve(workspaceSlug: string, projectId: string): Promise<TProject> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
stats(workspaceSlug: string, params?: TProjectAnalyticsCountParams): Promise<TProjectAnalyticsCount[]> {
return this.get(`/api/workspaces/${workspaceSlug}/project-stats/`, {
params,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
update(workspaceSlug: string, projectId: string, data: Partial<TProject>): Promise<TProject> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
destroy(workspaceSlug: string, projectId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
addToFavorites(workspaceSlug: string, project: string): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/user-favorite-projects/`, { project })
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
removeFromFavorites(workspaceSlug: string, projectId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/user-favorite-projects/${projectId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
@@ -0,0 +1,7 @@
import { CoreProjectService } from "./core.service";
export class ExtendedProjectService extends CoreProjectService {
constructor(BASE_URL: string) {
super(BASE_URL);
}
}
+8 -2
View File
@@ -1,2 +1,8 @@
export * from "./view.service";
export * from "./sites-publish.service";
import { API_BASE_URL } from "@plane/constants";
import { ExtendedProjectService } from "./extended.service";
export class ProjectService extends ExtendedProjectService {
constructor() {
super(API_BASE_URL);
}
}
@@ -1,46 +0,0 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import { TProjectPublishSettings } from "@plane/types";
// api service
import { APIService } from "../api.service";
/**
* Service class for managing project publish operations within plane sites application.
* Extends APIService to handle HTTP requests to the project publish-related endpoints.
* @extends {APIService}
* @remarks This service is only available for plane sites
*/
export class SitesProjectPublishService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves publish settings for a specific anchor.
* @param {string} anchor - The anchor identifier
* @returns {Promise<TProjectPublishSettings>} The publish settings
* @throws {Error} If the API request fails
*/
async retrieveSettingsByAnchor(anchor: string): Promise<TProjectPublishSettings> {
return this.get(`/api/public/anchor/${anchor}/settings/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
/**
* Retrieves publish settings for a specific project.
* @param {string} workspaceSlug - The workspace slug
* @param {string} projectID - The project identifier
* @returns {Promise<TProjectPublishSettings>} The publish settings
* @throws {Error} If the API request fails
*/
async retrieveSettingsByProjectId(workspaceSlug: string, projectID: string): Promise<TProjectPublishSettings> {
return this.get(`/api/public/workspaces/${workspaceSlug}/projects/${projectID}/anchor/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response;
});
}
}
@@ -1,14 +0,0 @@
// 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);
}
}
@@ -0,0 +1,56 @@
import { IState } from "@plane/types";
import { APIService } from "../api.service";
export class CoreStateService extends APIService {
constructor(baseUrl: string) {
super(baseUrl);
}
async anchorStates(anchor: string): Promise<IState[]> {
return this.get(`/api/public/anchor/${anchor}/states/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async list(workspaceSlug: string, projectId: string): Promise<IState[]> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async retrieve(workspaceSlug: string, projectId: string, stateId: string): Promise<IState> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async create(workspaceSlug: string, projectId: string, data: Partial<IState>): Promise<IState> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async update(workspaceSlug: string, projectId: string, stateId: string, data: Partial<IState>): Promise<IState> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, data)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async destroy(workspaceSlug: string, projectId: string, stateId: string): Promise<IState> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
@@ -0,0 +1,7 @@
import { CoreStateService } from "./core.service";
export class ExtendedStateService extends CoreStateService {
constructor(baseUrl: string) {
super(baseUrl);
}
}
+8 -1
View File
@@ -1 +1,8 @@
export * from "./sites-state.service";
import { API_BASE_URL } from "@plane/constants";
import { ExtendedStateService } from "./extended.service";
export class StateService extends ExtendedStateService {
constructor() {
super(API_BASE_URL);
}
}
@@ -1,31 +0,0 @@
// plane imports
import { API_BASE_URL } from "@plane/constants";
import { IState } from "@plane/types";
// api service
import { APIService } from "../api.service";
/**
* Service class for managing states within plane sites application.
* Extends APIService to handle HTTP requests to the state-related endpoints.
* @extends {APIService}
* @remarks This service is only available for plane sites
*/
export class SitesStateService extends APIService {
constructor(BASE_URL?: string) {
super(BASE_URL || API_BASE_URL);
}
/**
* Retrieves a list of states for a specific anchor.
* @param {string} anchor - The anchor identifier
* @returns {Promise<IState[]>} The list of states
* @throws {Error} If the API request fails
*/
async list(anchor: string): Promise<IState[]> {
return this.get(`/api/public/anchor/${anchor}/states/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
}
-5
View File
@@ -1,9 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
};
-1
View File
@@ -1,5 +1,4 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+3
View File
@@ -0,0 +1,3 @@
build/*
dist/*
out/*
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+1 -1
View File
@@ -60,7 +60,7 @@ export const AuthForm: React.FC<AuthFormProps> = ({
});
const [passwordStrength, setPasswordStrength] = useState<E_PASSWORD_STRENGTH>(E_PASSWORD_STRENGTH.EMPTY);
const [passwordsMatch, setPasswordsMatch] = useState(false);
const [_passwordsMatch, setPasswordsMatch] = useState(false);
const handleInputChange = (field: keyof AuthFormData) => (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData((prev) => ({
+1
View File
@@ -8,6 +8,7 @@ import { cn } from "./utils";
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const Calendar = ({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) => {
const currentYear = new Date().getFullYear();
const thirtyYearsAgoFirstDay = new Date(currentYear - 30, 0, 1);
-2
View File
@@ -1,6 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
};
+10 -10
View File
@@ -846,7 +846,7 @@ importers:
version: 2.31.0(@typescript-eslint/parser@8.40.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
eslint-plugin-react:
specifier: ^7.33.2
version: 7.37.5(eslint@8.57.1)
version: 7.37.3(eslint@8.57.1)
eslint-plugin-react-hooks:
specifier: ^5.2.0
version: 5.2.0(eslint@8.57.1)
@@ -1071,7 +1071,7 @@ importers:
version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.13.3(@swc/helpers@0.5.17))(@types/node@22.17.2)(typescript@5.8.3)))
autoprefixer:
specifier: ^10.4.14
version: 10.4.21(postcss@8.5.6)
version: 10.4.20(postcss@8.5.6)
postcss:
specifier: ^8.4.38
version: 8.5.6
@@ -1243,7 +1243,7 @@ importers:
version: 18.3.1
autoprefixer:
specifier: ^10.4.19
version: 10.4.21(postcss@8.5.6)
version: 10.4.20(postcss@8.5.6)
postcss-cli:
specifier: ^11.0.0
version: 11.0.1(jiti@1.21.7)(postcss@8.5.6)
@@ -3865,8 +3865,8 @@ packages:
peerDependencies:
postcss: ^8.1.0
autoprefixer@10.4.21:
resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
autoprefixer@10.4.20:
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
@@ -4738,8 +4738,8 @@ packages:
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
eslint-plugin-react@7.37.5:
resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
eslint-plugin-react@7.37.3:
resolution: {integrity: sha512-DomWuTQPFYZwF/7c9W2fkKkStqZmBd3uugfqBYLdkZ3Hii23WzZuOLUskGxB8qkSKqftxEeGL1TB2kMhrce0jA==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
@@ -10722,7 +10722,7 @@ snapshots:
postcss: 8.5.6
postcss-value-parser: 4.2.0
autoprefixer@10.4.21(postcss@8.5.6):
autoprefixer@10.4.20(postcss@8.5.6):
dependencies:
browserslist: 4.25.2
caniuse-lite: 1.0.30001735
@@ -11607,7 +11607,7 @@ snapshots:
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.40.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
eslint-plugin-react: 7.37.3(eslint@8.57.1)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1)
optionalDependencies:
typescript: 5.8.3
@@ -11715,7 +11715,7 @@ snapshots:
dependencies:
eslint: 8.57.1
eslint-plugin-react@7.37.5(eslint@8.57.1):
eslint-plugin-react@7.37.3(eslint@8.57.1):
dependencies:
array-includes: 3.1.9
array.prototype.findlast: 1.2.5