fix: linting issues and rule changes (#5681)

* fix: lint config package updates

* fix: tsconfig changes

* fix: lint config setup

* fix: lint errors and adding new rules

* fix: lint errors

* fix: ui and editor lints

* fix: build error

* fix: editor tsconfig

* fix: lint errors

* fix: types fixes

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
sriram veeraghanta
2024-09-23 17:10:38 +05:30
committed by GitHub
parent e143e0a051
commit 83bfca6f2d
75 changed files with 1583 additions and 2631 deletions

View File

@@ -1,59 +0,0 @@
/**
* Adds three new lint plugins over the existing configuration:
* This is used to lint staged files only.
* We should remove this file once the entire codebase follows these rules.
*/
module.exports = {
root: true,
extends: [
"custom",
],
parser: "@typescript-eslint/parser",
settings: {
"import/resolver": {
typescript: {},
node: {
moduleDirectory: ["node_modules", "."],
},
},
},
rules: {
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@headlessui/**",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
},
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
},
};

View File

@@ -1,10 +0,0 @@
module.exports = {
root: true,
// This tells ESLint to load the config from the package `eslint-config-custom`
extends: ["custom"],
settings: {
next: {
rootDir: ["web/", "space/", "admin/"],
},
},
};

View File

View File

@@ -1,3 +0,0 @@
{
"*.{ts,tsx,js,jsx}": ["eslint -c ./.eslintrc-staged.js", "prettier --check"]
}

View File

@@ -1,52 +1,8 @@
module.exports = {
root: true,
extends: ["custom"],
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
settings: {
"import/resolver": {
typescript: {},
node: {
moduleDirectory: ["node_modules", "."],
},
},
parserOptions: {
project: true,
},
rules: {
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling",],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@headlessui/**",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
}
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
},
}
};

View File

@@ -9,9 +9,7 @@ import { HelpSection, SidebarMenu, SidebarDropdown } from "@/components/admin-si
// hooks
import { useTheme } from "@/hooks/store";
export interface IInstanceSidebar {}
export const InstanceSidebar: FC<IInstanceSidebar> = observer(() => {
export const InstanceSidebar: FC = observer(() => {
// store
const { isSidebarCollapsed, toggleSidebar } = useTheme();

View File

@@ -7,11 +7,7 @@ import { Button } from "@plane/ui";
import InstanceFailureDarkImage from "@/public/instance/instance-failure-dark.svg";
import InstanceFailureImage from "@/public/instance/instance-failure.svg";
type InstanceFailureViewProps = {
// mutate: () => void;
};
export const InstanceFailureView: FC<InstanceFailureViewProps> = () => {
export const InstanceFailureView: FC = () => {
const { resolvedTheme } = useTheme();
const instanceImage = resolvedTheme === "dark" ? InstanceFailureDarkImage : InstanceFailureImage;

View File

@@ -1,5 +1,5 @@
// helpers
import { API_BASE_URL } from "helpers/common.helper";
import { API_BASE_URL } from "@/helpers/common.helper";
// services
import { APIService } from "@/services/api.service";

View File

@@ -1,7 +1,7 @@
// helpers
import { API_BASE_URL } from "helpers/common.helper";
// types
import type { IUser } from "@plane/types";
// helpers
import { API_BASE_URL } from "@/helpers/common.helper";
// services
import { APIService } from "@/services/api.service";

View File

@@ -8,7 +8,8 @@
"build": "next build",
"preview": "next build && next start",
"start": "next start",
"lint": "next lint"
"lint": "eslint . --ext .ts,.tsx",
"lint:errors": "eslint . --ext .ts,.tsx --quiet"
},
"dependencies": {
"@headlessui/react": "^1.7.19",
@@ -43,9 +44,9 @@
"@types/react-dom": "^18.2.18",
"@types/uuid": "^9.0.8",
"@types/zxcvbn": "^4.4.4",
"eslint-config-custom": "*",
"@plane/eslint-config": "*",
"tailwind-config-custom": "*",
"tsconfig": "*",
"typescript": "5.4.5"
"@plane/typescript-config": "*",
"typescript": "5.3.3"
}
}

View File

@@ -1,21 +1,15 @@
{
"extends": "tsconfig/nextjs.json",
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"],
"extends": "@plane/typescript-config/nextjs.json",
"compilerOptions": {
"plugins": [{ "name": "next" }],
"baseUrl": ".",
"jsx": "preserve",
"esModuleInterop": true,
"paths": {
"@/*": ["core/*"],
"@/helpers/*": ["helpers/*"],
"@/public/*": ["public/*"],
"@/plane-admin/*": ["ce/*"]
},
"plugins": [
{
"name": "next"
}
]
}
}
},
"include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

4
live/.eslintignore Normal file
View File

@@ -0,0 +1,4 @@
.turbo/*
out/*
dist/*
public/*

8
live/.eslintrc.json Normal file
View File

@@ -0,0 +1,8 @@
{
"root": true,
"extends": ["@plane/eslint-config/server.js"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": true
}
}

View File

@@ -7,7 +7,9 @@
"type": "module",
"scripts": {
"build": "babel src --out-dir dist --extensions \".ts,.js\"",
"start": "node dist/server.js"
"start": "node dist/server.js",
"lint": "eslint . --ext .ts,.tsx",
"lint:errors": "eslint . --ext .ts,.tsx --quiet"
},
"keywords": [],
"author": "",
@@ -55,6 +57,6 @@
"nodemon": "^3.1.0",
"ts-node": "^10.9.2",
"tsup": "^7.2.0",
"typescript": "5.4.5"
"typescript": "5.3.3"
}
}

View File

@@ -1,2 +1 @@
// eslint-disable-next-line @typescript-eslint/ban-types
export type TAdditionalDocumentTypes = {}
export type TAdditionalDocumentTypes = {};

View File

@@ -45,7 +45,8 @@ export const getExtensions: () => Promise<Extension[]> = async () => {
const documentType = params.get("documentType")?.toString() as
| TDocumentTypes
| undefined;
// TODO: Fix this lint error.
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
try {
let fetchedData = null;
@@ -53,7 +54,7 @@ export const getExtensions: () => Promise<Extension[]> = async () => {
fetchedData = await fetchPageDescriptionBinary(
params,
pageId,
cookie,
cookie
);
} else {
fetchedData = await fetchDocument({
@@ -83,6 +84,8 @@ export const getExtensions: () => Promise<Extension[]> = async () => {
| TDocumentTypes
| undefined;
// TODO: Fix this lint error.
// eslint-disable-next-line no-async-promise-executor
return new Promise(async () => {
try {
if (documentType === "project_page") {
@@ -121,7 +124,7 @@ export const getExtensions: () => Promise<Extension[]> = async () => {
}
manualLogger.warn(
`Redis Client wasn't able to connect, continuing without Redis (you won't be able to sync data between multiple plane live servers)`,
error,
error
);
reject(error);
});
@@ -135,12 +138,12 @@ export const getExtensions: () => Promise<Extension[]> = async () => {
} catch (error) {
manualLogger.warn(
`Redis Client wasn't able to connect, continuing without Redis (you won't be able to sync data between multiple plane live servers)`,
error,
error
);
}
} else {
manualLogger.warn(
"Redis URL is not set, continuing without Redis (you won't be able to sync data between multiple plane live servers)",
"Redis URL is not set, continuing without Redis (you won't be able to sync data between multiple plane live servers)"
);
}

View File

@@ -1,7 +1,7 @@
import { ErrorRequestHandler } from "express";
import { manualLogger } from "@/core/helpers/logger.js";
export const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {
export const errorHandler: ErrorRequestHandler = (err, _req, res) => {
// Log the error
manualLogger.error(err);

View File

@@ -1,43 +1,26 @@
{
"extends": "tsconfig/base.json",
"extends": "@plane/typescript-config/base.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": [
"ES2015"
],
"lib": ["ES2015"],
"outDir": "./dist",
"rootDir": "./src",
"rootDir": ".",
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
],
"@/plane-live/*": [
"./src/ce/*"
]
"@/*": ["./src/*"],
"@/plane-live/*": ["./src/ce/*"]
},
"removeComments": true,
"esModuleInterop": true,
"skipLibCheck": true,
"sourceMap": true,
"inlineSources": true,
// Set `sourceRoot` to "/" to strip the build path prefix
// from generated source code references.
// This improves issue grouping in Sentry.
"sourceRoot": "/"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"./dist",
"./build",
"./node_modules"
]
"include": ["src/**/*.ts", "tsup.config.ts"],
"exclude": ["./dist", "./build", "./node_modules"]
}

View File

@@ -8,34 +8,20 @@
"space",
"admin",
"live",
"packages/editor",
"packages/eslint-config-custom",
"packages/tailwind-config-custom",
"packages/tsconfig",
"packages/ui",
"packages/types",
"packages/constants",
"packages/helpers"
"packages/*"
],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev --concurrency=13",
"start": "turbo run start",
"lint": "turbo run lint",
"lint:errors": "turbo run lint:errors",
"clean": "turbo run clean",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"prepare": "husky"
"format": "prettier --write \"**/*.{ts,tsx,md}\""
},
"devDependencies": {
"autoprefixer": "^10.4.15",
"eslint-config-custom": "*",
"eslint-plugin-prettier": "^5.1.3",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"postcss": "^8.4.29",
"prettier": "latest",
"prettier-plugin-tailwindcss": "^0.5.4",
"tailwindcss": "^3.3.3",
"turbo": "^2.1.1"
},
"resolutions": {

View File

@@ -1,38 +1,9 @@
module.exports = {
root: true,
extends: ["custom"],
rules: {
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
},
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
rules: {},
};

View File

@@ -26,6 +26,7 @@
"build": "tsup --minify",
"dev": "tsup --watch",
"check-types": "tsc --noEmit",
"lint": "eslint src --ext .ts,.tsx",
"format": "prettier --write \"**/*.{ts,tsx,md}\""
},
"peerDependencies": {
@@ -74,12 +75,12 @@
"@types/node": "18.15.3",
"@types/react": "^18.2.42",
"@types/react-dom": "^18.2.17",
"eslint-config-custom": "*",
"@plane/eslint-config": "*",
"postcss": "^8.4.38",
"tailwind-config-custom": "*",
"tsconfig": "*",
"@plane/typescript-config": "*",
"tsup": "^7.2.0",
"typescript": "5.4.5"
"typescript": "5.3.3"
},
"keywords": [
"editor",

View File

@@ -23,7 +23,6 @@ export const AIFeaturesMenu: React.FC<Props> = (props) => {
menuRef.current.remove();
menuRef.current.style.visibility = "visible";
// @ts-expect-error - tippy types are incorrect
popup.current = tippy(document.body, {
getReferenceClientRect: null,
content: menuRef.current,

View File

@@ -34,7 +34,6 @@ export const BlockMenu = (props: BlockMenuProps) => {
menuRef.current.remove();
menuRef.current.style.visibility = "visible";
// @ts-expect-error - tippy types are incorrect
popup.current = tippy(document.body, {
getReferenceClientRect: null,
content: menuRef.current,

View File

@@ -117,14 +117,18 @@ export function LowlightPlugin({
// Such transactions can happen during collab syncing via y-prosemirror, for example.
transaction.steps.some(
(step) =>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
step.from !== undefined &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
step.to !== undefined &&
oldNodes.some(
(node) =>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node.pos >= step.from &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node.pos + node.node.nodeSize <= step.to
)

View File

@@ -1,6 +1,7 @@
// TODO: fix all warnings
/* eslint-disable react/display-name */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { useEffect, useState } from "react";
import { NodeViewWrapper } from "@tiptap/react";

View File

@@ -198,6 +198,7 @@ function createToolbox({
onSelectColor: (color: { backgroundColor: string; textColor: string }) => void;
colors: { [key: string]: { backgroundColor: string; textColor: string; icon?: string } };
}): Instance<Props> {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const toolbox = tippy(triggerButton, {
content: h(

View File

@@ -204,11 +204,8 @@ export const Table = Node.create({
({ tr, dispatch }) => {
if (dispatch) {
const selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell);
// @ts-ignore
tr.setSelection(selection);
}
return true;
},
};
@@ -247,7 +244,7 @@ export const Table = Node.create({
return ({ editor, getPos, node, decorations }) => {
const { cellMinWidth } = this.options;
return new TableView(node, cellMinWidth, decorations, editor, getPos as () => number);
return new TableView(node, cellMinWidth, decorations as any, editor, getPos as () => number);
};
},
@@ -267,8 +264,6 @@ export const Table = Node.create({
handleWidth: this.options.handleWidth,
cellMinWidth: this.options.cellMinWidth,
// View: TableView,
// @ts-ignore
lastColumnResizable: this.options.lastColumnResizable,
})
);

View File

@@ -82,7 +82,7 @@ export const useEditor = (props: CustomEditorProps) => {
},
mentionConfig: {
mentionSuggestions: mentionHandler.suggestions ?? (() => Promise.resolve<IMentionSuggestion[]>([])),
mentionHighlights: mentionHandler.highlights ?? [],
mentionHighlights: mentionHandler.highlights,
},
placeholder,
tabIndex,
@@ -170,9 +170,7 @@ export const useEditor = (props: CustomEditorProps) => {
editorRef.current?.off("update");
};
},
getHeadings: () => {
return editorRef?.current?.storage.headingList.headings;
},
getHeadings: () => editorRef?.current?.storage.headingList.headings,
onStateChange: (callback: () => void) => {
// Subscribe to editor state changes
editorRef.current?.on("transaction", () => {
@@ -263,13 +261,11 @@ export const useEditor = (props: CustomEditorProps) => {
editorRef.current.chain().focus().deleteRange({ from, to }).insertContent(contentHTML).run();
}
},
getDocumentInfo: () => {
return {
characters: editorRef?.current?.storage?.characterCount?.characters?.() ?? 0,
paragraphs: getParagraphCount(editorRef?.current?.state),
words: editorRef?.current?.storage?.characterCount?.words?.() ?? 0,
};
},
getDocumentInfo: () => ({
characters: editorRef?.current?.storage?.characterCount?.characters?.() ?? 0,
paragraphs: getParagraphCount(editorRef?.current?.state),
words: editorRef?.current?.storage?.characterCount?.words?.() ?? 0,
}),
setProviderDocument: (value) => {
const document = provider?.document;
if (!document) return;

View File

@@ -95,13 +95,11 @@ export const useReadOnlyEditor = (props: CustomReadOnlyEditorProps) => {
if (!editorRef.current) return;
scrollSummary(editorRef.current, marking);
},
getDocumentInfo: () => {
return {
characters: editorRef?.current?.storage?.characterCount?.characters?.() ?? 0,
paragraphs: getParagraphCount(editorRef?.current?.state),
words: editorRef?.current?.storage?.characterCount?.words?.() ?? 0,
};
},
getDocumentInfo: () => ({
characters: editorRef?.current?.storage?.characterCount?.characters?.() ?? 0,
paragraphs: getParagraphCount(editorRef?.current?.state),
words: editorRef?.current?.storage?.characterCount?.words?.() ?? 0,
}),
onHeadingChange: (callback: (headings: IMarking[]) => void) => {
// Subscribe to update event emitted from headers extension
editorRef.current?.on("update", () => {
@@ -114,9 +112,7 @@ export const useReadOnlyEditor = (props: CustomReadOnlyEditorProps) => {
editorRef.current?.off("update");
};
},
getHeadings: () => {
return editorRef?.current?.storage.headingList.headings;
},
getHeadings: () => editorRef?.current?.storage.headingList.headings,
}));
if (!editor) {

View File

@@ -66,7 +66,7 @@ export interface IEditorProps {
value?: string | null;
}
export interface ILiteTextEditor extends IEditorProps {}
export type ILiteTextEditor = IEditorProps;
export interface IRichTextEditor extends IEditorProps {
dragDropEnabled?: boolean;
@@ -97,9 +97,9 @@ export interface IReadOnlyEditorProps {
};
}
export interface ILiteTextReadOnlyEditor extends IReadOnlyEditorProps {}
export type ILiteTextReadOnlyEditor = IReadOnlyEditorProps;
export interface IRichTextReadOnlyEditor extends IReadOnlyEditorProps {}
export type IRichTextReadOnlyEditor = IReadOnlyEditorProps;
export interface ICollaborativeDocumentReadOnlyEditor extends Omit<IReadOnlyEditorProps, "initialValue"> {
embedHandler: TEmbedConfig;

View File

@@ -1,13 +1,19 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"],
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ES2015", "DOM"],
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES6",
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/core/*"],
"@/styles/*": ["src/styles/*"],
"@/plane-editor/*": ["src/ce/*"]
}
}
},
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
}

View File

@@ -1,18 +0,0 @@
{
"name": "eslint-config-custom",
"private": true,
"version": "0.22.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"eslint": "^8.57.0",
"eslint-config-next": "^14.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "^1.12.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.33.2",
"typescript": "5.4.5"
}
}

View File

@@ -1,19 +1,25 @@
const { resolve } = require("node:path");
const project = resolve(process.cwd(), "tsconfig.json");
/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: ["next", "prettier", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2021, // Or the ECMAScript version you are using
sourceType: "module", // Or 'script' if you're using CommonJS or other modules
},
extends: ["prettier", "plugin:@typescript-eslint/recommended"],
plugins: ["react", "@typescript-eslint", "import"],
settings: {
next: {
rootDir: ["."],
},
},
globals: {
React: "readonly",
JSX: "readonly",
React: true,
JSX: true,
},
env: {
node: true,
browser: true,
},
settings: {
"import/resolver": {
typescript: {
project,
},
},
},
rules: {
"no-useless-escape": "off",
@@ -32,18 +38,12 @@ module.exports = {
"react/self-closing-comp": ["error", { component: true, html: true }],
"react/jsx-boolean-value": "error",
"react/jsx-no-duplicate-props": "error",
"react-hooks/exhaustive-deps": "warn",
"@typescript-eslint/no-unused-vars": ["error"],
// "react-hooks/exhaustive-deps": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": ["warn"],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-useless-empty-export": "error",
"@typescript-eslint/prefer-ts-expect-error": "error",
"@typescript-eslint/naming-convention": [
"error",
{
selector: ["function", "variable"],
format: ["camelCase", "snake_case", "UPPER_CASE", "PascalCase"],
leadingUnderscore: "allow",
},
],
"@typescript-eslint/prefer-ts-expect-error": "warn",
},
ignorePatterns: [".*.js", "node_modules/", "dist/"],
};

View File

@@ -0,0 +1,92 @@
const { resolve } = require("node:path");
const project = resolve(process.cwd(), "tsconfig.json");
module.exports = {
extends: ["next", "prettier", "plugin:@typescript-eslint/recommended"],
globals: {
React: "readonly",
JSX: "readonly",
},
env: {
node: true,
browser: true,
},
plugins: ["react", "@typescript-eslint", "import"],
settings: {
"import/resolver": {
typescript: {
project,
},
},
},
ignorePatterns: [".*.js", "node_modules/"],
rules: {
"no-useless-escape": "off",
"prefer-const": "error",
"no-irregular-whitespace": "error",
"no-trailing-spaces": "error",
"no-duplicate-imports": "error",
"no-useless-catch": "warn",
"no-case-declarations": "error",
"no-undef": "error",
"no-unreachable": "error",
"arrow-body-style": ["error", "as-needed"],
"@next/next/no-html-link-for-pages": "off",
"@next/next/no-img-element": "off",
"react/jsx-key": "error",
"react/self-closing-comp": ["error", { component: true, html: true }],
"react/jsx-boolean-value": "error",
"react/jsx-no-duplicate-props": "error",
"react-hooks/exhaustive-deps": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": ["warn"],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-useless-empty-export": "error",
"@typescript-eslint/prefer-ts-expect-error": "warn",
"@typescript-eslint/naming-convention": [
"warn",
{
selector: "variable",
format: ["camelCase", "snake_case", "UPPER_CASE", "PascalCase"],
leadingUnderscore: "allow",
},
],
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@headlessui/**",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
},
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
},
};

View File

@@ -0,0 +1,21 @@
{
"name": "@plane/eslint-config",
"private": true,
"version": "0.22.0",
"files": [
"library.js",
"next.js",
"server.js"
],
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.6.0",
"eslint": "8",
"eslint-config-next": "^14.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "^1.12.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.33.2",
"typescript": "5.3.3"
}
}

View File

@@ -0,0 +1,11 @@
module.exports = {
extends: ["eslint:recommended"],
env: {
node: true,
es6: true,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
};

View File

@@ -1,15 +1,15 @@
import React, { useEffect } from "react";
export const useOutsideClickDetector = (
ref: React.RefObject<HTMLElement>,
ref: React.RefObject<HTMLElement> | any,
callback: () => void,
useCapture = false
) => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
if (ref.current && !ref.current.contains(event.target as any)) {
// check for the closest element with attribute name data-prevent-outside-click
const preventOutsideClickElement = (
event.target as HTMLElement | undefined
event.target as unknown as HTMLElement | undefined
)?.closest("[data-prevent-outside-click]");
// if the closest element with attribute name data-prevent-outside-click is found, return
if (preventOutsideClickElement) {

View File

@@ -1,7 +1,8 @@
{
"extends": "tsconfig/react-library.json",
"extends": "@plane/typescript-config/react-library.json",
"compilerOptions": {
"jsx": "react"
"jsx": "react",
"lib": ["esnext", "dom"]
},
"include": ["."],
"exclude": ["dist", "build", "node_modules"]

View File

@@ -9,7 +9,8 @@
"forceConsistentCasingInFileNames": true,
"inlineSources": false,
"isolatedModules": true,
"moduleResolution": "node",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,

View File

@@ -3,6 +3,7 @@
"display": "Next.js",
"extends": "./base.json",
"compilerOptions": {
"plugins": [{ "name": "next" }],
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
@@ -12,7 +13,8 @@
"noEmit": true,
"incremental": true,
"esModuleInterop": true,
"module": "esnext",
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"

View File

@@ -1,5 +1,5 @@
{
"name": "tsconfig",
"name": "@plane/typescript-config",
"version": "0.22.0",
"private": true,
"files": [

View File

@@ -3,10 +3,9 @@
"display": "React Library",
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ES2015", "DOM"],
"module": "ESNext",
"target": "es6",
"sourceMap": true
}
"lib": ["ES2015"],
"target": "ES6",
"jsx": "react-jsx"
},
"exclude": ["node_modules"]
}

10
packages/ui/.eslintrc.js Normal file
View File

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

View File

@@ -17,7 +17,8 @@
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"postcss": "postcss styles/globals.css -o styles/output.css --watch"
"postcss": "postcss styles/globals.css -o styles/output.css --watch",
"lint": "eslint src --ext .ts,.tsx"
},
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.1.10",
@@ -57,15 +58,15 @@
"@types/react-dom": "^18.2.17",
"autoprefixer": "^10.4.19",
"classnames": "^2.3.2",
"eslint-config-custom": "*",
"@plane/eslint-config": "*",
"postcss-cli": "^11.0.0",
"postcss-nested": "^6.0.1",
"react": "^18.2.0",
"storybook": "^8.1.1",
"tailwind-config-custom": "*",
"tailwindcss": "^3.4.3",
"tsconfig": "*",
"@plane/typescript-config": "*",
"tsup": "^7.2.0",
"typescript": "5.4.5"
"typescript": "5.3.3"
}
}

View File

@@ -25,6 +25,7 @@ export interface IBadgeStyling {
};
}
// TODO: convert them to objects instead of enums
enum badgeSizeStyling {
sm = `px-2.5 py-1 font-medium text-xs rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
md = `px-4 py-1.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
@@ -32,10 +33,12 @@ enum badgeSizeStyling {
xl = `px-5 py-3 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
}
// TODO: convert them to objects instead of enums
enum badgeIconStyling {
sm = "h-3 w-3 flex justify-center items-center overflow-hidden flex-shrink-0",
md = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden flex-shrink-0",
lg = "h-4 w-4 flex justify-center items-center overflow-hidden flex-shrink-0",
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
xl = "h-4 w-4 flex justify-center items-center overflow-hidden flex-shrink-0",
}

View File

@@ -33,7 +33,7 @@ enum buttonIconStyling {
sm = "h-3 w-3 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
md = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
lg = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
xl = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
xl = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0 ",
}
export const buttonStyling: IButtonStyling = {

View File

@@ -105,7 +105,6 @@ export const MultiSelectDropdown: FC<IMultiSelectDropdown> = (props) => {
(option) => !(value ?? []).includes(option.data[option.value]),
() => sortByKey && sortByKey.toLowerCase(),
]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [query, options]);
// hooks

View File

@@ -105,7 +105,6 @@ export const Dropdown: FC<ISingleSelectDropdown> = (props) => {
(option) => !(value ?? []).includes(option.data[option.value]),
() => sortByKey && sortByKey.toLowerCase(),
]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [query, options]);
// hooks

View File

@@ -38,7 +38,7 @@ const ComboDropDown = forwardRef((props: Props, ref) => {
};
useEffect(() => {
const element = dropDownButtonRef.current;
const element = dropDownButtonRef.current as any;
if (!element) return;
@@ -58,7 +58,8 @@ const ComboDropDown = forwardRef((props: Props, ref) => {
}
return (
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error, @typescript-eslint/ban-ts-comment
// @ts-expect-error
<Combobox {...rest} ref={ref}>
<Combobox.Button as={Fragment}>{button}</Combobox.Button>
{children}

View File

@@ -102,7 +102,7 @@ export const CustomEmojiIconPicker: React.FC<TCustomEmojiPicker> = (props) => {
type: EmojiIconPickerTypes.EMOJI,
value: val,
});
if (closeOnSelect) close();
if (closeOnSelect) handleToggle(false);
}}
height="20rem"
width="100%"
@@ -121,7 +121,7 @@ export const CustomEmojiIconPicker: React.FC<TCustomEmojiPicker> = (props) => {
type: EmojiIconPickerTypes.ICON,
value: val,
});
if (closeOnSelect) close();
if (closeOnSelect) handleToggle(false);
}}
/>
</Tab.Panel>

View File

@@ -27,7 +27,7 @@ export const LinearProgressIndicator: React.FC<Props> = ({
backgroundColor: item.color,
};
progress += item.value;
if (noTooltip) return <div style={style} />;
if (noTooltip) return <div style={style} key={item.id} />;
else
return (
<Tooltip key={item.id} tooltipContent={`${item.name} ${Math.round(item.value)}${inPercentage ? "%" : ""}`}>

View File

@@ -54,7 +54,7 @@ export const Tooltip: React.FC<ITooltipProps> = ({
};
useEffect(() => {
const element = toolTipRef.current;
const element = toolTipRef.current as any;
if (!element) return;

View File

@@ -1,7 +1,8 @@
{
"extends": "tsconfig/react-library.json",
"extends": "@plane/typescript-config/react-library.json",
"compilerOptions": {
"jsx": "react"
"jsx": "react",
"lib": ["esnext", "dom"]
},
"include": ["."],
"exclude": ["dist", "build", "node_modules"]

View File

@@ -1,52 +1,10 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["custom"],
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
settings: {
"import/resolver": {
typescript: {},
node: {
moduleDirectory: ["node_modules", "."],
},
},
},
rules: {
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling",],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@headlessui/**",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
}
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
parserOptions: {
project: true,
},
rules: {},
};

View File

@@ -6,7 +6,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useMention } from "@/hooks/use-mention";
interface LiteTextReadOnlyEditorWrapperProps extends Omit<ILiteTextReadOnlyEditor, "mentionHandler"> {}
type LiteTextReadOnlyEditorWrapperProps = Omit<ILiteTextReadOnlyEditor, "mentionHandler">;
export const LiteTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, LiteTextReadOnlyEditorWrapperProps>(
({ ...props }, ref) => {

View File

@@ -6,7 +6,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useMention } from "@/hooks/use-mention";
interface RichTextReadOnlyEditorWrapperProps extends Omit<IRichTextReadOnlyEditor, "mentionHandler"> {}
type RichTextReadOnlyEditorWrapperProps = Omit<IRichTextReadOnlyEditor, "mentionHandler">;
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
({ ...props }, ref) => {

View File

@@ -7,7 +7,8 @@
"develop": "next dev -p 3002",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint": "eslint . --ext .ts,.tsx",
"lint:errors": "eslint . --ext .ts,.tsx --quiet",
"export": "next export"
},
"dependencies": {
@@ -58,9 +59,9 @@
"@types/uuid": "^9.0.1",
"@types/zxcvbn": "^4.4.4",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"eslint-config-custom": "*",
"@plane/eslint-config": "*",
"tailwind-config-custom": "*",
"tsconfig": "*",
"typescript": "5.4.5"
"@plane/typescript-config": "*",
"typescript": "5.3.3"
}
}

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/nextjs.json",
"extends": "@plane/typescript-config/nextjs.json",
"plugins": [
{
"name": "next"

View File

@@ -1,55 +1,9 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["custom"],
extends: ["@plane/eslint-config/next.js"],
parser: "@typescript-eslint/parser",
settings: {
"import/resolver": {
typescript: {},
node: {
moduleDirectory: ["node_modules", "."],
},
},
next: {
rootDir: ["."],
},
},
rules: {
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "lucide-react",
group: "external",
position: "after",
},
{
pattern: "@headlessui/**",
group: "external",
position: "after",
},
{
pattern: "@plane/**",
group: "external",
position: "after",
},
{
pattern: "@/**",
group: "internal",
},
],
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
parserOptions: {
project: true,
},
};

View File

@@ -21,9 +21,7 @@ import useSize from "@/hooks/use-window-size";
import { SidebarAppSwitcher } from "@/plane-web/components/sidebar";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export interface IAppSidebar {}
export const AppSidebar: FC<IAppSidebar> = observer(() => {
export const AppSidebar: FC = observer(() => {
// store hooks
const { allowPermissions } = useUserPermissions();
const { toggleSidebar, sidebarCollapsed } = useAppTheme();

View File

@@ -1,13 +1,14 @@
import { observer } from "mobx-react";
import { Control, Controller, UseFormSetValue } from "react-hook-form";
// types
import { IAnalyticsParams } from "@plane/types";
// hooks
import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics";
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
import { useProject } from "@/hooks/store";
// ui
import { Row } from "@plane/ui";
// components
// types
import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics";
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
// hooks
import { useProject } from "@/hooks/store";
type Props = {
control: Control<IAnalyticsParams, any>;

View File

@@ -6,7 +6,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useMention, useUser } from "@/hooks/store";
interface LiteTextReadOnlyEditorWrapperProps extends Omit<ILiteTextReadOnlyEditor, "mentionHandler"> {}
type LiteTextReadOnlyEditorWrapperProps = Omit<ILiteTextReadOnlyEditor, "mentionHandler">;
export const LiteTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, LiteTextReadOnlyEditorWrapperProps>(
({ ...props }, ref) => {

View File

@@ -6,7 +6,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useMention } from "@/hooks/store";
interface RichTextReadOnlyEditorWrapperProps extends Omit<IRichTextReadOnlyEditor, "mentionHandler"> {}
type RichTextReadOnlyEditorWrapperProps = Omit<IRichTextReadOnlyEditor, "mentionHandler">;
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
({ ...props }, ref) => {

View File

@@ -10,6 +10,8 @@ import { useIssueDetail, useLabel, useProjectInbox, useUserPermissions } from "@
// ui
// types
import { LabelList, LabelCreate, IssueLabelSelectRoot } from "./";
// TODO: Fix this import statement, as core should not import from ee
// eslint-disable-next-line import/order
import { EUserPermissions, EUserPermissionsLevel } from "ee/constants/user-permissions";
export type TIssueLabel = {

View File

@@ -11,8 +11,6 @@ import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/u
// components
import { BaseKanBanRoot } from "../base-kanban-root";
export interface ICycleKanBanLayout {}
export const CycleKanBanLayout: React.FC = observer(() => {
const { workspaceSlug, projectId, cycleId } = useParams();

View File

@@ -3,6 +3,4 @@ import { observer } from "mobx-react";
import { DraftIssueQuickActions } from "@/components/issues";
import { BaseKanBanRoot } from "../base-kanban-root";
export interface IKanBanLayout {}
export const DraftKanBanLayout: React.FC = observer(() => <BaseKanBanRoot QuickActions={DraftIssueQuickActions} />);

View File

@@ -10,8 +10,6 @@ import { useIssues } from "@/hooks/store";
// constants
import { BaseKanBanRoot } from "../base-kanban-root";
export interface IModuleKanBanLayout {}
export const ModuleKanBanLayout: React.FC = observer(() => {
const { workspaceSlug, projectId, moduleId } = useParams();

View File

@@ -131,9 +131,7 @@ export const IssueBlockRoot: FC<Props> = observer((props) => {
classNames={`relative ${isLastChild && !isExpanded ? "" : "border-b border-b-custom-border-200"}`}
verticalOffset={100}
defaultValue={shouldRenderByDefault || isIssueNew(issuesMap[issueId])}
placeholderChildren={
<ListLoaderItemRow shouldAnimate={false} renderForPlaceHolder={true} defaultPropertyCount={4} />
}
placeholderChildren={<ListLoaderItemRow shouldAnimate={false} renderForPlaceHolder defaultPropertyCount={4} />}
shouldRecordHeights={isMobile}
>
<IssueBlock

View File

@@ -11,8 +11,6 @@ import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/u
// types
import { BaseListRoot } from "../base-list-root";
export interface ICycleListLayout {}
export const CycleListLayout: React.FC = observer(() => {
const { workspaceSlug, projectId, cycleId } = useParams();
// store

View File

@@ -10,8 +10,6 @@ import { useIssues } from "@/hooks/store";
// constants
import { BaseListRoot } from "../base-list-root";
export interface IModuleListLayout {}
export const ModuleListLayout: React.FC = observer(() => {
const { workspaceSlug, projectId, moduleId } = useParams();

View File

@@ -4,9 +4,7 @@ import { FC } from "react";
// components
import { Loader } from "@plane/ui";
export interface IProjectDetailsFormLoader {}
export const ProjectDetailsFormLoader: FC<IProjectDetailsFormLoader> = () => (
export const ProjectDetailsFormLoader: FC = () => (
<>
<div className="relative mt-6 h-44 w-full">
<Loader>

View File

@@ -7,7 +7,8 @@
"develop": "next dev --port 3000",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint": "eslint . --ext .ts,.tsx",
"lint:errors": "eslint . --ext .ts,.tsx --quiet",
"export": "next export",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
},
@@ -76,10 +77,10 @@
"@types/react-dom": "^18.2.18",
"@types/uuid": "^8.3.4",
"@types/zxcvbn": "^4.4.4",
"eslint-config-custom": "*",
"@plane/eslint-config": "*",
"prettier": "^3.2.5",
"tailwind-config-custom": "*",
"tsconfig": "*",
"typescript": "5.4.5"
"@plane/typescript-config": "*",
"typescript": "5.3.3"
}
}

View File

@@ -1,11 +1,7 @@
{
"extends": "tsconfig/nextjs.json",
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"],
"extends": "@plane/typescript-config/nextjs.json",
"compilerOptions": {
"baseUrl": ".",
"jsx": "preserve",
"esModuleInterop": true,
"paths": {
"@/*": ["core/*"],
"@/helpers/*": ["helpers/*"],
@@ -13,11 +9,9 @@
"@/styles/*": ["styles/*"],
"@/plane-web/*": ["ce/*"]
},
"plugins": [
{
"name": "next"
}
],
"plugins": [{ "name": "next" }],
"strictNullChecks": true
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

1
web/use-font-face-observer.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module "use-font-face-observer";

3392
yarn.lock

File diff suppressed because it is too large Load Diff