chore: run fixes (#8257)

* chore: run fixes

* fix: type, just use hocuspocusservercontext

* fix: codemod

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
This commit is contained in:
Aaron 2025-12-08 23:56:50 +07:00 committed by GitHub
parent a9e9cb2983
commit 0ab94ed6d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
172 changed files with 1784 additions and 1798 deletions

12
.npmrc
View file

@ -45,15 +45,3 @@ prefer-frozen-lockfile = true
# Use isolated linker (best compatibility with Node ecosystem tools) # Use isolated linker (best compatibility with Node ecosystem tools)
node-linker = isolated node-linker = isolated
# ------------------------------
# Hoisting Strategy
# ------------------------------
# Hoist commonly used tools to the root to prevent duplicates and speed up resolution
public-hoist-pattern[] = typescript
public-hoist-pattern[] = eslint
public-hoist-pattern[] = *@plane/*
public-hoist-pattern[] = vite
public-hoist-pattern[] = turbo

View file

@ -11,7 +11,7 @@ import { cn } from "@plane/utils";
// hooks // hooks
import { useTheme } from "@/hooks/store"; import { useTheme } from "@/hooks/store";
// assets // assets
// eslint-disable-next-line import/order
import packageJson from "package.json"; import packageJson from "package.json";
const helpOptions = [ const helpOptions = [

View file

@ -26,7 +26,7 @@ export enum EErrorAlertType {
} }
const errorCodeMessages: { const errorCodeMessages: {
[key in EAdminAuthErrorCodes]: { title: string; message: (email?: string | undefined) => React.ReactNode }; [key in EAdminAuthErrorCodes]: { title: string; message: (email?: string) => React.ReactNode };
} = { } = {
// admin // admin
[EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST]: { [EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST]: {
@ -79,14 +79,11 @@ const errorCodeMessages: {
}, },
[EAdminAuthErrorCodes.ADMIN_USER_DEACTIVATED]: { [EAdminAuthErrorCodes.ADMIN_USER_DEACTIVATED]: {
title: `User account deactivated`, title: `User account deactivated`,
message: () => `User account deactivated. Please contact ${!!SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`, message: () => `User account deactivated. Please contact ${SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`,
}, },
}; };
export const authErrorHandler = ( export const authErrorHandler = (errorCode: EAdminAuthErrorCodes, email?: string): TAdminAuthErrorInfo | undefined => {
errorCode: EAdminAuthErrorCodes,
email?: string | undefined
): TAdminAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [ const bannerAlertErrorCodes = [
EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST, EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST,
EAdminAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, EAdminAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,

View file

@ -1,4 +1,3 @@
/* eslint-disable import/order */
import * as Sentry from "@sentry/react-router"; import * as Sentry from "@sentry/react-router";
import { startTransition, StrictMode } from "react"; import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client"; import { hydrateRoot } from "react-dom/client";

View file

@ -11,6 +11,7 @@ export function UpgradeButton() {
href="https://plane.so/pricing?mode=self-hosted" href="https://plane.so/pricing?mode=self-hosted"
target="_blank" target="_blank"
className={cn(getButtonStyling("primary", "sm"))} className={cn(getButtonStyling("primary", "sm"))}
rel="noreferrer"
> >
Upgrade Upgrade
<SquareArrowOutUpRight className="h-3.5 w-3.5 p-0.5" /> <SquareArrowOutUpRight className="h-3.5 w-3.5 p-0.5" />

View file

@ -24,6 +24,7 @@ export const WorkspaceListItem = observer(function WorkspaceListItem({ workspace
href={`${WEB_BASE_URL}/${encodeURIComponent(workspace.slug)}`} href={`${WEB_BASE_URL}/${encodeURIComponent(workspace.slug)}`}
target="_blank" target="_blank"
className="group flex items-center justify-between p-4 gap-2.5 truncate border border-custom-border-200/70 hover:border-custom-border-200 hover:bg-custom-background-90 rounded-md" className="group flex items-center justify-between p-4 gap-2.5 truncate border border-custom-border-200/70 hover:border-custom-border-200 hover:bg-custom-background-90 rounded-md"
rel="noreferrer"
> >
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
<span <span

View file

@ -12,7 +12,7 @@ export class ForceCloseHandler implements Extension {
priority = 999; priority = 999;
async onConfigure({ instance }: onConfigurePayload) { async onConfigure({ instance }: onConfigurePayload) {
const redisExt = instance.configuration.extensions.find((ext) => ext instanceof Redis) as Redis | undefined; const redisExt = instance.configuration.extensions.find((ext) => ext instanceof Redis);
if (!redisExt) { if (!redisExt) {
logger.warn("[FORCE_CLOSE_HANDLER] Redis extension not found"); logger.warn("[FORCE_CLOSE_HANDLER] Redis extension not found");
@ -149,7 +149,7 @@ export const forceCloseDocumentAcrossServers = async (
logger.info(`[FORCE_CLOSE] Closed ${closedCount}/${connectionsBefore} local connections`); logger.info(`[FORCE_CLOSE] Closed ${closedCount}/${connectionsBefore} local connections`);
// STEP 4: BROADCAST TO OTHER SERVERS // STEP 4: BROADCAST TO OTHER SERVERS
const redisExt = instance.configuration.extensions.find((ext) => ext instanceof Redis) as Redis | undefined; const redisExt = instance.configuration.extensions.find((ext) => ext instanceof Redis);
if (redisExt) { if (redisExt) {
const commandData: ForceCloseCommandData = { const commandData: ForceCloseCommandData = {

View file

@ -1,4 +1,3 @@
// eslint-disable-next-line import/order
import { setupSentry } from "./instrument"; import { setupSentry } from "./instrument";
setupSentry(); setupSentry();

View file

@ -1,7 +1,7 @@
import type { Hocuspocus } from "@hocuspocus/server"; import type { Hocuspocus } from "@hocuspocus/server";
import { createRealtimeEvent } from "@plane/editor"; import { createRealtimeEvent } from "@plane/editor";
import { logger } from "@plane/logger"; import { logger } from "@plane/logger";
import type { FetchPayloadWithContext, StorePayloadWithContext } from "@/types"; import type { HocusPocusServerContext } from "@/types";
import { broadcastMessageToPage } from "./broadcast-message"; import { broadcastMessageToPage } from "./broadcast-message";
// Helper to broadcast error to frontend // Helper to broadcast error to frontend
@ -10,7 +10,7 @@ export const broadcastError = async (
pageId: string, pageId: string,
errorMessage: string, errorMessage: string,
errorType: "fetch" | "store", errorType: "fetch" | "store",
context: FetchPayloadWithContext["context"] | StorePayloadWithContext["context"], context: HocusPocusServerContext,
errorCode?: "content_too_large" | "page_locked" | "page_archived", errorCode?: "content_too_large" | "page_locked" | "page_archived",
shouldDisconnect?: boolean shouldDisconnect?: boolean
) => { ) => {

View file

@ -1,4 +1,3 @@
/* eslint-disable import/order */
import * as Sentry from "@sentry/react-router"; import * as Sentry from "@sentry/react-router";
import { startTransition, StrictMode } from "react"; import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client"; import { hydrateRoot } from "react-dom/client";

View file

@ -11,7 +11,7 @@ interface Props {
subGroupId: string | undefined, subGroupId: string | undefined,
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
} }
export const IssueLayoutHOC = observer(function IssueLayoutHOC(props: Props) { export const IssueLayoutHOC = observer(function IssueLayoutHOC(props: Props) {

View file

@ -37,7 +37,7 @@ export interface IKanBan {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
showEmptyGroup?: boolean; showEmptyGroup?: boolean;
} }

View file

@ -29,7 +29,7 @@ interface IKanbanGroup {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
} }

View file

@ -37,7 +37,7 @@ export interface IKanBanSwimLanes {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
showEmptyGroup: boolean; showEmptyGroup: boolean;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
orderBy: TIssueOrderByOptions | undefined; orderBy: TIssueOrderByOptions | undefined;
@ -163,7 +163,7 @@ interface ISubGroupSwimlane extends ISubGroupSwimlaneHeader {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
loadMoreIssues: (groupId?: string, subGroupId?: string) => void; loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
} }
@ -220,7 +220,7 @@ interface ISubGroup {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
loadMoreIssues: (groupId?: string, subGroupId?: string) => void; loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
} }

View file

@ -32,7 +32,7 @@ export interface IList {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
} }
export const List = observer(function List(props: IList) { export const List = observer(function List(props: IList) {

View file

@ -32,7 +32,7 @@ interface Props {
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined; getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
getIssueLoader: (groupId?: string | undefined, subGroupId?: string | undefined) => TLoader; getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
} }
// List loader component // List loader component

View file

@ -1,5 +1,3 @@
"use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// plane ui // plane ui
import { StateGroupIcon } from "@plane/propel/icons"; import { StateGroupIcon } from "@plane/propel/icons";
@ -24,7 +22,7 @@ type Props = {
} }
); );
export const IssueBlockState: React.FC<Props> = observer((props) => { export const IssueBlockState = observer(function IssueBlockState(props: Props) {
const { shouldShowBorder = true } = props; const { shouldShowBorder = true } = props;
// store hooks // store hooks
const { getStateById } = useStates(); const { getStateById } = useStates();

View file

@ -44,7 +44,7 @@ export const getGroupByColumns = (
case "labels": case "labels":
return getLabelsColumns(label) as any; return getLabelsColumns(label) as any;
case "assignees": case "assignees":
return getAssigneeColumns(member) as any; return getAssigneeColumns(member);
case "created_by": case "created_by":
return getCreatedByColumns(member) as any; return getCreatedByColumns(member) as any;
default: default:
@ -65,7 +65,7 @@ const getCycleColumns = (cycleStore: ICycleStore): IGroupByColumn[] | undefined
cycleGroups.push({ cycleGroups.push({
id: cycle.id, id: cycle.id,
name: cycle.name, name: cycle.name,
icon: <CycleGroupIcon cycleGroup={cycleStatus as TCycleGroups} className="h-3.5 w-3.5" />, icon: <CycleGroupIcon cycleGroup={cycleStatus} className="h-3.5 w-3.5" />,
payload: { cycle_id: cycle.id }, payload: { cycle_id: cycle.id },
}); });
} }
@ -196,11 +196,8 @@ export const getDisplayPropertiesCount = (
return count; return count;
}; };
export const getIssueBlockId = ( export const getIssueBlockId = (issueId: string | undefined, groupId: string | undefined, subGroupId?: string) =>
issueId: string | undefined, `issue_${issueId}_${groupId}_${subGroupId}`;
groupId: string | undefined,
subGroupId?: string | undefined
) => `issue_${issueId}_${groupId}_${subGroupId}`;
/** /**
* returns empty Array if groupId is None * returns empty Array if groupId is None

View file

@ -6,7 +6,7 @@ const useClipboardWritePermission = () => {
useEffect(() => { useEffect(() => {
const checkClipboardWriteAccess = () => { const checkClipboardWriteAccess = () => {
navigator.permissions navigator.permissions
//eslint-disable-next-line no-undef
.query({ name: "clipboard-write" as PermissionName }) .query({ name: "clipboard-write" as PermissionName })
.then((result) => { .then((result) => {
if (result.state === "granted") { if (result.state === "granted") {

View file

@ -32,7 +32,6 @@ export const useIntersectionObserver = (
observer.observe(elementRef); observer.observe(elementRef);
return () => { return () => {
if (elementRef) { if (elementRef) {
// eslint-disable-next-line react-hooks/exhaustive-deps
observer.unobserve(elementRef); observer.unobserve(elementRef);
} }
}; };

View file

@ -103,15 +103,15 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
const allIssues = groupedIssueIds[ALL_ISSUES] ?? []; const allIssues = groupedIssueIds[ALL_ISSUES] ?? [];
if (allIssues && Array.isArray(allIssues)) { if (allIssues && Array.isArray(allIssues)) {
return allIssues as string[]; return allIssues;
} }
if (groupId && groupedIssueIds?.[groupId] && Array.isArray(groupedIssueIds[groupId])) { if (groupId && groupedIssueIds?.[groupId] && Array.isArray(groupedIssueIds[groupId])) {
return (groupedIssueIds[groupId] ?? []) as string[]; return groupedIssueIds[groupId] ?? [];
} }
if (groupId && subGroupId) { if (groupId && subGroupId) {
return ((groupedIssueIds as TSubGroupedIssues)[groupId]?.[subGroupId] ?? []) as string[]; return (groupedIssueIds as TSubGroupedIssues)[groupId]?.[subGroupId] ?? [];
} }
return undefined; return undefined;
@ -443,7 +443,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
// if groupedIssueIds is an array, update the `groupedIssueIds` store at the issuePath // if groupedIssueIds is an array, update the `groupedIssueIds` store at the issuePath
if (groupedIssueIds && Array.isArray(groupedIssueIds)) { if (groupedIssueIds && Array.isArray(groupedIssueIds)) {
update(this, ["groupedIssueIds", ...issuePath], (issueIds: string[] = []) => update(this, ["groupedIssueIds", ...issuePath], (issueIds: string[] = []) =>
uniq(concat(issueIds, groupedIssueIds as string[])) uniq(concat(issueIds, groupedIssueIds))
); );
// return true to indicate the store has been updated // return true to indicate the store has been updated
return true; return true;

View file

@ -86,7 +86,7 @@ export type TAuthErrorInfo = {
}; };
const errorCodeMessages: { const errorCodeMessages: {
[key in EAuthenticationErrorCodes]: { title: string; message: (email?: string | undefined) => React.ReactNode }; [key in EAuthenticationErrorCodes]: { title: string; message: (email?: string) => React.ReactNode };
} = { } = {
// global // global
[EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED]: { [EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED]: {
@ -156,7 +156,7 @@ const errorCodeMessages: {
// sign in // sign in
[EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: { [EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
title: `User account deactivated`, title: `User account deactivated`,
message: () => `User account deactivated. Please contact ${!!SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`, message: () => `User account deactivated. Please contact ${SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`,
}, },
[EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: { [EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: {
@ -332,10 +332,7 @@ const errorCodeMessages: {
}, },
}; };
export const authErrorHandler = ( export const authErrorHandler = (errorCode: EAuthenticationErrorCodes, email?: string): TAuthErrorInfo | undefined => {
errorCode: EAuthenticationErrorCodes,
email?: string | undefined
): TAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [ const bannerAlertErrorCodes = [
EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED, EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED,
EAuthenticationErrorCodes.INVALID_EMAIL, EAuthenticationErrorCodes.INVALID_EMAIL,

View file

@ -1,5 +1,3 @@
"use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";

View file

@ -1,5 +1,3 @@
"use client";
import React from "react"; import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
@ -16,7 +14,7 @@ import { useAppRouter } from "@/hooks/use-app-router";
// plane web imports // plane web imports
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common"; import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
export const WorkItemDetailsHeader = observer(() => { export const WorkItemDetailsHeader = observer(function WorkItemDetailsHeader() {
// router // router
const router = useAppRouter(); const router = useAppRouter();
const { workspaceSlug, workItem } = useParams(); const { workspaceSlug, workItem } = useParams();

View file

@ -50,11 +50,7 @@ export const CycleIssuesHeader = observer(function CycleIssuesHeader() {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // router
const router = useAppRouter(); const router = useAppRouter();
const { workspaceSlug, projectId, cycleId } = useParams() as { const { workspaceSlug, projectId, cycleId } = useParams();
workspaceSlug: string;
projectId: string;
cycleId: string;
};
// i18n // i18n
const { t } = useTranslation(); const { t } = useTranslation();
// store hooks // store hooks

View file

@ -22,10 +22,7 @@ export const ProjectIssuesMobileHeader = observer(function ProjectIssuesMobileHe
// i18n // i18n
const { t } = useTranslation(); const { t } = useTranslation();
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { workspaceSlug, projectId } = useParams() as { const { workspaceSlug, projectId } = useParams();
workspaceSlug: string;
projectId: string;
};
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
// store hooks // store hooks

View file

@ -1,5 +1,3 @@
"use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Outlet } from "react-router"; import { Outlet } from "react-router";
// plane imports // plane imports

View file

@ -25,11 +25,7 @@ const SUPPORTED_LAYOUTS = [
export const ModuleIssuesMobileHeader = observer(function ModuleIssuesMobileHeader() { export const ModuleIssuesMobileHeader = observer(function ModuleIssuesMobileHeader() {
// router // router
const { workspaceSlug, projectId, moduleId } = useParams() as { const { workspaceSlug, projectId, moduleId } = useParams();
workspaceSlug: string;
projectId: string;
moduleId: string;
};
// states // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// plane hooks // plane hooks

View file

@ -21,7 +21,7 @@ import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/com
export const ModulesListHeader = observer(function ModulesListHeader() { export const ModulesListHeader = observer(function ModulesListHeader() {
// router // router
const router = useAppRouter(); const router = useAppRouter();
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string }; const { workspaceSlug, projectId } = useParams();
// store hooks // store hooks
const { toggleCreateModuleModal } = useCommandPalette(); const { toggleCreateModuleModal } = useCommandPalette();
const { allowPermissions } = useUserPermissions(); const { allowPermissions } = useUserPermissions();

View file

@ -15,7 +15,7 @@ import { useProject } from "@/hooks/store/use-project";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common"; import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
export const ProjectViewsHeader = observer(function ProjectViewsHeader() { export const ProjectViewsHeader = observer(function ProjectViewsHeader() {
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string }; const { workspaceSlug, projectId } = useParams();
// store hooks // store hooks
const { toggleCreateViewModal } = useCommandPalette(); const { toggleCreateViewModal } = useCommandPalette();
const { loader } = useProject(); const { loader } = useProject();

View file

@ -1,4 +1,3 @@
/* eslint-disable import/order */
import * as Sentry from "@sentry/react-router"; import * as Sentry from "@sentry/react-router";
import { startTransition, StrictMode } from "react"; import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client"; import { hydrateRoot } from "react-dom/client";

View file

@ -1,6 +1,4 @@
// hoc/withDockItems.tsx // hoc/withDockItems.tsx
"use client";
import React from "react"; import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
@ -13,7 +11,7 @@ type WithDockItemsProps = {
}; };
export function withDockItems<P extends WithDockItemsProps>(WrappedComponent: React.ComponentType<P>) { export function withDockItems<P extends WithDockItemsProps>(WrappedComponent: React.ComponentType<P>) {
const ComponentWithDockItems = observer((props: Omit<P, keyof WithDockItemsProps>) => { const ComponentWithDockItems = observer(function ComponentWithDockItems(props: Omit<P, keyof WithDockItemsProps>) {
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
const { isProjectsPath, isNotificationsPath } = useWorkspacePaths(); const { isProjectsPath, isNotificationsPath } = useWorkspacePaths();

View file

@ -35,7 +35,7 @@ import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/com
export const IssuesHeader = observer(function IssuesHeader() { export const IssuesHeader = observer(function IssuesHeader() {
// router // router
const router = useAppRouter(); const router = useAppRouter();
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string }; const { workspaceSlug, projectId } = useParams();
// store hooks // store hooks
const { const {
issues: { getGroupIssueCount }, issues: { getGroupIssueCount },

View file

@ -69,7 +69,7 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList verticalFeatureList
extraFeatures={ extraFeatures={
<p className={COMMON_EXTRA_FEATURES_CLASSNAME}> <p className={COMMON_EXTRA_FEATURES_CLASSNAME}>
<a href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.PRO]} target="_blank"> <a href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.PRO]} target="_blank" rel="noreferrer">
See full features list See full features list
</a> </a>
</p> </p>
@ -87,7 +87,11 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList verticalFeatureList
extraFeatures={ extraFeatures={
<p className={COMMON_EXTRA_FEATURES_CLASSNAME}> <p className={COMMON_EXTRA_FEATURES_CLASSNAME}>
<a href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.BUSINESS]} target="_blank"> <a
href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.BUSINESS]}
target="_blank"
rel="noreferrer"
>
See full features list See full features list
</a> </a>
</p> </p>
@ -105,7 +109,11 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList verticalFeatureList
extraFeatures={ extraFeatures={
<p className={COMMON_EXTRA_FEATURES_CLASSNAME}> <p className={COMMON_EXTRA_FEATURES_CLASSNAME}>
<a href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.ENTERPRISE]} target="_blank"> <a
href={SUBSCRIPTION_WEBPAGE_URLS[EProductSubscriptionEnum.ENTERPRISE]}
target="_blank"
rel="noreferrer"
>
See full features list See full features list
</a> </a>
</p> </p>

View file

@ -13,7 +13,7 @@ import { InboxIcon } from "@plane/propel/icons";
import useSWR from "swr"; import useSWR from "swr";
import { useWorkspaceNotifications } from "@/hooks/store/notifications"; import { useWorkspaceNotifications } from "@/hooks/store/notifications";
export const TopNavigationRoot = observer(() => { export const TopNavigationRoot = observer(function TopNavigationRoot() {
// router // router
const { workspaceSlug, projectId, workItem } = useParams(); const { workspaceSlug, projectId, workItem } = useParams();
const pathname = usePathname(); const pathname = usePathname();

View file

@ -65,7 +65,7 @@ export const useProjectColumns = (props: TUseProjectColumnsProps) => {
tdRender: (rowData: RowData) => ( tdRender: (rowData: RowData) => (
<NameColumn <NameColumn
rowData={rowData} rowData={rowData}
workspaceSlug={workspaceSlug as string} workspaceSlug={workspaceSlug}
isAdmin={isAdmin} isAdmin={isAdmin}
currentUser={currentUser} currentUser={currentUser}
setRemoveMemberModal={setRemoveMemberModal} setRemoveMemberModal={setRemoveMemberModal}
@ -110,8 +110,8 @@ export const useProjectColumns = (props: TUseProjectColumnsProps) => {
<AccountTypeColumn <AccountTypeColumn
rowData={rowData} rowData={rowData}
currentProjectRole={currentProjectRole} currentProjectRole={currentProjectRole}
projectId={projectId as string} projectId={projectId}
workspaceSlug={workspaceSlug as string} workspaceSlug={workspaceSlug}
/> />
), ),
}, },

View file

@ -1,5 +1,3 @@
"use client";
import React from "react"; import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { AppRailVisibilityProvider as CoreProvider } from "@/lib/app-rail"; import { AppRailVisibilityProvider as CoreProvider } from "@/lib/app-rail";
@ -12,6 +10,8 @@ interface AppRailVisibilityProviderProps {
* CE AppRailVisibilityProvider * CE AppRailVisibilityProvider
* Wraps core provider with isEnabled hardcoded to false * Wraps core provider with isEnabled hardcoded to false
*/ */
export const AppRailVisibilityProvider = observer(({ children }: AppRailVisibilityProviderProps) => ( export const AppRailVisibilityProvider = observer(function AppRailVisibilityProvider({
<CoreProvider isEnabled={false}>{children}</CoreProvider> children,
)); }: AppRailVisibilityProviderProps) {
return <CoreProvider isEnabled={false}>{children}</CoreProvider>;
});

View file

@ -17,10 +17,10 @@ export const getTimelineStore = (
return timelineStore.modulesTimeLineStore as IBaseTimelineStore; return timelineStore.modulesTimeLineStore as IBaseTimelineStore;
} }
if (timelineType === GANTT_TIMELINE_TYPE.PROJECT) { if (timelineType === GANTT_TIMELINE_TYPE.PROJECT) {
return timelineStore.projectTimeLineStore as IBaseTimelineStore; return timelineStore.projectTimeLineStore;
} }
if (timelineType === GANTT_TIMELINE_TYPE.GROUPED) { if (timelineType === GANTT_TIMELINE_TYPE.GROUPED) {
return timelineStore.groupedTimeLineStore as IBaseTimelineStore; return timelineStore.groupedTimeLineStore;
} }
throw new Error(`Unknown timeline type: ${timelineType}`); throw new Error(`Unknown timeline type: ${timelineType}`);
}; };

View file

@ -49,7 +49,7 @@ export function GeneratedTokenDetails(props: Props) {
<div className="mt-6 flex items-center justify-between"> <div className="mt-6 flex items-center justify-between">
<p className="text-xs text-custom-text-400"> <p className="text-xs text-custom-text-400">
{tokenDetails.expired_at {tokenDetails.expired_at
? `Expires ${renderFormattedDate(tokenDetails.expired_at!)} at ${renderFormattedTime(tokenDetails.expired_at!)}` ? `Expires ${renderFormattedDate(tokenDetails.expired_at)} at ${renderFormattedTime(tokenDetails.expired_at)}`
: "Never expires"} : "Never expires"}
</p> </p>
<Button variant="neutral-primary" size="sm" onClick={handleClose}> <Button variant="neutral-primary" size="sm" onClick={handleClose}>

View file

@ -51,7 +51,7 @@ export function ApiTokenListItem(props: Props) {
<p className="mb-1 text-xs leading-6 text-custom-text-400"> <p className="mb-1 text-xs leading-6 text-custom-text-400">
{token.is_active {token.is_active
? token.expired_at ? token.expired_at
? `Expires ${renderFormattedDate(token.expired_at!)} at ${renderFormattedTime(token.expired_at!)}` ? `Expires ${renderFormattedDate(token.expired_at)} at ${renderFormattedTime(token.expired_at)}`
: "Never expires" : "Never expires"
: `Expired ${calculateTimeAgo(token.expired_at)}`} : `Expired ${calculateTimeAgo(token.expired_at)}`}
</p> </p>

View file

@ -42,7 +42,7 @@ export const CommentCreate = observer(function CommentCreate(props: TCommentCrea
// store hooks // store hooks
const workspaceStore = useWorkspace(); const workspaceStore = useWorkspace();
// derived values // derived values
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
// form info // form info
const { const {
handleSubmit, handleSubmit,

View file

@ -65,7 +65,7 @@ export const CommentsWrapper = observer(function CommentsWrapper(props: TComment
<CommentCard <CommentCard
key={comment.id} key={comment.id}
workspaceSlug={workspaceSlug} workspaceSlug={workspaceSlug}
comment={comment as TIssueComment} comment={comment}
activityOperations={activityOperations} activityOperations={activityOperations}
disabled={!isEditingAllowed} disabled={!isEditingAllowed}
ends={index === 0 ? "top" : index === comments.length - 1 ? "bottom" : undefined} ends={index === 0 ? "top" : index === comments.length - 1 ? "bottom" : undefined}

View file

@ -1,4 +1,3 @@
import type { FC } from "react";
import { useMemo } from "react"; import { useMemo } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Globe2, Link, Lock, Pencil, Trash2 } from "lucide-react"; import { Globe2, Link, Lock, Pencil, Trash2 } from "lucide-react";
@ -31,8 +30,9 @@ export const CommentQuickActions = observer(function CommentQuickActions(props:
// translation // translation
const { t } = useTranslation(); const { t } = useTranslation();
const MENU_ITEMS = useMemo<TContextMenuItem[]>( const MENU_ITEMS = useMemo(
() => [ function MENU_ITEMS(): TContextMenuItem[] {
return [
{ {
key: "edit", key: "edit",
action: setEditMode, action: setEditMode,
@ -70,7 +70,8 @@ export const CommentQuickActions = observer(function CommentQuickActions(props:
icon: Trash2, icon: Trash2,
shouldRender: canDelete, shouldRender: canDelete,
}, },
], ];
},
[t, setEditMode, canEdit, showCopyLinkOption, activityOperations, comment, showAccessSpecifier, canDelete] [t, setEditMode, canEdit, showCopyLinkOption, activityOperations, comment, showAccessSpecifier, canDelete]
); );

View file

@ -1,4 +1,3 @@
import type { ReactNode, FC } from "react";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
@ -19,7 +18,7 @@ const IconWrapper = React.memo(function IconWrapper({ icon }: { icon: React.Reac
IconWrapper.displayName = "IconWrapper"; IconWrapper.displayName = "IconWrapper";
const LabelWrapper = React.memo(function LabelWrapper({ label }: { label: ReactNode }) { const LabelWrapper = React.memo(function LabelWrapper({ label }: { label: React.ReactNode }) {
return <div className="relative line-clamp-1 block max-w-[150px] overflow-hidden truncate">{label}</div>; return <div className="relative line-clamp-1 block max-w-[150px] overflow-hidden truncate">{label}</div>;
}); });
@ -30,7 +29,7 @@ const BreadcrumbContent = React.memo(function BreadcrumbContent({
label, label,
}: { }: {
icon?: React.ReactNode; icon?: React.ReactNode;
label?: ReactNode; label?: React.ReactNode;
}) { }) {
if (!icon && !label) return null; if (!icon && !label) return null;
@ -58,10 +57,10 @@ export const BreadcrumbLink = observer(function BreadcrumbLink(props: Props) {
const { isMobile } = usePlatformOS(); const { isMobile } = usePlatformOS();
const itemWrapperProps = useMemo( const itemWrapperProps = useMemo(
() => ({ (): Omit<React.ComponentProps<typeof ItemWrapper>, "children"> => ({
label: label?.toString(), label: label?.toString(),
disableTooltip: isMobile || disableTooltip, disableTooltip: isMobile || disableTooltip,
type: (href && href !== "" ? "link" : "text") as "link" | "text", type: href && href !== "" ? "link" : "text",
isLast, isLast,
}), }),
[href, label, isMobile, disableTooltip, isLast] [href, label, isMobile, disableTooltip, isLast]

View file

@ -105,7 +105,7 @@ export const BulkDeleteIssuesModal = observer(function BulkDeleteIssuesModal(pro
if (!Array.isArray(data.delete_issue_ids)) data.delete_issue_ids = [data.delete_issue_ids]; if (!Array.isArray(data.delete_issue_ids)) data.delete_issue_ids = [data.delete_issue_ids];
await removeBulkIssues(workspaceSlug as string, projectId as string, data.delete_issue_ids) await removeBulkIssues(workspaceSlug, projectId, data.delete_issue_ids)
.then(() => { .then(() => {
setToast({ setToast({
type: TOAST_TYPE.SUCCESS, type: TOAST_TYPE.SUCCESS,

View file

@ -1,5 +1,3 @@
"use client";
import React, { useState } from "react"; import React, { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
@ -29,7 +27,7 @@ const defaultValues: TUniqueCodeValuesForm = { email: "", code: "" };
// service initialization // service initialization
const authService = new AuthService(); const authService = new AuthService();
export const ChangeEmailModal: React.FC<Props> = observer((props) => { export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props) {
const { isOpen, onClose } = props; const { isOpen, onClose } = props;
// states // states
const [currentStep, setCurrentStep] = useState<TModalStep>("EMAIL"); const [currentStep, setCurrentStep] = useState<TModalStep>("EMAIL");

View file

@ -106,7 +106,7 @@ export const CycleSidebarHeader = observer(function CycleSidebarHeader(props: Pr
const dateChecker = async (payload: any) => { const dateChecker = async (payload: any) => {
try { try {
const res = await cycleService.cycleDateCheck(workspaceSlug as string, projectId as string, payload); const res = await cycleService.cycleDateCheck(workspaceSlug, projectId, payload);
return res.status; return res.status;
} catch (err) { } catch (err) {
return false; return false;

View file

@ -1,5 +1,3 @@
"use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
@ -41,7 +39,9 @@ export type TWorkItemStateDropdownBaseProps = TDropdownProps & {
value: string | undefined | null; value: string | undefined | null;
}; };
export const WorkItemStateDropdownBase: React.FC<TWorkItemStateDropdownBaseProps> = observer((props) => { export const WorkItemStateDropdownBase = observer(function WorkItemStateDropdownBase(
props: TWorkItemStateDropdownBaseProps
) {
const { const {
button, button,
buttonClassName, buttonClassName,
@ -79,7 +79,7 @@ export const WorkItemStateDropdownBase: React.FC<TWorkItemStateDropdownBaseProps
const { t } = useTranslation(); const { t } = useTranslation();
const statesList = stateIds.map((stateId) => getStateById(stateId)).filter((state) => !!state); const statesList = stateIds.map((stateId) => getStateById(stateId)).filter((state) => !!state);
const defaultState = statesList?.find((state) => state?.default) || statesList[0]; const defaultState = statesList?.find((state) => state?.default) || statesList[0];
const stateValue = !!value ? value : showDefaultState ? defaultState?.id : undefined; const stateValue = value ? value : showDefaultState ? defaultState?.id : undefined;
// popper-js init // popper-js init
const { styles, attributes } = usePopper(referenceElement, popperElement, { const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start", placement: placement ?? "bottom-start",

View file

@ -1,5 +1,3 @@
"use client";
import { useState } from "react"; import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
@ -16,7 +14,7 @@ type TWorkItemStateDropdownProps = Omit<
stateIds?: string[]; stateIds?: string[];
}; };
export const IntakeStateDropdown: React.FC<TWorkItemStateDropdownProps> = observer((props) => { export const IntakeStateDropdown = observer(function IntakeStateDropdown(props: TWorkItemStateDropdownProps) {
const { projectId, stateIds: propsStateIds } = props; const { projectId, stateIds: propsStateIds } = props;
// router params // router params
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();

View file

@ -79,7 +79,7 @@ export const WorkItemStateDropdownBase = observer(function WorkItemStateDropdown
const { t } = useTranslation(); const { t } = useTranslation();
const statesList = stateIds.map((stateId) => getStateById(stateId)).filter((state) => !!state); const statesList = stateIds.map((stateId) => getStateById(stateId)).filter((state) => !!state);
const defaultState = statesList?.find((state) => state?.default); const defaultState = statesList?.find((state) => state?.default);
const stateValue = !!value ? value : showDefaultState ? defaultState?.id : undefined; const stateValue = value ? value : showDefaultState ? defaultState?.id : undefined;
// popper-js init // popper-js init
const { styles, attributes } = usePopper(referenceElement, popperElement, { const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start", placement: placement ?? "bottom-start",

View file

@ -82,7 +82,7 @@ export const EstimatePointCreate = observer(function EstimatePointCreate(props:
const currentEstimatePointValues = estimatePoints const currentEstimatePointValues = estimatePoints
.map((point) => point?.value || undefined) .map((point) => point?.value || undefined)
.filter((value) => value != undefined) as string[]; .filter((value) => value != undefined);
const isRepeated = const isRepeated =
(estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) || (estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) ||
false; false;

View file

@ -87,7 +87,7 @@ export const EstimatePointUpdate = observer(function EstimatePointUpdate(props:
const currentEstimatePointValues = estimatePoints const currentEstimatePointValues = estimatePoints
.map((point) => (point?.key != estimatePoint?.key ? point?.value : undefined)) .map((point) => (point?.key != estimatePoint?.key ? point?.value : undefined))
.filter((value) => value != undefined) as string[]; .filter((value) => value != undefined);
const isRepeated = const isRepeated =
(estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) || (estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) ||
false; false;

View file

@ -104,6 +104,7 @@ export const EstimateRoot = observer(function EstimateRoot(props: TEstimateRoot)
href={"https://docs.plane.so/core-concepts/projects/run-project#estimate"} href={"https://docs.plane.so/core-concepts/projects/run-project#estimate"}
target="_blank" target="_blank"
className="text-custom-primary-100/80 hover:text-custom-primary-100" className="text-custom-primary-100/80 hover:text-custom-primary-100"
rel="noreferrer"
> >
here. here.
</a> </a>

View file

@ -102,7 +102,7 @@ export const ExportForm = observer(function ExportForm(props: Props) {
rich_filters: formData.filters, rich_filters: formData.filters,
}; };
await projectExportService await projectExportService
.csvExport(workspaceSlug as string, payload) .csvExport(workspaceSlug, payload)
.then(() => { .then(() => {
mutateServices(); mutateServices();
setExportLoading(false); setExportLoading(false);

View file

@ -74,7 +74,7 @@ export const Exporter = observer(function Exporter(props: Props) {
multiple: multiple, multiple: multiple,
}; };
await projectExportService await projectExportService
.csvExport(workspaceSlug as string, payload) .csvExport(workspaceSlug, payload)
.then(() => { .then(() => {
mutateServices(); mutateServices();
router.push(`/${workspaceSlug}/settings/exports`); router.push(`/${workspaceSlug}/settings/exports`);

View file

@ -20,16 +20,11 @@ const IntegrationGuide = observer(function IntegrationGuide() {
<div className="h-full w-full"> <div className="h-full w-full">
<> <>
<ExportForm <ExportForm
workspaceSlug={workspaceSlug as string} workspaceSlug={workspaceSlug}
provider={provider} provider={provider}
mutateServices={() => mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`))} mutateServices={() => mutate(EXPORT_SERVICES_LIST(workspaceSlug, `${cursor}`, `${per_page}`))}
/>
<PrevExports
workspaceSlug={workspaceSlug as string}
cursor={cursor}
per_page={per_page}
setCursor={setCursor}
/> />
<PrevExports workspaceSlug={workspaceSlug} cursor={cursor} per_page={per_page} setCursor={setCursor} />
</> </>
</div> </div>
</> </>

View file

@ -35,15 +35,13 @@ export const PrevExports = observer(function PrevExports(props: Props) {
const columns = useExportColumns(); const columns = useExportColumns();
const { data: exporterServices } = useSWR( const { data: exporterServices } = useSWR(
workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null, workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug, cursor, `${per_page}`) : null,
workspaceSlug && cursor workspaceSlug && cursor ? () => integrationService.getExportsServicesList(workspaceSlug, cursor, per_page) : null
? () => integrationService.getExportsServicesList(workspaceSlug as string, cursor, per_page)
: null
); );
const handleRefresh = () => { const handleRefresh = () => {
setRefreshing(true); setRefreshing(true);
mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`)).then(() => setRefreshing(false)); mutate(EXPORT_SERVICES_LIST(workspaceSlug, `${cursor}`, `${per_page}`)).then(() => setRefreshing(false));
}; };
useEffect(() => { useEffect(() => {

View file

@ -14,7 +14,7 @@ type Props = {
export function SingleExport({ service, refreshing }: Props) { export function SingleExport({ service, refreshing }: Props) {
const provider = service.provider; const provider = service.provider;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [isLoading] = useState(false); const [isLoading] = useState(false);
const checkExpiry = (inputDateString: string) => { const checkExpiry = (inputDateString: string) => {

View file

@ -59,7 +59,7 @@ export const timePreview = (date: Date) => {
export const datePreview = (date: Date, includeTime: boolean = false) => { export const datePreview = (date: Date, includeTime: boolean = false) => {
const day = date.getDate(); const day = date.getDate();
let month: number | WeekMonthDataType = date.getMonth(); let month: number | WeekMonthDataType = date.getMonth();
month = months[month as number] as WeekMonthDataType; month = months[month];
const year = date.getFullYear(); const year = date.getFullYear();
return `${charCapitalize(month?.shortTitle)} ${day}, ${year}${includeTime ? `, ${timePreview(date)}` : ``}`; return `${charCapitalize(month?.shortTitle)} ${day}, ${year}${includeTime ? `, ${timePreview(date)}` : ``}`;

View file

@ -5,7 +5,7 @@ export const handleOrderChange = (
droppedBlockId: string | undefined, droppedBlockId: string | undefined,
dropAtEndOfList: boolean, dropAtEndOfList: boolean,
blockIds: string[] | null, blockIds: string[] | null,
getBlockById: (id: string, currentViewData?: ChartDataType | undefined) => IGanttBlock, getBlockById: (id: string, currentViewData?: ChartDataType) => IGanttBlock,
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void
) => { ) => {
if (!blockIds || !draggingBlockId || !droppedBlockId) return; if (!blockIds || !draggingBlockId || !droppedBlockId) return;

View file

@ -15,6 +15,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-docs" href="https://go.plane.so/p-docs"
target="_blank" target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none" className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
> >
{t("docs")} {t("docs")}
</a> </a>
@ -26,6 +27,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-changelog" href="https://go.plane.so/p-changelog"
target="_blank" target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none" className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
> >
{t("full_changelog")} {t("full_changelog")}
</a> </a>
@ -36,6 +38,7 @@ export function ProductUpdatesFooter() {
href="mailto:support@plane.so" href="mailto:support@plane.so"
target="_blank" target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none" className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
> >
{t("support")} {t("support")}
</a> </a>
@ -46,6 +49,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-discord" href="https://go.plane.so/p-discord"
target="_blank" target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none" className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
> >
Discord Discord
</a> </a>
@ -57,6 +61,7 @@ export function ProductUpdatesFooter() {
getButtonStyling("accent-primary", "sm"), getButtonStyling("accent-primary", "sm"),
"flex gap-1.5 items-center text-center font-medium hover:underline underline-offset-2 outline-none" "flex gap-1.5 items-center text-center font-medium hover:underline underline-offset-2 outline-none"
)} )}
rel="noreferrer"
> >
<PlaneLogo className="h-4 w-auto text-custom-text-100" /> <PlaneLogo className="h-4 w-auto text-custom-text-100" />
{t("powered_by_plane_pages")} {t("powered_by_plane_pages")}

View file

@ -46,7 +46,7 @@ export const WidgetItem = observer(function WidgetItem(props: Props) {
const { widgetsMap } = useHome(); const { widgetsMap } = useHome();
const { t } = useTranslation(); const { t } = useTranslation();
// derived values // derived values
const widget = widgetsMap[widgetId] as TWidgetEntityData; const widget = widgetsMap[widgetId];
const widgetTitle = HOME_WIDGETS_LIST[widget.key]?.title; const widgetTitle = HOME_WIDGETS_LIST[widget.key]?.title;
// drag and drop // drag and drop

View file

@ -90,11 +90,10 @@ export const InboxIssueMainContent = observer(function InboxIssueMainContent(pro
const issueOperations: TIssueOperations = useMemo( const issueOperations: TIssueOperations = useMemo(
() => ({ () => ({
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars, arrow-body-style
fetch: async (_workspaceSlug: string, _projectId: string, _issueId: string) => { fetch: async (_workspaceSlug: string, _projectId: string, _issueId: string) => {
return; return;
}, },
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars, arrow-body-style
remove: async (_workspaceSlug: string, _projectId: string, _issueId: string) => { remove: async (_workspaceSlug: string, _projectId: string, _issueId: string) => {
try { try {
await removeIssue(workspaceSlug, projectId, _issueId); await removeIssue(workspaceSlug, projectId, _issueId);

View file

@ -43,8 +43,8 @@ export const DeleteInboxIssueModal = observer(function DeleteInboxIssueModal({
.then(() => { .then(() => {
setToast({ setToast({
type: TOAST_TYPE.SUCCESS, type: TOAST_TYPE.SUCCESS,
title: `${t("success")!}`, title: `${t("success")}`,
message: `${t("inbox_issue.modals.delete.success")!}`, message: `${t("inbox_issue.modals.delete.success")}`,
}); });
}) })
.catch((errors) => { .catch((errors) => {

View file

@ -41,13 +41,13 @@ export function DeleteImportModal({ isOpen, handleClose, data }: Props) {
setDeleteLoading(true); setDeleteLoading(true);
mutate<IImporterService[]>( mutate<IImporterService[]>(
IMPORTER_SERVICES_LIST(workspaceSlug as string), IMPORTER_SERVICES_LIST(workspaceSlug),
(prevData) => (prevData ?? []).filter((i) => i.id !== data.id), (prevData) => (prevData ?? []).filter((i) => i.id !== data.id),
false false
); );
integrationService integrationService
.deleteImporterService(workspaceSlug as string, data.service, data.id) .deleteImporterService(workspaceSlug, data.service, data.id)
.catch(() => .catch(() =>
setToast({ setToast({
type: TOAST_TYPE.ERROR, type: TOAST_TYPE.ERROR,

View file

@ -30,10 +30,10 @@ export function GithubRepoDetails({ selectedRepo, handleStepChange, setUsers, se
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
const { data: repoInfo } = useSWR( const { data: repoInfo } = useSWR(
workspaceSlug && selectedRepo ? GITHUB_REPOSITORY_INFO(workspaceSlug as string, selectedRepo.name) : null, workspaceSlug && selectedRepo ? GITHUB_REPOSITORY_INFO(workspaceSlug, selectedRepo.name) : null,
workspaceSlug && selectedRepo workspaceSlug && selectedRepo
? () => ? () =>
githubIntegrationService.getGithubRepoInfo(workspaceSlug as string, { githubIntegrationService.getGithubRepoInfo(workspaceSlug, {
owner: selectedRepo.owner.login, owner: selectedRepo.owner.login,
repo: selectedRepo.name, repo: selectedRepo.name,
}) })

View file

@ -96,8 +96,8 @@ export function GithubImporterRoot() {
const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () => integrationService.getAppIntegrationsList()); const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () => integrationService.getAppIntegrationsList());
const { data: workspaceIntegrations } = useSWR( const { data: workspaceIntegrations } = useSWR(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null, workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug) : null,
workspaceSlug ? () => integrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null workspaceSlug ? () => integrationService.getWorkspaceIntegrationsList(workspaceSlug) : null
); );
const activeIntegrationState = () => { const activeIntegrationState = () => {
@ -138,10 +138,10 @@ export function GithubImporterRoot() {
}; };
await githubIntegrationService await githubIntegrationService
.createGithubServiceImport(workspaceSlug as string, payload) .createGithubServiceImport(workspaceSlug, payload)
.then(() => { .then(() => {
router.push(`/${workspaceSlug}/settings/imports`); router.push(`/${workspaceSlug}/settings/imports`);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)); mutate(IMPORTER_SERVICES_LIST(workspaceSlug));
}) })
.catch(() => .catch(() =>
setToast({ setToast({

View file

@ -54,8 +54,8 @@ const IntegrationGuide = observer(function IntegrationGuide() {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: importerServices } = useSWR( const { data: importerServices } = useSWR(
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null, workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug) : null,
workspaceSlug ? () => integrationService.getImporterServicesList(workspaceSlug as string) : null workspaceSlug ? () => integrationService.getImporterServicesList(workspaceSlug) : null
); );
const handleDeleteImport = (importService: IImporterService) => { const handleDeleteImport = (importService: IImporterService) => {
@ -129,7 +129,7 @@ const IntegrationGuide = observer(function IntegrationGuide() {
className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 px-1.5 py-1 text-xs outline-none" className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 px-1.5 py-1 text-xs outline-none"
onClick={() => { onClick={() => {
setRefreshing(true); setRefreshing(true);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() => setRefreshing(false)); mutate(IMPORTER_SERVICES_LIST(workspaceSlug)).then(() => setRefreshing(false));
}} }}
> >
<RefreshCw className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`} />{" "} <RefreshCw className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`} />{" "}

View file

@ -94,7 +94,7 @@ export function JiraImportUsers() {
input input
value={value} value={value}
onChange={onChange} onChange={onChange}
label={<span className="capitalize">{Boolean(value) ? value : ("Ignore" as any)}</span>} label={<span className="capitalize">{value ? value : ("Ignore" as any)}</span>}
> >
<CustomSelect.Option value="invite">Invite by email</CustomSelect.Option> <CustomSelect.Option value="invite">Invite by email</CustomSelect.Option>
<CustomSelect.Option value="map">Map to existing</CustomSelect.Option> <CustomSelect.Option value="map">Map to existing</CustomSelect.Option>

View file

@ -60,9 +60,8 @@ export const SingleIntegrationCard = observer(function SingleIntegrationCard({ i
slack_client_id: config?.slack_client_id || "", slack_client_id: config?.slack_client_id || "",
}); });
const { data: workspaceIntegrations } = useSWR( const { data: workspaceIntegrations } = useSWR(workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug) : null, () =>
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null, workspaceSlug ? integrationService.getWorkspaceIntegrationsList(workspaceSlug) : null
() => (workspaceSlug ? integrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null)
); );
const handleRemoveIntegration = async () => { const handleRemoveIntegration = async () => {
@ -73,10 +72,10 @@ export const SingleIntegrationCard = observer(function SingleIntegrationCard({ i
setDeletingIntegration(true); setDeletingIntegration(true);
await integrationService await integrationService
.deleteWorkspaceIntegration(workspaceSlug as string, workspaceIntegrationId ?? "") .deleteWorkspaceIntegration(workspaceSlug, workspaceIntegrationId ?? "")
.then(() => { .then(() => {
mutate<IWorkspaceIntegration[]>( mutate<IWorkspaceIntegration[]>(
WORKSPACE_INTEGRATIONS(workspaceSlug as string), WORKSPACE_INTEGRATIONS(workspaceSlug),
(prevData) => prevData?.filter((i) => i.id !== workspaceIntegrationId), (prevData) => prevData?.filter((i) => i.id !== workspaceIntegrationId),
false false
); );

View file

@ -38,16 +38,10 @@ export const SelectChannel = observer(function SelectChannel({ integration }: Pr
}); });
const { data: projectIntegration } = useSWR( const { data: projectIntegration } = useSWR(
workspaceSlug && projectId && integration.id workspaceSlug && projectId && integration.id ? SLACK_CHANNEL_INFO(workspaceSlug, projectId) : null,
? SLACK_CHANNEL_INFO(workspaceSlug as string, projectId as string)
: null,
() => () =>
workspaceSlug && projectId && integration.id workspaceSlug && projectId && integration.id
? appInstallationService.getSlackChannelDetail( ? appInstallationService.getSlackChannelDetail(workspaceSlug, projectId, integration.id)
workspaceSlug as string,
projectId as string,
integration.id as string
)
: null : null
); );
@ -74,7 +68,7 @@ export const SelectChannel = observer(function SelectChannel({ integration }: Pr
setSlackChannel(null); setSlackChannel(null);
}); });
appInstallationService appInstallationService
.removeSlackChannel(workspaceSlug as string, projectId as string, integration.id as string, slackChannel?.id) .removeSlackChannel(workspaceSlug, projectId, integration.id, slackChannel?.id)
.catch((err) => console.error(err)); .catch((err) => console.error(err));
}; };

View file

@ -186,7 +186,7 @@ export const RelationsCollapsibleContent = observer(function RelationsCollapsibl
issueCrudState.delete.issue.id && issueCrudState.delete.issue.id &&
issueCrudState.delete.issue.project_id issueCrudState.delete.issue.project_id
) { ) {
const deleteOperation = !!issueCrudState.delete.issue?.is_epic const deleteOperation = issueCrudState.delete.issue?.is_epic
? epicOperations.remove ? epicOperations.remove
: issueOperations.remove; : issueOperations.remove;
await deleteOperation( await deleteOperation(
@ -202,7 +202,7 @@ export const RelationsCollapsibleContent = observer(function RelationsCollapsibl
{shouldRenderIssueUpdateModal && ( {shouldRenderIssueUpdateModal && (
<> <>
{!!issueCrudState?.update?.issue?.is_epic ? ( {issueCrudState?.update?.issue?.is_epic ? (
<CreateUpdateEpicModal <CreateUpdateEpicModal
isOpen={issueCrudState?.update?.toggle} isOpen={issueCrudState?.update?.toggle}
onClose={() => { onClose={() => {

View file

@ -51,7 +51,7 @@ export const RelationActionButton = observer(function RelationActionButton(props
<CustomMenu.MenuItem <CustomMenu.MenuItem
key={index} key={index}
onClick={() => { onClick={() => {
handleOnClick(item.key as TIssueRelationTypes); handleOnClick(item.key);
}} }}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">

View file

@ -13,7 +13,6 @@ import { useProjectInbox } from "@/hooks/store/use-project-inbox";
// types // types
import { LabelList, IssueLabelSelectRoot } from "./"; import { LabelList, IssueLabelSelectRoot } from "./";
// TODO: Fix this import statement, as core should not import from ee // TODO: Fix this import statement, as core should not import from ee
// eslint-disable-next-line import/order
export type TIssueLabel = { export type TIssueLabel = {
workspaceSlug: string; workspaceSlug: string;

View file

@ -39,12 +39,7 @@ import { CalendarWeekDays } from "./week-days";
import { CalendarWeekHeader } from "./week-header"; import { CalendarWeekHeader } from "./week-header";
type Props = { type Props = {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
issues: TIssueMap | undefined; issues: TIssueMap | undefined;
groupedIssueIds: TGroupedIssues; groupedIssueIds: TGroupedIssues;
layout: "month" | "week" | undefined; layout: "month" | "week" | undefined;

View file

@ -23,12 +23,7 @@ import type { TRenderQuickActions } from "../list/list-view-types";
import { CalendarIssueBlocks } from "./issue-blocks"; import { CalendarIssueBlocks } from "./issue-blocks";
type Props = { type Props = {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
date: ICalendarDate; date: ICalendarDate;
issues: TIssueMap | undefined; issues: TIssueMap | undefined;
groupedIssueIds: TGroupedIssues; groupedIssueIds: TGroupedIssues;

View file

@ -17,12 +17,7 @@ import type { IProjectViewIssuesFilter } from "@/store/issue/project-views";
// helpers // helpers
interface Props { interface Props {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
} }
export const CalendarMonthsDropdown = observer(function CalendarMonthsDropdown(props: Props) { export const CalendarMonthsDropdown = observer(function CalendarMonthsDropdown(props: Props) {
const { issuesFilterStore } = props; const { issuesFilterStore } = props;

View file

@ -25,12 +25,7 @@ import type { IProjectIssuesFilter } from "@/store/issue/project";
import type { IProjectViewIssuesFilter } from "@/store/issue/project-views"; import type { IProjectViewIssuesFilter } from "@/store/issue/project-views";
interface ICalendarHeader { interface ICalendarHeader {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
updateFilters?: ( updateFilters?: (
projectId: string, projectId: string,
filterType: TSupportedFilterTypeForUpdate, filterType: TSupportedFilterTypeForUpdate,

View file

@ -16,12 +16,7 @@ import type { IProjectViewIssuesFilter } from "@/store/issue/project-views";
import { CalendarMonthsDropdown, CalendarOptionsDropdown } from "./dropdowns"; import { CalendarMonthsDropdown, CalendarOptionsDropdown } from "./dropdowns";
interface ICalendarHeader { interface ICalendarHeader {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
updateFilters?: ( updateFilters?: (
projectId: string, projectId: string,
filterType: TSupportedFilterTypeForUpdate, filterType: TSupportedFilterTypeForUpdate,

View file

@ -1,4 +1,3 @@
/* eslint-disable react/display-name */
import { useState, useRef, forwardRef } from "react"; import { useState, useRef, forwardRef } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";

View file

@ -14,12 +14,7 @@ import type { TRenderQuickActions } from "../list/list-view-types";
import { CalendarDayTile } from "./day-tile"; import { CalendarDayTile } from "./day-tile";
type Props = { type Props = {
issuesFilterStore: issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
issues: TIssueMap | undefined; issues: TIssueMap | undefined;
groupedIssueIds: TGroupedIssues; groupedIssueIds: TGroupedIssues;
week: ICalendarWeek | undefined; week: ICalendarWeek | undefined;

View file

@ -37,7 +37,7 @@ export const FilterDisplayProperties = observer(function FilterDisplayProperties
// states // states
const [previewEnabled, setPreviewEnabled] = React.useState(true); const [previewEnabled, setPreviewEnabled] = React.useState(true);
// derived values // derived values
const projectId = !!routerProjectId ? routerProjectId?.toString() : undefined; const projectId = routerProjectId ? routerProjectId?.toString() : undefined;
// Filter out "cycle" and "module" keys if cycleViewDisabled or moduleViewDisabled is true // Filter out "cycle" and "module" keys if cycleViewDisabled or moduleViewDisabled is true
// Also filter out display properties that should not be rendered // Also filter out display properties that should not be rendered

View file

@ -152,7 +152,7 @@ export const KanBan = observer(function KanBan(props: IKanBan) {
const issueIds = isSubGroup const issueIds = isSubGroup
? ((groupedIssueIds as TSubGroupedIssues)?.[subList.id]?.[sub_group_id] ?? []) ? ((groupedIssueIds as TSubGroupedIssues)?.[subList.id]?.[sub_group_id] ?? [])
: ((groupedIssueIds as TGroupedIssues)?.[subList.id] ?? []); : ((groupedIssueIds as TGroupedIssues)?.[subList.id] ?? []);
const issueLength = issueIds?.length as number; const issueLength = issueIds?.length;
const groupHeight = issueLength * approximateCardHeight; const groupHeight = issueLength * approximateCardHeight;
return ( return (

View file

@ -268,7 +268,7 @@ export const KanbanGroup = observer(function KanbanGroup(props: IKanbanGroup) {
const canDragIssuesInCurrentGrouping = const canDragIssuesInCurrentGrouping =
!!group_by && !!group_by &&
DRAG_ALLOWED_GROUPS.includes(group_by) && DRAG_ALLOWED_GROUPS.includes(group_by) &&
(!!sub_group_by ? DRAG_ALLOWED_GROUPS.includes(sub_group_by) : true); (sub_group_by ? DRAG_ALLOWED_GROUPS.includes(sub_group_by) : true);
return ( return (
<div <div

View file

@ -160,7 +160,7 @@ const getCycleColumns = (): IGroupByColumn[] | undefined => {
cycles.push({ cycles.push({
id: cycle.id, id: cycle.id,
name: cycle.name, name: cycle.name,
icon: <CycleGroupIcon cycleGroup={cycleStatus as TCycleGroups} className="h-3.5 w-3.5" />, icon: <CycleGroupIcon cycleGroup={cycleStatus} className="h-3.5 w-3.5" />,
payload: { cycle_id: cycle.id }, payload: { cycle_id: cycle.id },
isDropDisabled, isDropDisabled,
dropErrorMessage: isDropDisabled ? "Work item cannot be moved to completed cycles" : undefined, dropErrorMessage: isDropDisabled ? "Work item cannot be moved to completed cycles" : undefined,
@ -486,11 +486,8 @@ const handleSortOrder = (
return currentIssueState; return currentIssueState;
}; };
export const getIssueBlockId = ( export const getIssueBlockId = (issueId: string | undefined, groupId: string | undefined, subGroupId?: string) =>
issueId: string | undefined, `issue_${issueId}_${groupId}_${subGroupId}`;
groupId: string | undefined,
subGroupId?: string | undefined
) => `issue_${issueId}_${groupId}_${subGroupId}`;
/** /**
* returns empty Array if groupId is None * returns empty Array if groupId is None

View file

@ -180,7 +180,7 @@ export const IssueDescriptionEditor = observer(function IssueDescriptionEditor(p
id="issue-modal-editor" id="issue-modal-editor"
initialValue={value ?? ""} initialValue={value ?? ""}
value={descriptionHtmlData} value={descriptionHtmlData}
workspaceSlug={workspaceSlug?.toString() as string} workspaceSlug={workspaceSlug?.toString()}
workspaceId={workspaceId} workspaceId={workspaceId}
projectId={projectId} projectId={projectId}
onChange={(_description: object, description_html: string) => { onChange={(_description: object, description_html: string) => {

View file

@ -70,7 +70,7 @@ export function ParentIssuesListModal({
setIsLoading(true); setIsLoading(true);
projectService projectService
.projectIssuesSearch(workspaceSlug as string, projectId as string, { .projectIssuesSearch(workspaceSlug, projectId, {
search: debouncedSearchTerm, search: debouncedSearchTerm,
parent: searchEpic ? undefined : true, parent: searchEpic ? undefined : true,
issue_id: issueId, issue_id: issueId,

View file

@ -63,7 +63,7 @@ export const RelationIssueListItem = observer(function RelationIssueListItem(pro
// derived values // derived values
const issue = getIssueById(relationIssueId); const issue = getIssueById(relationIssueId);
const { handleRedirection } = useIssuePeekOverviewRedirection(!!issue?.is_epic); const { handleRedirection } = useIssuePeekOverviewRedirection(!!issue?.is_epic);
const issueOperations = useRelationOperations(!!issue?.is_epic ? EIssueServiceType.EPICS : EIssueServiceType.ISSUES); const issueOperations = useRelationOperations(issue?.is_epic ? EIssueServiceType.EPICS : EIssueServiceType.ISSUES);
const projectDetail = (issue && issue.project_id && project.getProjectById(issue.project_id)) || undefined; const projectDetail = (issue && issue.project_id && project.getProjectById(issue.project_id)) || undefined;
const projectId = issue?.project_id; const projectId = issue?.project_id;

View file

@ -150,7 +150,7 @@ export const LabelDndHOC = observer(function LabelDndHOC(props: Props) {
if (instruction === "reorder-below") dropAtEndOfList = true; if (instruction === "reorder-below") dropAtEndOfList = true;
const sourceData = source.data as TargetData; const sourceData = source.data as TargetData;
if (sourceData.id) onDrop(sourceData.id as string, parentId, droppedLabelId, dropAtEndOfList); if (sourceData.id) onDrop(sourceData.id, parentId, droppedLabelId, dropAtEndOfList);
}, },
}) })
); );

View file

@ -78,6 +78,7 @@ export const TalkToSalesCard = observer(function TalkToSalesCard(props: TalkToSa
upgradeButtonStyle, upgradeButtonStyle,
"relative inline-flex items-center justify-center w-56 px-4 py-2 text-sm font-medium rounded-lg focus:outline-none" "relative inline-flex items-center justify-center w-56 px-4 py-2 text-sm font-medium rounded-lg focus:outline-none"
)} )}
rel="noreferrer"
> >
Talk to Sales Talk to Sales
</a> </a>

View file

@ -1,4 +1,3 @@
"use client";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams, usePathname } from "next/navigation"; import { useParams, usePathname } from "next/navigation";
import { Check, SettingsIcon } from "lucide-react"; import { Check, SettingsIcon } from "lucide-react";
@ -14,7 +13,7 @@ import { DesktopSidebarWorkspaceMenu } from "@/plane-web/components/desktop";
// local imports // local imports
import { AppSidebarItemsRoot } from "./items-root"; import { AppSidebarItemsRoot } from "./items-root";
export const AppRailRoot = observer(() => { export const AppRailRoot = observer(function AppRailRoot() {
// router // router
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
const pathname = usePathname(); const pathname = usePathname();

View file

@ -38,7 +38,9 @@ const PERSONAL_ITEMS: Array<{ key: TPersonalNavigationItemKey; labelTranslationK
{ key: "drafts", labelTranslationKey: "drafts" }, { key: "drafts", labelTranslationKey: "drafts" },
]; ];
export const CustomizeNavigationDialog: FC<TCustomizeNavigationDialogProps> = observer((props) => { export const CustomizeNavigationDialog = observer(function CustomizeNavigationDialog(
props: TCustomizeNavigationDialogProps
) {
const { isOpen, onClose } = props; const { isOpen, onClose } = props;
const { t } = useTranslation(); const { t } = useTranslation();

View file

@ -1,5 +1,4 @@
// components/AppSidebarItemsRoot.tsx // components/AppSidebarItemsRoot.tsx
"use client";
import React from "react"; import React from "react";
import type { AppSidebarItemData } from "@/components/sidebar/sidebar-item"; import type { AppSidebarItemData } from "@/components/sidebar/sidebar-item";
@ -11,7 +10,8 @@ type Props = {
showLabel?: boolean; showLabel?: boolean;
}; };
const Component = ({ dockItems, showLabel = true }: Props) => ( function Component({ dockItems, showLabel = true }: Props) {
return (
<> <>
{dockItems {dockItems
.filter((item) => item.shouldRender) .filter((item) => item.shouldRender)
@ -19,6 +19,7 @@ const Component = ({ dockItems, showLabel = true }: Props) => (
<AppSidebarItem key={item.label} item={{ ...item, showLabel }} variant="link" /> <AppSidebarItem key={item.label} item={{ ...item, showLabel }} variant="link" />
))} ))}
</> </>
); );
}
export const AppSidebarItemsRoot = withDockItems(Component); export const AppSidebarItemsRoot = withDockItems(Component);

View file

@ -1,5 +1,3 @@
"use client";
import type { FC } from "react"; import type { FC } from "react";
import { useState, useRef } from "react"; import { useState, useRef } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
@ -21,7 +19,7 @@ type Props = {
onPublishModal: () => void; onPublishModal: () => void;
}; };
export const ProjectActionsMenu: FC<Props> = ({ export function ProjectActionsMenu({
workspaceSlug, workspaceSlug,
project, project,
isAdmin, isAdmin,
@ -29,7 +27,7 @@ export const ProjectActionsMenu: FC<Props> = ({
onCopyText, onCopyText,
onLeaveProject, onLeaveProject,
onPublishModal, onPublishModal,
}) => { }: Props) {
// states // states
const [isMenuActive, setIsMenuActive] = useState(false); const [isMenuActive, setIsMenuActive] = useState(false);
// translation // translation
@ -111,4 +109,4 @@ export const ProjectActionsMenu: FC<Props> = ({
)} )}
</CustomMenu> </CustomMenu>
); );
}; }

View file

@ -22,7 +22,7 @@ type TProjectHeaderProps = {
projectId: string; projectId: string;
}; };
export const ProjectHeader = observer((props: TProjectHeaderProps) => { export const ProjectHeader = observer(function ProjectHeader(props: TProjectHeaderProps) {
const { workspaceSlug, projectId } = props; const { workspaceSlug, projectId } = props;
// router // router
const router = useAppRouter(); const router = useAppRouter();

View file

@ -24,13 +24,7 @@ type Props = {
* Displays items that don't fit in the visible area, with action icons * Displays items that don't fit in the visible area, with action icons
* Shows "Eye" icon for user-hidden items, "Set as default" icon for all items * Shows "Eye" icon for user-hidden items, "Set as default" icon for all items
*/ */
export const TabNavigationOverflowMenu: React.FC<Props> = ({ export function TabNavigationOverflowMenu({ overflowItems, isActive, tabPreferences, onToggleDefault, onShow }: Props) {
overflowItems,
isActive,
tabPreferences,
onToggleDefault,
onShow,
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@ -97,4 +91,4 @@ export const TabNavigationOverflowMenu: React.FC<Props> = ({
})} })}
</Menu> </Menu>
); );
}; }

View file

@ -1,5 +1,3 @@
"use client";
import type { FC } from "react"; import type { FC } from "react";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
@ -44,7 +42,7 @@ type TTabNavigationRootProps = {
projectId: string; projectId: string;
}; };
export const TabNavigationRoot: FC<TTabNavigationRootProps> = observer((props) => { export const TabNavigationRoot = observer(function TabNavigationRoot(props: TTabNavigationRootProps) {
const { workspaceSlug, projectId } = props; const { workspaceSlug, projectId } = props;
const { workItem: workItemIdentifierFromRoute } = useParams(); const { workItem: workItemIdentifierFromRoute } = useParams();
const location = useLocation(); const location = useLocation();

View file

@ -23,14 +23,14 @@ export type TTabNavigationVisibleItemProps = {
* Individual visible tab navigation item with context menu * Individual visible tab navigation item with context menu
* Handles right-click actions for setting default and hiding tabs * Handles right-click actions for setting default and hiding tabs
*/ */
export const TabNavigationVisibleItem: React.FC<TTabNavigationVisibleItemProps> = ({ export function TabNavigationVisibleItem({
item, item,
isActive, isActive,
tabPreferences, tabPreferences,
onToggleDefault, onToggleDefault,
onHide, onHide,
itemRef, itemRef,
}) => { }: TTabNavigationVisibleItemProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const isDefault = item.key === tabPreferences.defaultTab; const isDefault = item.key === tabPreferences.defaultTab;
@ -76,4 +76,4 @@ export const TabNavigationVisibleItem: React.FC<TTabNavigationVisibleItemProps>
</div> </div>
</div> </div>
); );
}; }

View file

@ -15,7 +15,7 @@ import { useUser } from "@/hooks/store/user";
import { useAppRouter } from "@/hooks/use-app-router"; import { useAppRouter } from "@/hooks/use-app-router";
import { useExpandableSearch } from "@/hooks/use-expandable-search"; import { useExpandableSearch } from "@/hooks/use-expandable-search";
export const TopNavPowerK = observer(() => { export const TopNavPowerK = observer(function TopNavPowerK() {
// router // router
const router = useAppRouter(); const router = useAppRouter();
const params = useParams(); const params = useParams();

View file

@ -87,7 +87,8 @@ export const PageActions = observer(function PageActions(props: Props) {
canCurrentUserMovePage, canCurrentUserMovePage,
} = page; } = page;
// menu items // menu items
const MENU_ITEMS = useMemo(() => { const MENU_ITEMS = useMemo(
function MENU_ITEMS() {
const menuItems: (TContextMenuItem & { key: TPageActions })[] = [ const menuItems: (TContextMenuItem & { key: TPageActions })[] = [
{ {
key: "toggle-lock", key: "toggle-lock",
@ -175,7 +176,8 @@ export const PageActions = observer(function PageActions(props: Props) {
menuItems.push(...extraOptions); menuItems.push(...extraOptions);
} }
return menuItems; return menuItems;
}, [ },
[
extraOptions, extraOptions,
is_locked, is_locked,
canCurrentUserLockPage, canCurrentUserLockPage,
@ -188,7 +190,8 @@ export const PageActions = observer(function PageActions(props: Props) {
canCurrentUserMovePage, canCurrentUserMovePage,
isMovePageEnabled, isMovePageEnabled,
pageOperations, pageOperations,
]); ]
);
// arrange options // arrange options
const arrangedOptions = useMemo<(TContextMenuItem & { key: TPageActions })[]>( const arrangedOptions = useMemo<(TContextMenuItem & { key: TPageActions })[]>(
() => () =>

Some files were not shown because too many files have changed in this diff Show more